/** * Obtain the URI use by the {@code StatusResponseManager} during lookups. * This method takes into account not only the AIA extension from a * certificate to be checked, but also any default URI and possible * override settings for the response manager. * * @param cert the subject to get the responder URI from * * @return a {@code URI} containing the address to the OCSP responder, or * {@code null} if no AIA extension exists in the certificate and no * default responder has been configured. * * @throws NullPointerException if {@code cert} is {@code null}. */ URI getURI(X509Certificate cert) { Objects.requireNonNull(cert); if (cert.getExtensionValue( PKIXExtensions.OCSPNoCheck_Id.toString()) != null) { debugLog("OCSP NoCheck extension found. OCSP will be skipped"); return null; } else if (defaultResponder != null && respOverride) { debugLog("Responder override: URI is " + defaultResponder); return defaultResponder; } else { URI certURI = OCSP.getResponderURI(cert); return (certURI != null ? certURI : defaultResponder); } }
/** * Create an {@code OCSPNonceExtension} by providing the nonce length and * criticality setting. The OID for the extension will * be the value defined by "id-pkix-ocsp-nonce" from RFC 6960. * * @param isCritical a boolean flag indicating whether the criticality bit * is set for this extension * @param length the number of random bytes composing the nonce * * @throws IOException if any errors happen during encoding of the * extension. * @throws IllegalArgumentException if length is not a positive integer. */ public OCSPNonceExtension(boolean isCritical, int length) throws IOException { this.extensionId = PKIXExtensions.OCSPNonce_Id; this.critical = isCritical; if (length > 0) { SecureRandom rng = new SecureRandom(); this.nonceData = new byte[length]; rng.nextBytes(nonceData); this.extensionValue = new DerValue(DerValue.tag_OctetString, nonceData).toByteArray(); } else { throw new IllegalArgumentException( "Length must be a positive integer"); } }
/** * Set the response extensions based on the request extensions * that were received. Right now, this is limited to the * OCSP nonce extension. * * @param reqExts a {@code Map} of zero or more request extensions * * @return a {@code Map} of zero or more response extensions, keyed * by the extension object identifier in {@code String} form. */ private Map<String, Extension> setResponseExtensions( Map<String, Extension> reqExts) { Map<String, Extension> respExts = new HashMap<>(); String ocspNonceStr = PKIXExtensions.OCSPNonce_Id.toString(); if (reqExts != null) { for (String id : reqExts.keySet()) { if (id.equals(ocspNonceStr)) { // We found a nonce, add it into the response extensions Extension ext = reqExts.get(id); if (ext != null) { respExts.put(id, ext); log("Added OCSP Nonce to response"); } else { log("Error: Found nonce entry, but found null " + "value. Skipping"); } } } } return respExts; }
/** * Performs the basic constraints and name constraints * checks on the certificate using its internal state. * * @param cert the <code>Certificate</code> to be checked * @param unresCritExts a <code>Collection</code> of OID strings * representing the current set of unresolved critical extensions * @throws CertPathValidatorException if the specified certificate * does not pass the check */ public void check(Certificate cert, Collection<String> unresCritExts) throws CertPathValidatorException { X509Certificate currCert = (X509Certificate) cert; i++; // MUST run NC check second, since it depends on BC check to // update remainingCerts checkBasicConstraints(currCert); verifyNameConstraints(currCert); if (unresCritExts != null && !unresCritExts.isEmpty()) { unresCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString()); unresCritExts.remove(PKIXExtensions.NameConstraints_Id.toString()); } }
/** * Check the cache for a given {@code CertId}. * * @param cid the CertId of the response to look up * @param ocspRequest the OCSP request structure sent by the client * in the TLS status_request[_v2] hello extension. * * @return the {@code ResponseCacheEntry} for a specific CertId, or * {@code null} if it is not found or a nonce extension has been * requested by the caller. */ private ResponseCacheEntry getFromCache(CertId cid, OCSPStatusRequest ocspRequest) { // Determine if the nonce extension is present in the request. If // so, then do not attempt to retrieve the response from the cache. for (Extension ext : ocspRequest.getExtensions()) { if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) { debugLog("Nonce extension found, skipping cache check"); return null; } } ResponseCacheEntry respEntry = responseCache.get(cid); // If the response entry has a nextUpdate and it has expired // before the cache expiration, purge it from the cache // and do not return it as a cache hit. if (respEntry != null && respEntry.nextUpdate != null && respEntry.nextUpdate.before(new Date())) { debugLog("nextUpdate threshold exceeded, purging from cache"); respEntry = null; } debugLog("Check cache for SN" + cid.getSerialNumber() + ": " + (respEntry != null ? "HIT" : "MISS")); return respEntry; }
/** * Checks the revocation status of a list of certificates using OCSP. * * @param certIds the CertIds to be checked * @param responderURI the URI of the OCSP responder * @param issuerInfo the issuer's certificate and/or subject and public key * @param responderCert the OCSP responder's certificate * @param date the time the validity of the OCSP responder's certificate * should be checked against. If null, the current time is used. * @param extensions zero or more OCSP extensions to be included in the * request. If no extensions are requested, an empty {@code List} must * be used. A {@code null} value is not allowed. * @return the OCSPResponse * @throws IOException if there is an exception connecting to or * communicating with the OCSP responder * @throws CertPathValidatorException if an exception occurs while * encoding the OCSP Request or validating the OCSP Response */ static OCSPResponse check(List<CertId> certIds, URI responderURI, OCSPResponse.IssuerInfo issuerInfo, X509Certificate responderCert, Date date, List<Extension> extensions, String variant) throws IOException, CertPathValidatorException { byte[] nonce = null; for (Extension ext : extensions) { if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) { nonce = ext.getValue(); } } OCSPResponse ocspResponse = null; try { byte[] response = getOCSPBytes(certIds, responderURI, extensions); ocspResponse = new OCSPResponse(response); // verify the response ocspResponse.verify(certIds, issuerInfo, responderCert, date, nonce, variant); } catch (IOException ioe) { throw new CertPathValidatorException( "Unable to determine revocation status due to network error", ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } return ocspResponse; }
public static void verifyExtStructure(byte[] derData) throws IOException { debuglog("verifyASN1Extension() received " + derData.length + " bytes"); DerInputStream dis = new DerInputStream(derData); // The sequenceItems array should be either two or three elements // long. If three, then the criticality bit setting has been asserted. DerValue[] sequenceItems = dis.getSequence(3); debuglog("Found sequence containing " + sequenceItems.length + " elements"); if (sequenceItems.length != 2 && sequenceItems.length != 3) { throw new RuntimeException("Incorrect number of items found in " + "the SEQUENCE (Got " + sequenceItems.length + ", expected 2 or 3 items)"); } int seqIndex = 0; ObjectIdentifier extOid = sequenceItems[seqIndex++].getOID(); debuglog("Found OID: " + extOid.toString()); if (!extOid.equals((Object)PKIXExtensions.OCSPNonce_Id)) { throw new RuntimeException("Incorrect OID (Got " + extOid.toString() + ", expected " + PKIXExtensions.OCSPNonce_Id.toString() + ")"); } if (sequenceItems.length == 3) { // Non-default criticality bit setting should be at index 1 boolean isCrit = sequenceItems[seqIndex++].getBoolean(); debuglog("Found BOOLEAN (critical): " + isCrit); } // The extnValue is an encapsulating OCTET STRING that contains the // extension's value. For the OCSP Nonce, that value itself is also // an OCTET STRING consisting of the random bytes. DerValue extnValue = new DerValue(sequenceItems[seqIndex++].getOctetString()); byte[] nonceData = extnValue.getOctetString(); debuglog("Found " + nonceData.length + " bytes of nonce data"); }
/** * Checks the revocation status of a list of certificates using OCSP. * * @param certIds the CertIds to be checked * @param responderURI the URI of the OCSP responder * @param issuerCert the issuer's certificate * @param responderCert the OCSP responder's certificate * @param date the time the validity of the OCSP responder's certificate * should be checked against. If null, the current time is used. * @param extensions zero or more OCSP extensions to be included in the * request. If no extensions are requested, an empty {@code List} must * be used. A {@code null} value is not allowed. * @return the OCSPResponse * @throws IOException if there is an exception connecting to or * communicating with the OCSP responder * @throws CertPathValidatorException if an exception occurs while * encoding the OCSP Request or validating the OCSP Response */ static OCSPResponse check(List<CertId> certIds, URI responderURI, X509Certificate issuerCert, X509Certificate responderCert, Date date, List<Extension> extensions) throws IOException, CertPathValidatorException { byte[] nonce = null; for (Extension ext : extensions) { if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) { nonce = ext.getValue(); } } OCSPResponse ocspResponse = null; try { byte[] response = getOCSPBytes(certIds, responderURI, extensions); ocspResponse = new OCSPResponse(response); // verify the response ocspResponse.verify(certIds, issuerCert, responderCert, date, nonce); } catch (IOException ioe) { throw new CertPathValidatorException( "Unable to determine revocation status due to network error", ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); } return ocspResponse; }
public Set<String> getSupportedExtensions() { if (supportedExts == null) { supportedExts = new HashSet<String>(); supportedExts.add(PKIXExtensions.KeyUsage_Id.toString()); supportedExts.add(PKIXExtensions.ExtendedKeyUsage_Id.toString()); supportedExts.add(PKIXExtensions.SubjectAlternativeName_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; }
/** * Checks that keyUsage and target constraints are satisfied by * the specified certificate. * * @param cert the Certificate * @param unresolvedCritExts the unresolved critical extensions * @exception CertPathValidatorException Exception thrown if certificate * does not verify */ public void check(Certificate cert, Collection<String> unresCritExts) throws CertPathValidatorException { X509Certificate currCert = (X509Certificate) cert; remainingCerts--; // if final certificate, check that target constraints are satisfied if (remainingCerts == 0) { if ((targetConstraints != null) && (targetConstraints.match(currCert) == false)) { throw new CertPathValidatorException("target certificate " + "constraints check failed"); } } else { // otherwise, verify that keyCertSign bit is set in CA certificate verifyCAKeyUsage(currCert); } // remove the extensions that we have checked if (unresCritExts != null && !unresCritExts.isEmpty()) { unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString()); unresCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString()); unresCritExts.remove( PKIXExtensions.SubjectAlternativeName_Id.toString()); } }
public Set<String> getSupportedExtensions() { if (supportedExts == null) { supportedExts = new HashSet<String>(); supportedExts.add(PKIXExtensions.BasicConstraints_Id.toString()); supportedExts.add(PKIXExtensions.NameConstraints_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; }
/** * Gets an immutable Set of the OID strings for the extensions that * the PKIXCertPathChecker supports (i.e. recognizes, is able to * process), or null if no extensions are * supported. All OID strings that a PKIXCertPathChecker might * possibly be able to process should be included. * * @return the Set of extensions supported by this PKIXCertPathChecker, * or null if no extensions are supported */ public Set<String> getSupportedExtensions() { if (supportedExts == null) { supportedExts = new HashSet<String>(); supportedExts.add(PKIXExtensions.CertificatePolicies_Id.toString()); supportedExts.add(PKIXExtensions.PolicyMappings_Id.toString()); supportedExts.add(PKIXExtensions.PolicyConstraints_Id.toString()); supportedExts.add(PKIXExtensions.InhibitAnyPolicy_Id.toString()); supportedExts = Collections.unmodifiableSet(supportedExts); } return supportedExts; }
/** * Performs the policy processing checks on the certificate using its * internal state. * * @param cert the Certificate to be processed * @param unresCritExts the unresolved critical extensions * @exception CertPathValidatorException Exception thrown if * the certificate does not verify. */ public void check(Certificate cert, Collection<String> unresCritExts) throws CertPathValidatorException { // now do the policy checks checkPolicy((X509Certificate) cert); if (unresCritExts != null && !unresCritExts.isEmpty()) { unresCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString()); unresCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString()); unresCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString()); unresCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString()); } }
/** * Merges the specified inhibitAnyPolicy value with the * SkipCerts value of the InhibitAnyPolicy * extension obtained from the certificate. * * @param inhibitAnyPolicy an integer which indicates whether * "any-policy" is considered a match * @param currCert the Certificate to be processed * @return returns the new inhibitAnyPolicy value * @exception CertPathValidatorException Exception thrown if an error * occurs */ static int mergeInhibitAnyPolicy(int inhibitAnyPolicy, X509CertImpl currCert) throws CertPathValidatorException { if ((inhibitAnyPolicy > 0) && !X509CertImpl.isSelfIssued(currCert)) { inhibitAnyPolicy--; } try { InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension) currCert.getExtension(PKIXExtensions.InhibitAnyPolicy_Id); if (inhAnyPolExt == null) return inhibitAnyPolicy; int skipCerts = ((Integer) inhAnyPolExt.get(InhibitAnyPolicyExtension.SKIP_CERTS)).intValue(); if (debug != null) debug.println("PolicyChecker.mergeInhibitAnyPolicy() " + "skipCerts Index from cert = " + skipCerts); if (skipCerts != -1) { if (skipCerts < inhibitAnyPolicy) { inhibitAnyPolicy = skipCerts; } } } catch (Exception e) { if (debug != null) { debug.println("PolicyChecker.mergeInhibitAnyPolicy " + "unexpected exception"); e.printStackTrace(); } throw new CertPathValidatorException(e); } return inhibitAnyPolicy; }