Search in sources :

Example 1 with ValidationResult

use of org.xipki.qa.ValidationResult in project xipki by xipki.

the class OcspQa method checkOcsp.

// method checkOcsp
public ValidationResult checkOcsp(OCSPResp response, IssuerHash issuerHash, List<BigInteger> serialNumbers, Map<BigInteger, byte[]> encodedCerts, Map<BigInteger, OcspCertStatus> expectedOcspStatuses, Map<BigInteger, Date> expectedRevTimes, OcspResponseOption responseOption, boolean noSigVerify) {
    notNull(response, "response");
    notEmpty(serialNumbers, "serialNumbers");
    notEmpty(expectedOcspStatuses, "expectedOcspStatuses");
    notNull(responseOption, "responseOption");
    List<ValidationIssue> resultIssues = new LinkedList<>();
    int status = response.getStatus();
    // Response status
    ValidationIssue issue = new ValidationIssue("OCSP.STATUS", "response.status");
    resultIssues.add(issue);
    if (status != 0) {
        issue.setFailureMessage("is '" + Unsuccessful.getStatusText(status) + "', but expected 'successful'");
        return new ValidationResult(resultIssues);
    }
    ValidationIssue encodingIssue = new ValidationIssue("OCSP.ENCODING", "response encoding");
    resultIssues.add(encodingIssue);
    BasicOCSPResp basicResp;
    try {
        basicResp = (BasicOCSPResp) response.getResponseObject();
    } catch (OCSPException ex) {
        encodingIssue.setFailureMessage(ex.getMessage());
        return new ValidationResult(resultIssues);
    }
    SingleResp[] singleResponses = basicResp.getResponses();
    issue = new ValidationIssue("OCSP.RESPONSES.NUM", "number of single responses");
    resultIssues.add(issue);
    if (singleResponses == null || singleResponses.length == 0) {
        issue.setFailureMessage("received no status from server");
        return new ValidationResult(resultIssues);
    }
    final int n = singleResponses.length;
    if (n != serialNumbers.size()) {
        issue.setFailureMessage("is '" + n + "', but expected '" + serialNumbers.size() + "'");
        return new ValidationResult(resultIssues);
    }
    boolean hasSignature = basicResp.getSignature() != null;
    // check the signature if available
    if (noSigVerify) {
        issue = new ValidationIssue("OCSP.SIG", (hasSignature ? "signature presence (Ignore)" : "signature presence"));
    } else {
        issue = new ValidationIssue("OCSP.SIG", "signature presence");
    }
    resultIssues.add(issue);
    if (!hasSignature) {
        issue.setFailureMessage("response is not signed");
    }
    if (hasSignature && !noSigVerify) {
        // signature algorithm
        issue = new ValidationIssue("OCSP.SIG.ALG", "signature algorithm");
        resultIssues.add(issue);
        SignAlgo expectedSigalgo = responseOption.getSignatureAlg();
        if (expectedSigalgo != null) {
            try {
                SignAlgo signAlgo = SignAlgo.getInstance(basicResp.getSignatureAlgorithmID());
                if (signAlgo != expectedSigalgo) {
                    issue.setFailureMessage("is '" + signAlgo.getJceName() + "', but expected '" + expectedSigalgo.getJceName() + "'");
                }
            } catch (NoSuchAlgorithmException ex) {
                issue.setFailureMessage("could not extract the signature algorithm");
            }
        }
        // end if (expectedSigalgo != null)
        // signer certificate
        ValidationIssue sigSignerCertIssue = new ValidationIssue("OCSP.SIGNERCERT", "signer certificate");
        resultIssues.add(sigSignerCertIssue);
        // signature validation
        ValidationIssue sigValIssue = new ValidationIssue("OCSP.SIG.VALIDATION", "signature validation");
        resultIssues.add(sigValIssue);
        X509CertificateHolder respSigner = null;
        X509CertificateHolder[] responderCerts = basicResp.getCerts();
        if (responderCerts == null || responderCerts.length < 1) {
            sigSignerCertIssue.setFailureMessage("no responder certificate is contained in the response");
            sigValIssue.setFailureMessage("could not find certificate to validate signature");
        } else {
            ResponderID respId = basicResp.getResponderId().toASN1Primitive();
            X500Name respIdByName = respId.getName();
            byte[] respIdByKey = respId.getKeyHash();
            for (X509CertificateHolder cert : responderCerts) {
                if (respIdByName != null) {
                    if (cert.getSubject().equals(respIdByName)) {
                        respSigner = cert;
                    }
                } else {
                    byte[] spkiSha1 = HashAlgo.SHA1.hash(cert.getSubjectPublicKeyInfo().getPublicKeyData().getBytes());
                    if (Arrays.equals(respIdByKey, spkiSha1)) {
                        respSigner = cert;
                    }
                }
                if (respSigner != null) {
                    break;
                }
            }
            if (respSigner == null) {
                sigSignerCertIssue.setFailureMessage("no responder certificate match the ResponderId");
                sigValIssue.setFailureMessage("could not find certificate matching the" + " ResponderId to validate signature");
            }
        }
        if (respSigner != null) {
            issue = new ValidationIssue("OCSP.SIGNERCERT.TRUST", "signer certificate validation");
            resultIssues.add(issue);
            for (int i = 0; i < singleResponses.length; i++) {
                SingleResp singleResp = singleResponses[i];
                if (!respSigner.isValidOn(singleResp.getThisUpdate())) {
                    issue.setFailureMessage(String.format("responder certificate is not valid on the thisUpdate[%d]: %s", i, singleResp.getThisUpdate()));
                }
            }
            // end for
            X509Cert respIssuer = responseOption.getRespIssuer();
            if (!issue.isFailed() && respIssuer != null) {
                X509Cert jceRespSigner;
                try {
                    jceRespSigner = new X509Cert(respSigner);
                    if (X509Util.issues(respIssuer, jceRespSigner)) {
                        jceRespSigner.verify(respIssuer.getPublicKey());
                    } else {
                        issue.setFailureMessage("responder signer is not trusted");
                    }
                } catch (Exception ex) {
                    issue.setFailureMessage("responder signer is not trusted");
                }
            }
            try {
                PublicKey responderPubKey = KeyUtil.generatePublicKey(respSigner.getSubjectPublicKeyInfo());
                ContentVerifierProvider cvp = securityFactory.getContentVerifierProvider(responderPubKey);
                boolean sigValid = basicResp.isSignatureValid(cvp);
                if (!sigValid) {
                    sigValIssue.setFailureMessage("signature is invalid");
                }
            } catch (Exception ex) {
                sigValIssue.setFailureMessage("could not validate signature");
            }
        }
    // end if
    }
    // end if (hasSignature)
    // nonce
    Extension nonceExtn = basicResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
    resultIssues.add(checkOccurrence("OCSP.NONCE", nonceExtn, responseOption.getNonceOccurrence()));
    boolean extendedRevoke = basicResp.getExtension(ObjectIdentifiers.Extn.id_pkix_ocsp_extendedRevoke) != null;
    for (int i = 0; i < singleResponses.length; i++) {
        SingleResp singleResp = singleResponses[i];
        BigInteger serialNumber = singleResp.getCertID().getSerialNumber();
        OcspCertStatus expectedStatus = expectedOcspStatuses.get(serialNumber);
        Date expectedRevTime = null;
        if (expectedRevTimes != null) {
            expectedRevTime = expectedRevTimes.get(serialNumber);
        }
        byte[] encodedCert = null;
        if (encodedCerts != null) {
            encodedCert = encodedCerts.get(serialNumber);
        }
        List<ValidationIssue> issues = checkSingleCert(i, singleResp, issuerHash, expectedStatus, encodedCert, expectedRevTime, extendedRevoke, responseOption.getNextUpdateOccurrence(), responseOption.getCerthashOccurrence(), responseOption.getCerthashAlg());
        resultIssues.addAll(issues);
    }
    return new ValidationResult(resultIssues);
}
Also used : ResponderID(org.bouncycastle.asn1.ocsp.ResponderID) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) X500Name(org.bouncycastle.asn1.x500.X500Name) ValidationResult(org.xipki.qa.ValidationResult) ContentVerifierProvider(org.bouncycastle.operator.ContentVerifierProvider) PublicKey(java.security.PublicKey) ValidationIssue(org.xipki.qa.ValidationIssue) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) Extension(org.bouncycastle.asn1.x509.Extension) X509CertificateHolder(org.bouncycastle.cert.X509CertificateHolder) BigInteger(java.math.BigInteger)

