/** * Create KeyStore and add a self-signed X.509 Certificate * * @param dname the X.509 Distinguished Name, eg "CN=www.google.co.uk, O=\"Google Inc\", * L=\"Mountain View\", S=California, C=US" * @param keyAlgorithmName the key algorithm, eg "RSA" */ private static KeyStore generateCertificate( String alias, char[] keyStorePassword, KeyAlgorithmName keyAlgorithmName, String dname, String... sanDomains) throws GeneralSecurityException, IOException { CertAndKeyGen certAndKeyGen = new CertAndKeyGen( keyAlgorithmName.name(), keyAlgorithmName.signatureAlgorithmName, "SunCertificates"); certAndKeyGen.generate(keyAlgorithmName.keySize); PrivateKey privateKey = certAndKeyGen.getPrivateKey(); X509CertInfo info = new X509CertInfo(); Date from = new Date(); Date to = new Date(from.getTime() + TimeUnit.DAYS.toMillis(360)); CertificateValidity interval = new CertificateValidity(from, to); BigInteger sn = new BigInteger(64, new SecureRandom()); X500Name owner = new X500Name(dname); info.set(X509CertInfo.VALIDITY, interval); info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn)); info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner)); info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner)); info.set(X509CertInfo.KEY, new CertificateX509Key(certAndKeyGen.getPublicKey())); info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); info.set( X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid))); // add subject alternative names GeneralNames generalNames = new GeneralNames(); for (String sanDomain : sanDomains) { generalNames.add(new GeneralName(new DNSName(sanDomain))); } if (generalNames.size() > 0) { CertificateExtensions certificateExtensions = (CertificateExtensions) info.get(X509CertInfo.EXTENSIONS); if (certificateExtensions == null) certificateExtensions = new CertificateExtensions(); certificateExtensions.set( SubjectAlternativeNameExtension.NAME, new SubjectAlternativeNameExtension(generalNames)); info.set(X509CertInfo.EXTENSIONS, certificateExtensions); } // Sign the certificate to identify the algorithm that's used. X509CertImpl x509Certificate = new X509CertImpl(info); x509Certificate.sign(privateKey, keyAlgorithmName.signatureAlgorithmName); // update the algorithm, and resign. info.set( CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, x509Certificate.get(X509CertImpl.SIG_ALG)); x509Certificate = new X509CertImpl(info); x509Certificate.sign(privateKey, keyAlgorithmName.signatureAlgorithmName); // add to new key store KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, keyStorePassword); keyStore.setKeyEntry( alias, privateKey, keyStorePassword, new X509Certificate[] {x509Certificate}); return keyStore; }
void verify(List<CertId> certIds, X509Certificate responderCert, Date date, byte[] nonce) throws CertPathValidatorException { switch (responseStatus) { case SUCCESSFUL: break; case TRY_LATER: case INTERNAL_ERROR: throw new CertPathValidatorException( "OCSP response error: " + responseStatus, null, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS); case UNAUTHORIZED: default: throw new CertPathValidatorException("OCSP response error: " + responseStatus); } // Check that the response includes a response for all of the // certs that were supplied in the request for (CertId certId : certIds) { SingleResponse sr = getSingleResponse(certId); if (sr == null) { if (debug != null) { debug.println("No response found for CertId: " + certId); } throw new CertPathValidatorException( "OCSP response does not include a response for a " + "certificate supplied in the OCSP request"); } if (debug != null) { debug.println( "Status of certificate (with serial number " + certId.getSerialNumber() + ") is: " + sr.getCertStatus()); } } // Check whether the cert returned by the responder is trusted if (!certs.isEmpty()) { X509CertImpl cert = certs.get(0); // First check if the cert matches the expected responder cert if (cert.equals(responderCert)) { // cert is trusted, now verify the signed response // Next check if the cert was issued by the responder cert // which was set locally. } else if (cert.getIssuerX500Principal().equals(responderCert.getSubjectX500Principal())) { // Check for the OCSPSigning key purpose try { List<String> keyPurposes = cert.getExtendedKeyUsage(); if (keyPurposes == null || !keyPurposes.contains(KP_OCSP_SIGNING_OID)) { throw new CertPathValidatorException( "Responder's certificate not valid for signing " + "OCSP responses"); } } catch (CertificateParsingException cpe) { // assume cert is not valid for signing throw new CertPathValidatorException( "Responder's certificate not valid for signing " + "OCSP responses", cpe); } // Check algorithm constraints specified in security property // "jdk.certpath.disabledAlgorithms". AlgorithmChecker algChecker = new AlgorithmChecker(new TrustAnchor(responderCert, null)); algChecker.init(false); algChecker.check(cert, Collections.<String>emptySet()); // check the validity try { if (date == null) { cert.checkValidity(); } else { cert.checkValidity(date); } } catch (CertificateException e) { throw new CertPathValidatorException( "Responder's certificate not within the " + "validity period", e); } // check for revocation // // A CA may specify that an OCSP client can trust a // responder for the lifetime of the responder's // certificate. The CA does so by including the // extension id-pkix-ocsp-nocheck. // Extension noCheck = cert.getExtension(PKIXExtensions.OCSPNoCheck_Id); if (noCheck != null) { if (debug != null) { debug.println( "Responder's certificate includes " + "the extension id-pkix-ocsp-nocheck."); } } else { // we should do the revocation checking of the // authorized responder in a future update. } // verify the signature try { cert.verify(responderCert.getPublicKey()); responderCert = cert; // cert is trusted, now verify the signed response } catch (GeneralSecurityException e) { responderCert = null; } } else { throw new CertPathValidatorException( "Responder's certificate is not authorized to sign " + "OCSP responses"); } } // Confirm that the signed response was generated using the public // key from the trusted responder cert if (responderCert != null) { // Check algorithm constraints specified in security property // "jdk.certpath.disabledAlgorithms". AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId); if (!verifySignature(responderCert)) { throw new CertPathValidatorException("Error verifying OCSP Response's signature"); } } else { // Need responder's cert in order to verify the signature throw new CertPathValidatorException("Unable to verify OCSP Response's signature"); } // Check freshness of OCSPResponse if (nonce != null) { if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) { throw new CertPathValidatorException("Nonces don't match"); } } long now = (date == null) ? System.currentTimeMillis() : date.getTime(); Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW); Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW); for (SingleResponse sr : singleResponseMap.values()) { if (debug != null) { String until = ""; if (sr.nextUpdate != null) { until = " until " + sr.nextUpdate; } debug.println("Response's validity interval is from " + sr.thisUpdate + until); } // Check that the test date is within the validity interval if ((sr.thisUpdate != null && nowPlusSkew.before(sr.thisUpdate)) || (sr.nextUpdate != null && nowMinusSkew.after(sr.nextUpdate))) { throw new CertPathValidatorException( "Response is unreliable: its validity " + "interval is out-of-date"); } } }