Example 2 with ValidationResult

use of org.xipki.qa.ValidationResult in project xipki by xipki.

the class CertprofileQa method checkCert.

// constructor
public ValidationResult checkCert(byte[] certBytes, IssuerInfo issuerInfo, X500Name requestedSubject, SubjectPublicKeyInfo requestedPublicKey, Extensions requestedExtensions) {
    notNull(certBytes, "certBytes");
    notNull(issuerInfo, "issuerInfo");
    notNull(requestedSubject, "requestedSubject");
    notNull(requestedPublicKey, "requestedPublicKey");
    List<ValidationIssue> resultIssues = new LinkedList<>();
    // certificate size
    ValidationIssue issue = new ValidationIssue("X509.SIZE", "certificate size");
    resultIssues.add(issue);
    certBytes = X509Util.toDerEncoded(certBytes);
    Integer maxSize = certprofile.getMaxSize();
    if (maxSize != 0) {
        int size = certBytes.length;
        if (size > maxSize) {
            issue.setFailureMessage(String.format("certificate exceeds the maximal allowed size: %d > %d", size, maxSize));
        }
    }
    // certificate encoding
    issue = new ValidationIssue("X509.ENCODING", "certificate encoding");
    resultIssues.add(issue);
    Certificate bcCert = Certificate.getInstance(certBytes);
    TBSCertificate tbsCert = bcCert.getTBSCertificate();
    X509Cert cert = new X509Cert(bcCert, certBytes);
    // syntax version
    issue = new ValidationIssue("X509.VERSION", "certificate version");
    resultIssues.add(issue);
    int versionNumber = tbsCert.getVersion().intPositiveValueExact();
    X509CertVersion expVersion = certprofile.getVersion();
    if (versionNumber != expVersion.getVersionNumber()) {
        issue.setFailureMessage("is '" + versionNumber + "' but expected '" + expVersion.getVersionNumber() + "'");
    }
    // serialNumber
    issue = new ValidationIssue("X509.serialNumber", "certificate serial number");
    resultIssues.add(issue);
    BigInteger serialNumber = tbsCert.getSerialNumber().getValue();
    if (serialNumber.signum() != 1) {
        issue.setFailureMessage("not positive");
    } else {
        if (serialNumber.bitLength() >= 160) {
            issue.setFailureMessage("serial number has more than 20 octets");
        }
    }
    // signatureAlgorithm
    List<SignAlgo> signatureAlgorithms = certprofile.getSignatureAlgorithms();
    if (CollectionUtil.isNotEmpty(signatureAlgorithms)) {
        issue = new ValidationIssue("X509.SIGALG", "signature algorithm");
        resultIssues.add(issue);
        AlgorithmIdentifier sigAlgId = bcCert.getSignatureAlgorithm();
        AlgorithmIdentifier tbsSigAlgId = tbsCert.getSignature();
        if (!tbsSigAlgId.equals(sigAlgId)) {
            issue.setFailureMessage("Certificate.tbsCertificate.signature != Certificate.signatureAlgorithm");
        }
        try {
            if (!issue.isFailed()) {
                SignAlgo signAlgo = SignAlgo.getInstance(sigAlgId);
                if (!signatureAlgorithms.contains(signAlgo)) {
                    issue.setFailureMessage("signatureAlgorithm '" + signAlgo + "' is not allowed");
                }
                if (!issue.isFailed()) {
                    if (!sigAlgId.equals(signAlgo.getAlgorithmIdentifier())) {
                        issue.setFailureMessage("signatureAlgorithm has invalid content");
                    }
                }
            }
        } catch (NoSuchAlgorithmException ex) {
            issue.setFailureMessage("unsupported signature algorithm " + sigAlgId.getAlgorithm().getId());
        }
    }
    // notBefore encoding
    issue = new ValidationIssue("X509.NOTBEFORE.ENCODING", "notBefore encoding");
    checkTime(tbsCert.getStartDate(), issue);
    // notAfter encoding
    issue = new ValidationIssue("X509.NOTAFTER.ENCODING", "notAfter encoding");
    checkTime(tbsCert.getStartDate(), issue);
    if (certprofile.getNotBeforeOption().getMidNightTimeZone() != null) {
        issue = new ValidationIssue("X509.NOTBEFORE", "notBefore midnight");
        resultIssues.add(issue);
        Calendar cal = Calendar.getInstance(UTC);
        cal.setTime(cert.getNotBefore());
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        if (minute != 0 || second != 0) {
            issue.setFailureMessage(" '" + cert.getNotBefore() + "' is not midnight time");
        }
    }
    // validity
    issue = new ValidationIssue("X509.VALIDITY", "cert validity");
    resultIssues.add(issue);
    if (cert.getNotAfter().before(cert.getNotBefore())) {
        issue.setFailureMessage("notAfter may not be before notBefore");
    } else if (cert.getNotBefore().before(issuerInfo.getCaNotBefore())) {
        issue.setFailureMessage("notBefore may not be before CA's notBefore");
    } else {
        Validity validity = certprofile.getValidity();
        Date expectedNotAfter = validity.add(cert.getNotBefore());
        if (expectedNotAfter.getTime() > MAX_CERT_TIME_MS) {
            expectedNotAfter = new Date(MAX_CERT_TIME_MS);
        }
        if (issuerInfo.isCutoffNotAfter() && expectedNotAfter.after(issuerInfo.getCaNotAfter())) {
            expectedNotAfter = issuerInfo.getCaNotAfter();
        }
        if (Math.abs(expectedNotAfter.getTime() - cert.getNotAfter().getTime()) > 60 * SECOND) {
            issue.setFailureMessage("cert validity is not within " + validity.toString());
        }
    }
    // subjectPublicKeyInfo
    resultIssues.addAll(publicKeyChecker.checkPublicKey(bcCert.getSubjectPublicKeyInfo(), requestedPublicKey));
    // Signature
    issue = new ValidationIssue("X509.SIG", "whether certificate is signed by CA");
    resultIssues.add(issue);
    try {
        cert.verify(issuerInfo.getCert().getPublicKey(), "BC");
    } catch (NoSuchAlgorithmException ex) {
        try {
            cert.verify(issuerInfo.getCert().getPublicKey());
        } catch (Exception ex1) {
            issue.setFailureMessage("invalid signature");
        }
    } catch (Exception ex) {
        issue.setFailureMessage("invalid signature");
    }
    // issuer
    issue = new ValidationIssue("X509.ISSUER", "certificate issuer");
    resultIssues.add(issue);
    if (!cert.getIssuer().equals(issuerInfo.getCert().getSubject())) {
        issue.setFailureMessage("issue in certificate does not equal the subject of CA certificate");
    }
    // subject
    resultIssues.addAll(subjectChecker.checkSubject(bcCert.getSubject(), requestedSubject));
    // issuerUniqueID
    issue = new ValidationIssue("X509.IssuerUniqueID", "issuerUniqueID");
    resultIssues.add(issue);
    if (tbsCert.getIssuerUniqueId() != null) {
        issue.setFailureMessage("is present but not permitted");
    }
    // subjectUniqueID
    issue = new ValidationIssue("X509.SubjectUniqueID", "subjectUniqueID");
    resultIssues.add(issue);
    if (tbsCert.getSubjectUniqueId() != null) {
        issue.setFailureMessage("is present but not permitted");
    }
    // extensions
    issue = new ValidationIssue("X509.GrantedSubject", "grantedSubject");
    resultIssues.add(issue);
    resultIssues.addAll(extensionsChecker.checkExtensions(bcCert, issuerInfo, requestedExtensions, requestedSubject));
    return new ValidationResult(resultIssues);
}
Also used : NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ValidationResult(org.xipki.qa.ValidationResult) ValidationIssue(org.xipki.qa.ValidationIssue) CertprofileException(org.xipki.ca.api.profile.CertprofileException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) BigInteger(java.math.BigInteger) SignAlgo(org.xipki.security.SignAlgo) X509CertVersion(org.xipki.ca.api.profile.Certprofile.X509CertVersion) X509Cert(org.xipki.security.X509Cert) BigInteger(java.math.BigInteger)

Example 3 with ValidationResult

use of org.xipki.qa.ValidationResult in project xipki by xipki.

the class OcspQa method checkOcsp.

// method checkOcsp
public ValidationResult checkOcsp(OCSPResp response, OcspError expectedOcspError) {
    notNull(response, "response");
    notNull(expectedOcspError, "expectedOcspError");
    List<ValidationIssue> resultIssues = new LinkedList<>();
    int status = response.getStatus();
    // Response status
    ValidationIssue issue = new ValidationIssue("OCSP.STATUS", "response.status");
    resultIssues.add(issue);
    if (status != expectedOcspError.getStatus()) {
        issue.setFailureMessage("is '" + Unsuccessful.getStatusText(status) + "', but expected '" + Unsuccessful.getStatusText(expectedOcspError.getStatus()) + "'");
    }
    return new ValidationResult(resultIssues);
}
Also used : ValidationResult(org.xipki.qa.ValidationResult) ValidationIssue(org.xipki.qa.ValidationIssue)

Aggregations

ValidationIssue (org.xipki.qa.ValidationIssue)3 ValidationResult (org.xipki.qa.ValidationResult)3 BigInteger (java.math.BigInteger)2 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)2 IOException (java.io.IOException)1 PublicKey (java.security.PublicKey)1 ResponderID (org.bouncycastle.asn1.ocsp.ResponderID)1 X500Name (org.bouncycastle.asn1.x500.X500Name)1 Extension (org.bouncycastle.asn1.x509.Extension)1 X509CertificateHolder (org.bouncycastle.cert.X509CertificateHolder)1 ContentVerifierProvider (org.bouncycastle.operator.ContentVerifierProvider)1 X509CertVersion (org.xipki.ca.api.profile.Certprofile.X509CertVersion)1 CertprofileException (org.xipki.ca.api.profile.CertprofileException)1 SignAlgo (org.xipki.security.SignAlgo)1 X509Cert (org.xipki.security.X509Cert)1