private String hostNameMessage(X509Certificate cert, String hostname) { StringBuffer si = new StringBuffer(); si.append(master.getString(R.string.mtm_hostname_mismatch, hostname)); si.append("\n\n"); try { Collection<List<?>> sans = cert.getSubjectAlternativeNames(); if (sans == null) { si.append(cert.getSubjectDN()); si.append("\n"); } else for (List<?> altName : sans) { Object name = altName.get(1); if (name instanceof String) { si.append("["); si.append((Integer) altName.get(0)); si.append("] "); si.append(name); si.append("\n"); } } } catch (CertificateParsingException e) { e.printStackTrace(); si.append("<Parsing error: "); si.append(e.getLocalizedMessage()); si.append(">\n"); } si.append("\n"); si.append(master.getString(R.string.mtm_connect_anyway)); si.append("\n\n"); si.append(master.getString(R.string.mtm_cert_details)); certDetails(si, cert); return si.toString(); }
/* Cert creation engine */ private static synchronized X509Certificate createX509V3Certificate( PublicKey pubKey, PrivateKey privKey, int ttlMonths, String issuerDN, String subjectDN, long serial, String signAlgoritm) throws GeneralSecurityException { X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator(); certGenerator.reset(); certGenerator.setSerialNumber(java.math.BigInteger.valueOf(serial)); certGenerator.setIssuerDN(new org.bouncycastle.asn1.x509.X509Name(issuerDN)); certGenerator.setNotBefore(new java.util.Date(System.currentTimeMillis())); certGenerator.setNotAfter( new java.util.Date(System.currentTimeMillis() + ttlMonths * (1000L * 60 * 60 * 24 * 30))); certGenerator.setSubjectDN(new org.bouncycastle.asn1.x509.X509Name(subjectDN)); certGenerator.setPublicKey(pubKey); certGenerator.setSignatureAlgorithm(signAlgoritm); X509Certificate cert = certGenerator.generateX509Certificate(privKey, "BC", new java.security.SecureRandom()); cert.checkValidity(new java.util.Date()); cert.verify(pubKey); return cert; }
protected boolean verify(String hostname, SSLSession session, boolean interactive) { LOGGER.log( Level.FINE, "hostname verifier for " + hostname + ", trying default verifier first"); // if the default verifier accepts the hostname, we are done if (defaultVerifier.verify(hostname, session)) { LOGGER.log(Level.FINE, "default verifier accepted " + hostname); return true; } // otherwise, we check if the hostname is an alias for this cert in our keystore try { X509Certificate cert = (X509Certificate) session.getPeerCertificates()[0]; // Log.d(TAG, "cert: " + cert); if (cert.equals(appKeyStore.getCertificate(hostname.toLowerCase(Locale.US)))) { LOGGER.log(Level.FINE, "certificate for " + hostname + " is in our keystore. accepting."); return true; } else { LOGGER.log( Level.FINE, "server " + hostname + " provided wrong certificate, asking user."); if (interactive) { return interactHostname(cert, hostname); } else { return false; } } } catch (Exception e) { e.printStackTrace(); return false; } }
private boolean isValuePartOfX509CertificateList(List<X509Certificate> list, String value) { if (list != null) { for (X509Certificate actAttribute : list) { if (actAttribute.getValue().equals(value)) { return true; } } } return false; }
/** * Return the subject of a certificate as X500Name, by reparsing if necessary. X500Name should * only be used if access to name components is required, in other cases X500Principal is to be * prefered. * * <p>This method is currently used from within JSSE, do not remove. */ public static X500Name getSubjectX500Name(X509Certificate cert) throws CertificateParsingException { try { Principal subjectDN = cert.getSubjectDN(); if (subjectDN instanceof X500Name) { return (X500Name) subjectDN; } else { X500Principal subjectX500 = cert.getSubjectX500Principal(); return new X500Name(subjectX500.getEncoded()); } } catch (IOException e) { throw (CertificateParsingException) new CertificateParsingException().initCause(e); } }
private void certDetails(StringBuffer si, X509Certificate c) { SimpleDateFormat validityDateFormater = new SimpleDateFormat("yyyy-MM-dd"); si.append("\n"); si.append(c.getSubjectDN().toString()); si.append("\n"); si.append(validityDateFormater.format(c.getNotBefore())); si.append(" - "); si.append(validityDateFormater.format(c.getNotAfter())); si.append("\nSHA-256: "); si.append(certHash(c, "SHA-256")); si.append("\nSHA-1: "); si.append(certHash(c, "SHA-1")); si.append("\nSigned by: "); si.append(c.getIssuerDN().toString()); si.append("\n"); }
/** * Check if the certificate allows use of the given DNS name. * * <p>From RFC2818: If a subjectAltName extension of type dNSName is present, that MUST be used as * the identity. Otherwise, the (most specific) Common Name field in the Subject field of the * certificate MUST be used. Although the use of the Common Name is existing practice, it is * deprecated and Certification Authorities are encouraged to use the dNSName instead. * * <p>Matching is performed using the matching rules specified by [RFC2459]. If more than one * identity of a given type is present in the certificate (e.g., more than one dNSName name, a * match in any one of the set is considered acceptable.) */ private void matchDNS(String expectedName, X509Certificate cert) throws CertificateException { Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames(); if (subjAltNames != null) { boolean foundDNS = false; for (List<?> next : subjAltNames) { if (((Integer) next.get(0)).intValue() == ALTNAME_DNS) { foundDNS = true; String dnsName = (String) next.get(1); if (isMatched(expectedName, dnsName)) { return; } } } if (foundDNS) { // if certificate contains any subject alt names of type DNS // but none match, reject throw new CertificateException( "No subject alternative DNS " + "name matching " + expectedName + " found."); } } X500Name subjectName = getSubjectX500Name(cert); DerValue derValue = subjectName.findMostSpecificAttribute(X500Name.commonName_oid); if (derValue != null) { try { if (isMatched(expectedName, derValue.getAsString())) { return; } } catch (IOException e) { // ignore } } String msg = "No name matching " + expectedName + " found"; throw new CertificateException(msg); }
/* * Returns the list of root certificates * The list of certificates we received is an array of certificates * we have to determine * 1) how many chain do we have (a chain stops when verifier of a cert is * not the signer of the next cert in the list * 2) build a cert with the leaf signer and the root verifier for each chain */ public CertificatePair[] getRootCertificates() { if (rootCertificates == null) { rootCertificates = new CertificatePair[0]; List rootCertificatesList = new ArrayList(); if (certificates != null && certificates.size() > 0) { Iterator iter = certificates.iterator(); while (iter.hasNext()) { Certificate[] certs = (Certificate[]) iter.next(); if (certs != null && certs.length > 0) { CertificatePair pair = new CertificatePair(); pair.setIssuer(certs[0]); for (int i = 0; i < certs.length - 1; i++) { X509Certificate x509certRoot = (X509Certificate) certs[i]; X509Certificate x509certIssuer = (X509Certificate) certs[i + 1]; if (!x509certRoot.getIssuerDN().equals(x509certIssuer.getSubjectDN())) { pair.setRoot(x509certRoot); if (!rootCertificatesList.contains(pair)) { rootCertificatesList.add(pair); } pair = new CertificatePair(); pair.setIssuer(x509certIssuer); } } // add the latest one if (pair != null) { pair.setRoot(certs[certs.length - 1]); if (!rootCertificatesList.contains(pair)) { rootCertificatesList.add(pair); } } } } } if (rootCertificatesList.size() > 0) { rootCertificates = new CertificatePair[rootCertificatesList.size()]; rootCertificatesList.toArray(rootCertificates); } } return rootCertificates; }
/** return the subject of the given cert as an X509PrincipalObject. */ public static X509Principal getSubjectX509Principal(X509Certificate cert) throws CertificateEncodingException { try { TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(ASN1Object.fromByteArray(cert.getTBSCertificate())); return new X509Principal(tbsCert.getSubject()); } catch (IOException e) { throw new CertificateEncodingException(e.toString()); } }
/* * Returns a String to show if the certificate is valid */ private String checkValidity(X509Certificate cert) { try { cert.checkValidity(); } catch (CertificateExpiredException e) { return ("\r\n" + Messages.JarVerificationResult_ExpiredCertificate); // $NON-NLS-1$ } catch (CertificateNotYetValidException e) { return ("\r\n" + Messages.JarVerificationResult_CertificateNotYetValid); // $NON-NLS-1$ } return ("\r\n" + Messages.JarVerificationResult_CertificateValid); // $NON-NLS-1$ }
private static String certHash(final X509Certificate cert, String digest) { try { MessageDigest md = MessageDigest.getInstance(digest); md.update(cert.getEncoded()); return hexString(md.digest()); } catch (java.security.cert.CertificateEncodingException e) { return e.getMessage(); } catch (java.security.NoSuchAlgorithmException e) { return e.getMessage(); } }
/** * Checks certification path by IssuerX500Principal keyed in CAroot<br> * <br> * Risale il certification path attraverso IssuerX500Principal chiave in CAroot * * @return true: if certification path is valid */ public boolean getPathValid() { isPathValid = true; X509Certificate certChild = cert; X509Certificate certParent = null; while (!certChild.getIssuerDN().equals(certChild.getSubjectDN())) { // finche' la CA non è autofirmata try { certParent = CAroot.getCACertificate(certChild.getIssuerX500Principal()); } catch (GeneralSecurityException ex) { // la CA non è presente nella root isPathValid = false; return isPathValid; } certChild = certParent; } ; return isPathValid; }
private String certChainMessage(final X509Certificate[] chain, CertificateException cause) { Throwable e = cause; Log.d(TAG, "certChainMessage for " + e); StringBuffer si = new StringBuffer(); if (e.getCause() != null) { e = e.getCause(); si.append(e.getLocalizedMessage()); // si.append("\n"); } for (X509Certificate c : chain) { si.append("\n\n"); si.append(c.getSubjectDN().toString()); si.append("\nMD5: "); si.append(certHash(c, "MD5")); si.append("\nSHA1: "); si.append(certHash(c, "SHA-1")); si.append("\nSigned by: "); si.append(c.getIssuerDN().toString()); } return si.toString(); }
/** * Return true if the certificate is active<br> * <br> * Restituisce true se il certificato è ancora attivo * * @return true: if the certificate is active */ public boolean getInUse() { try { cert.checkValidity(); isInUse = true; isExpired = false; } catch (CertificateNotYetValidException ex) { isInUse = false; } catch (CertificateExpiredException ex) { isExpired = true; } return isInUse; }
void storeCert(X509Certificate[] chain) { // add all certs from chain to appKeyStore try { for (X509Certificate c : chain) appKeyStore.setCertificateEntry(c.getSubjectDN().toString(), c); } catch (KeyStoreException e) { Log.e(TAG, "storeCert(" + chain + ")", e); return; } // reload appTrustManager appTrustManager = getTrustManager(appKeyStore); // store KeyStore to file try { java.io.FileOutputStream fos = new java.io.FileOutputStream(keyStoreFile); appKeyStore.store(fos, "MTM".toCharArray()); fos.close(); } catch (Exception e) { Log.e(TAG, "storeCert(" + keyStoreFile + ")", e); } }
private boolean isSignatureValid(List<PublicKey> keys, X509Certificate sub) { if (plugin) { for (PublicKey key : keys) { try { sub.verify(key); return true; } catch (Exception ex) { continue; } } return false; } return true; // only check if PLUGIN is set }
/** * Construct a "simplified name" based on the subject DN from the certificate. The purpose is to * have something shorter to display in the list. The name used is one of the following DN parts, * if available, otherwise the complete DN: 'CN', 'OU' or else 'O'. * * @param cert to read subject DN from * @return the simplified name */ private static String getSimplifiedName(X509Certificate cert) { final HashMap<String, String> parts = new HashMap<String, String>(); try { for (Rdn name : new LdapName(cert.getSubjectX500Principal().getName()).getRdns()) { if (name.getType() != null && name.getValue() != null) { parts.put(name.getType(), name.getValue().toString()); } } } catch (InvalidNameException ignored) // NOPMD { } String result = parts.get("CN"); if (result == null) { result = parts.get("OU"); } if (result == null) { result = parts.get("O"); } if (result == null) { result = cert.getSubjectX500Principal().getName(); } return result; }
private void initCommon() { if (TRY_VALIDATOR == false) { return; } trustedSubjects = new HashMap<X500Principal, List<PublicKey>>(); for (Iterator t = trustedCerts.iterator(); t.hasNext(); ) { X509Certificate cert = (X509Certificate) t.next(); X500Principal dn = cert.getSubjectX500Principal(); List<PublicKey> keys; if (trustedSubjects.containsKey(dn)) { keys = trustedSubjects.get(dn); } else { keys = new ArrayList<PublicKey>(); trustedSubjects.put(dn, keys); } keys.add(cert.getPublicKey()); } try { factory = CertificateFactory.getInstance("X.509"); } catch (CertificateException e) { throw new RuntimeException("Internal error", e); } plugin = variant.equals(VAR_PLUGIN_CODE_SIGNING); }
/** * Return the general result<br> * <br> * Restituisce il risultato di tutte le verifiche * * @return true: if certificate is valid */ public boolean getPassed() { isPathValid = this.getPathValid(); isExpired = this.getExpired(); isInUse = this.getInUse(); isRevoked = this.getRevoked(); isPassed = isPathValid && !isRevoked && !isExpired && isInUse; System.out.println( "************************Verifica: " + cert.getSubjectDN() + "\n Risultato getPassed: " + isPassed); CRLerror = CRL.getCRLerror(); return isPassed; }
/* * Initializes the signerInfo and the VerifierInfo from the Certificate Pair */ private void initializeCertificates() { X509Certificate certRoot = null; X509Certificate certIssuer = null; CertificatePair trustedCertificate; if (getFoundCertificate() == null) { CertificatePair[] certs = getRootCertificates(); if (certs.length == 0) return; trustedCertificate = certs[0]; } else { trustedCertificate = getFoundCertificate(); } certRoot = (X509Certificate) trustedCertificate.getRoot(); certIssuer = (X509Certificate) trustedCertificate.getIssuer(); StringBuffer strb = new StringBuffer(); strb.append(issuerString(certIssuer.getSubjectDN())); strb.append("\r\n"); // $NON-NLS-1$ strb.append( NLS.bind( Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certIssuer.getNotBefore()), dateString(certIssuer.getNotAfter()) }))); strb.append(checkValidity(certIssuer)); signerInfo = strb.toString(); if (certIssuer != null && !certIssuer.equals(certRoot)) { strb = new StringBuffer(); strb.append(issuerString(certIssuer.getIssuerDN())); strb.append("\r\n"); // $NON-NLS-1$ strb.append( NLS.bind( Messages.JarVerificationResult_ValidBetween, (new String[] { dateString(certRoot.getNotBefore()), dateString(certRoot.getNotAfter()) }))); strb.append(checkValidity(certRoot)); verifierInfo = strb.toString(); } }
/** * Check if the certificate allows use of the given IP address. * * <p>From RFC2818: In some cases, the URI is specified as an IP address rather than a hostname. * In this case, the iPAddress subjectAltName must be present in the certificate and must exactly * match the IP in the URI. */ private static void matchIP(String expectedIP, X509Certificate cert) throws CertificateException { Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames(); if (subjAltNames == null) { throw new CertificateException("No subject alternative names present"); } for (List<?> next : subjAltNames) { // For IP address, it needs to be exact match if (((Integer) next.get(0)).intValue() == ALTNAME_IP) { String ipAddress = (String) next.get(1); if (expectedIP.equalsIgnoreCase(ipAddress)) { return; } } } throw new CertificateException( "No subject alternative " + "names matching " + "IP address " + expectedIP + " found"); }
/** * Calculates the hash of the certificate known as the "thumbprint" and returns it as a string * representation. * * @param cert The certificate to hash. * @param algorithm The hash algorithm to use. * @return The SHA-1 hash of the certificate. * @throws CertificateException */ private static String getThumbprint(X509Certificate cert, String algorithm) throws CertificateException { MessageDigest digest; try { digest = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { throw new CertificateException(e); } byte[] encodedCert = cert.getEncoded(); StringBuilder sb = new StringBuilder(encodedCert.length * 2); Formatter f = new Formatter(sb); try { for (byte b : digest.digest(encodedCert)) f.format("%02x", b); } finally { f.close(); } return sb.toString(); }
private void verify(X509Certificate[] certs, String authType) throws CertificateException { final int len = certs.length; for (int i = 0; i < len; i++) { final X509Certificate currentX509Cert = certs[i]; try { if (i == len - 1) { if (currentX509Cert.getSubjectDN().equals(currentX509Cert.getIssuerDN())) currentX509Cert.verify(currentX509Cert.getPublicKey()); } else { final X509Certificate nextX509Cert = certs[i + 1]; currentX509Cert.verify(nextX509Cert.getPublicKey()); } } catch (final Exception e) { final CertificateException ce = new ECFCertificateException( "Certificate chain is not valid", certs, authType); // $NON-NLS-1$ ce.initCause(e); throw ce; } } }
/** * Return an interned X509CertImpl for the given certificate. If the given X509Certificate or * X509CertImpl is already present in the cert cache, the cached object is returned. Otherwise, if * it is a X509Certificate, it is first converted to a X509CertImpl. Then the X509CertImpl is * added to the cache and returned. * * <p>Note that all certificates created via generateCertificate(InputStream) are already interned * and this method does not need to be called. It is useful for certificates that cannot be * created via generateCertificate() and for converting other X509Certificate implementations to * an X509CertImpl. */ public static synchronized X509CertImpl intern(X509Certificate c) throws CertificateException { if (c == null) { return null; } boolean isImpl = c instanceof X509CertImpl; byte[] encoding; if (isImpl) { encoding = ((X509CertImpl) c).getEncodedInternal(); } else { encoding = c.getEncoded(); } X509CertImpl newC = getFromCache(certCache, encoding); if (newC != null) { return newC; } if (isImpl) { newC = (X509CertImpl) c; } else { newC = new X509CertImpl(encoding); encoding = newC.getEncodedInternal(); } addToCache(certCache, encoding, newC); return newC; }
/** * Connect to the underlying secure socket transport. Perform the SSL handshake and then proceded * to the underlying HTTP protocol connect semantics. * * @return SSL/TCP stream connection * @exception IOException is thrown if the connection cannot be opened */ protected StreamConnection connect() throws IOException { String httpsTunnel; com.sun.midp.io.j2me.socket.Protocol tcpConnection; OutputStream tcpOutputStream; InputStream tcpInputStream; X509Certificate serverCert; verifyPermissionCheck(); /* * To save memory for applications the do not use HTTPS, * the public keys of the certificate authorities may not * have been loaded yet. */ WebPublicKeyStore.loadCertificateAuthorities(); // Open socket connection tcpConnection = new com.sun.midp.io.j2me.socket.Protocol(); // check to see if a protocol is specified for the tunnel httpsTunnel = Configuration.getProperty("com.sun.midp.io.http.proxy"); if (httpsTunnel != null) { // Make the connection to the ssl tunnel tcpConnection.openPrim(classSecurityToken, "//" + httpsTunnel); // Do not delay request since this delays the response. tcpConnection.setSocketOption(SocketConnection.DELAY, 0); tcpOutputStream = tcpConnection.openOutputStream(); tcpInputStream = tcpConnection.openInputStream(); // Do the handshake with the ssl tunnel try { doTunnelHandshake(tcpOutputStream, tcpInputStream); } catch (IOException ioe) { String temp = ioe.getMessage(); tcpConnection.close(); tcpOutputStream.close(); tcpInputStream.close(); if (temp.indexOf(" 500 ") > -1) { throw new ConnectionNotFoundException(temp); } throw ioe; } } else { tcpConnection.openPrim(classSecurityToken, "//" + hostAndPort); // Do not delay request since this delays the response. tcpConnection.setSocketOption(SocketConnection.DELAY, 0); tcpOutputStream = tcpConnection.openOutputStream(); tcpInputStream = tcpConnection.openInputStream(); } tcpConnection.close(); try { // Get the SSLStreamConnection sslConnection = new SSLStreamConnection(url.host, url.port, tcpInputStream, tcpOutputStream); } catch (Exception e) { try { tcpInputStream.close(); } finally { try { tcpOutputStream.close(); } finally { if (e instanceof IOException) { throw (IOException) e; } else { throw (RuntimeException) e; } } } } try { serverCert = sslConnection.getServerCertificate(); /* * if the subject alternate name is a DNS name, * then use that instead of the common name for a * site name match */ if (serverCert.getSubjectAltNameType() == X509Certificate.TYPE_DNS_NAME) { if (!checkSiteName(url.host, (String) serverCert.getSubjectAltName())) { throw new CertificateException( "Subject alternative name did not match site name", serverCert, CertificateException.SITENAME_MISMATCH); } } else { String cname = getCommonName(serverCert.getSubject()); if (cname == null) { throw new CertificateException( "Common name missing from subject name", serverCert, CertificateException.SITENAME_MISMATCH); } if (!checkSiteName(url.host, cname)) { throw new CertificateException(serverCert, CertificateException.SITENAME_MISMATCH); } } return sslConnection; } catch (Exception e) { try { sslConnection.close(); } finally { if (e instanceof IOException) { throw (IOException) e; } else { throw (RuntimeException) e; } } } }
X509Certificate[] engineValidate(X509Certificate[] chain, Collection otherCerts, Object parameter) throws CertificateException { if ((chain == null) || (chain.length == 0)) { throw new CertificateException("null or zero-length certificate chain"); } if (TRY_VALIDATOR) { // check that chain is in correct order and check if chain contains // trust anchor X500Principal prevIssuer = null; for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; X500Principal dn = cert.getSubjectX500Principal(); if (i != 0 && !dn.equals(prevIssuer)) { // chain is not ordered correctly, call builder instead return doBuild(chain, otherCerts); } // Check if chain[i] is already trusted. It may be inside // trustedCerts, or has the same dn and public key as a cert // inside trustedCerts. The latter happens when a CA has // updated its cert with a stronger signature algorithm in JRE // but the weak one is still in circulation. if (trustedCerts.contains(cert) || // trusted cert (trustedSubjects.containsKey(dn) && // replacing ... trustedSubjects .get(dn) .contains( // ... weak cert cert.getPublicKey()))) { if (i == 0) { return new X509Certificate[] {chain[0]}; } // Remove and call validator on partial chain [0 .. i-1] X509Certificate[] newChain = new X509Certificate[i]; System.arraycopy(chain, 0, newChain, 0, i); return doValidate(newChain); } prevIssuer = cert.getIssuerX500Principal(); } // apparently issued by trust anchor? X509Certificate last = chain[chain.length - 1]; X500Principal issuer = last.getIssuerX500Principal(); X500Principal subject = last.getSubjectX500Principal(); if (trustedSubjects.containsKey(issuer) && isSignatureValid(trustedSubjects.get(issuer), last)) { return doValidate(chain); } // don't fallback to builder if called from plugin/webstart if (plugin) { // Validate chain even if no trust anchor is found. This // allows plugin/webstart to make sure the chain is // otherwise valid if (chain.length > 1) { X509Certificate[] newChain = new X509Certificate[chain.length - 1]; System.arraycopy(chain, 0, newChain, 0, newChain.length); // temporarily set last cert as sole trust anchor PKIXBuilderParameters params = (PKIXBuilderParameters) parameterTemplate.clone(); try { params.setTrustAnchors( Collections.singleton(new TrustAnchor(chain[chain.length - 1], null))); } catch (InvalidAlgorithmParameterException iape) { // should never occur, but ... throw new CertificateException(iape); } doValidate(newChain, params); } // if the rest of the chain is valid, throw exception // indicating no trust anchor was found throw new ValidatorException(ValidatorException.T_NO_TRUST_ANCHOR); } // otherwise, fall back to builder } return doBuild(chain, otherCerts); }
public static void main(String[] args) throws Exception { // Get a CertificateFactory for various tests CF = CertificateFactory.getInstance("X509"); ByteArrayInputStream bais = new ByteArrayInputStream(readFile("int.crt").getBytes()); X509Certificate intCA = (X509Certificate) CF.generateCertificate(bais); System.out.println( "Successfully instantiated CA cert \"" + intCA.getSubjectX500Principal() + "\""); CertId cid0x1500 = new CertId(intCA, new SerialNumber(0x1500)); boolean noFailures = true; OCSPResponse.SingleResponse sr = getSRByFilename("ocsp-good-nonext.resp", cid0x1500); noFailures &= checkSingleExts(sr, 0); if (sr.getRevocationTime() != null) { throw new RuntimeException("Oops. revocationTime is non-null " + sr.getRevocationTime()); } else if (sr.getRevocationReason() != null) { throw new RuntimeException("Oops. revocationReason is non-null " + sr.getRevocationReason()); } sr = getSRByFilename("ocsp-good-withnext.resp", cid0x1500); noFailures &= checkSingleExts(sr, 0); sr = getSRByFilename("ocsp-good-witharchcut.resp", cid0x1500); noFailures &= checkSingleExts(sr, 1); sr = getSRByFilename("ocsp-rev-nocerts.resp", cid0x1500); noFailures &= checkSingleExts(sr, 1); sr = getSRByFilename("ocsp-rev-nonext-noinv.resp", cid0x1500); noFailures &= checkSingleExts(sr, 0); sr = getSRByFilename("ocsp-rev-withnext-noinv.resp", cid0x1500); noFailures &= checkSingleExts(sr, 0); sr = getSRByFilename("ocsp-rev-nonext-withinv.resp", cid0x1500); noFailures &= checkSingleExts(sr, 1); sr = getSRByFilename("ocsp-rev-withnext-withinv.resp", cid0x1500); noFailures &= checkSingleExts(sr, 1); try { sr = getSRByFilename("ocsp-rev-twonext.resp", cid0x1500); System.out.println("FAIL: Allowed two nextUpdate fields"); noFailures = false; } catch (IOException ioe) { System.out.println("Caught expected exception: " + ioe); } try { sr = getSRByFilename("ocsp-rev-bad-sr-tag.resp", cid0x1500); System.out.println("FAIL: Allowed invalid singleResponse item"); noFailures = false; } catch (IOException ioe) { System.out.println("Caught expected exception: " + ioe); } try { sr = getSRByFilename("ocsp-rev-sr-cont-reverse.resp", cid0x1500); System.out.println("FAIL: Allowed reversed " + "nextUpdate/singleExtensions"); noFailures = false; } catch (IOException ioe) { System.out.println("Caught expected exception: " + ioe); } if (!noFailures) { throw new RuntimeException("One or more tests failed"); } }
/* * This method performs a depth first search for a certification * path while building forward which meets the requirements set in * the parameters object. * It uses an adjacency list to store all certificates which were * tried (i.e. at one time added to the path - they may not end up in * the final path if backtracking occurs). This information can * be used later to debug or demo the build. * * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman" * for an explanation of the DFS algorithm. * * @param dN the distinguished name being currently searched for certs * @param currentState the current PKIX validation state */ private void depthFirstSearchForward( X500Principal dN, ForwardState currentState, ForwardBuilder builder, List<List<Vertex>> adjList, LinkedList<X509Certificate> cpList) throws GeneralSecurityException, IOException { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(" + dN + ", " + currentState.toString() + ")"); } /* * Find all the certificates issued to dN which * satisfy the PKIX certification path constraints. */ Collection<X509Certificate> certs = builder.getMatchingCerts(currentState, buildParams.certStores()); List<Vertex> vertices = addVertices(certs, adjList); if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "certs.size=" + vertices.size()); } /* * For each cert in the collection, verify anything * that hasn't been checked yet (signature, revocation, etc) * and check for loops. Call depthFirstSearchForward() * recursively for each good cert. */ vertices: for (Vertex vertex : vertices) { /** * Restore state to currentState each time through the loop. This is important because some of * the user-defined checkers modify the state, which MUST be restored if the cert eventually * fails to lead to the target and the next matching cert is tried. */ ForwardState nextState = (ForwardState) currentState.clone(); X509Certificate cert = vertex.getCertificate(); try { builder.verifyCert(cert, nextState, cpList); } catch (GeneralSecurityException gse) { if (debug != null) { debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": validation failed: " + gse); gse.printStackTrace(); } vertex.setThrowable(gse); continue; } /* * Certificate is good. * If cert completes the path, * process userCheckers that don't support forward checking * and process policies over whole path * and backtrack appropriately if there is a failure * else if cert does not complete the path, * add it to the path */ if (builder.isPathCompleted(cert)) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": commencing final verification"); List<X509Certificate> appendedCerts = new ArrayList<>(cpList); /* * if the trust anchor selected is specified as a trusted * public key rather than a trusted cert, then verify this * cert (which is signed by the trusted public key), but * don't add it yet to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) { appendedCerts.add(0, cert); } Set<String> initExpPolSet = Collections.singleton(PolicyChecker.ANY_POLICY); PolicyNodeImpl rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false); List<PKIXCertPathChecker> checkers = new ArrayList<>(); PolicyChecker policyChecker = new PolicyChecker( buildParams.initialPolicies(), appendedCerts.size(), buildParams.explicitPolicyRequired(), buildParams.policyMappingInhibited(), buildParams.anyPolicyInhibited(), buildParams.policyQualifiersRejected(), rootNode); checkers.add(policyChecker); // add the algorithm checker checkers.add(new AlgorithmChecker(builder.trustAnchor)); BasicChecker basicChecker = null; if (nextState.keyParamsNeeded()) { PublicKey rootKey = cert.getPublicKey(); if (builder.trustAnchor.getTrustedCert() == null) { rootKey = builder.trustAnchor.getCAPublicKey(); if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward " + "using buildParams public key: " + rootKey.toString()); } TrustAnchor anchor = new TrustAnchor(cert.getSubjectX500Principal(), rootKey, null); // add the basic checker basicChecker = new BasicChecker(anchor, buildParams.date(), buildParams.sigProvider(), true); checkers.add(basicChecker); } buildParams.setCertPath(cf.generateCertPath(appendedCerts)); boolean revCheckerAdded = false; List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers(); for (PKIXCertPathChecker ckr : ckrs) { if (ckr instanceof PKIXRevocationChecker) { if (revCheckerAdded) { throw new CertPathValidatorException( "Only one PKIXRevocationChecker can be specified"); } revCheckerAdded = true; // if it's our own, initialize it if (ckr instanceof RevocationChecker) { ((RevocationChecker) ckr).init(builder.trustAnchor, buildParams); } } } // only add a RevocationChecker if revocation is enabled and // a PKIXRevocationChecker has not already been added if (buildParams.revocationEnabled() && !revCheckerAdded) { checkers.add(new RevocationChecker(builder.trustAnchor, buildParams)); } checkers.addAll(ckrs); // Why we don't need BasicChecker and RevocationChecker // if nextState.keyParamsNeeded() is false? for (int i = 0; i < appendedCerts.size(); i++) { X509Certificate currCert = appendedCerts.get(i); if (debug != null) debug.println("current subject = " + currCert.getSubjectX500Principal()); Set<String> unresCritExts = currCert.getCriticalExtensionOIDs(); if (unresCritExts == null) { unresCritExts = Collections.<String>emptySet(); } for (PKIXCertPathChecker currChecker : checkers) { if (!currChecker.isForwardCheckingSupported()) { if (i == 0) { currChecker.init(false); // The user specified // AlgorithmChecker may not be // able to set the trust anchor until now. if (currChecker instanceof AlgorithmChecker) { ((AlgorithmChecker) currChecker).trySetTrustAnchor(builder.trustAnchor); } } try { currChecker.check(currCert, unresCritExts); } catch (CertPathValidatorException cpve) { if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward(): " + "final verification failed: " + cpve); // If the target cert itself is revoked, we // cannot trust it. We can bail out here. if (buildParams.targetCertConstraints().match(currCert) && cpve.getReason() == BasicReason.REVOKED) { throw cpve; } vertex.setThrowable(cpve); continue vertices; } } } /* * Remove extensions from user checkers that support * forward checking. After this step, we will have * removed all extensions that all user checkers * are capable of processing. */ for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) { if (checker.isForwardCheckingSupported()) { Set<String> suppExts = checker.getSupportedExtensions(); if (suppExts != null) { unresCritExts.removeAll(suppExts); } } } if (!unresCritExts.isEmpty()) { unresCritExts.remove(BasicConstraints_Id.toString()); unresCritExts.remove(NameConstraints_Id.toString()); unresCritExts.remove(CertificatePolicies_Id.toString()); unresCritExts.remove(PolicyMappings_Id.toString()); unresCritExts.remove(PolicyConstraints_Id.toString()); unresCritExts.remove(InhibitAnyPolicy_Id.toString()); unresCritExts.remove(SubjectAlternativeName_Id.toString()); unresCritExts.remove(KeyUsage_Id.toString()); unresCritExts.remove(ExtendedKeyUsage_Id.toString()); if (!unresCritExts.isEmpty()) { throw new CertPathValidatorException( "unrecognized critical extension(s)", null, null, -1, PKIXReason.UNRECOGNIZED_CRIT_EXT); } } } if (debug != null) debug.println( "SunCertPathBuilder.depthFirstSearchForward()" + ": final verification succeeded - path completed!"); pathCompleted = true; /* * if the user specified a trusted public key rather than * trusted certs, then add this cert (which is signed by * the trusted public key) to the cpList */ if (builder.trustAnchor.getTrustedCert() == null) builder.addCertToPath(cert, cpList); // Save the trust anchor this.trustAnchor = builder.trustAnchor; /* * Extract and save the final target public key */ if (basicChecker != null) { finalPublicKey = basicChecker.getPublicKey(); } else { Certificate finalCert; if (cpList.isEmpty()) { finalCert = builder.trustAnchor.getTrustedCert(); } else { finalCert = cpList.getLast(); } finalPublicKey = finalCert.getPublicKey(); } policyTreeResult = policyChecker.getPolicyTree(); return; } else { builder.addCertToPath(cert, cpList); } /* Update the PKIX state */ nextState.updateState(cert); /* * Append an entry for cert in adjacency list and * set index for current vertex. */ adjList.add(new LinkedList<Vertex>()); vertex.setIndex(adjList.size() - 1); /* recursively search for matching certs at next dN */ depthFirstSearchForward(cert.getIssuerX500Principal(), nextState, builder, adjList, cpList); /* * If path has been completed, return ASAP! */ if (pathCompleted) { return; } else { /* * If we get here, it means we have searched all possible * certs issued by the dN w/o finding any matching certs. * This means we have to backtrack to the previous cert in * the path and try some other paths. */ if (debug != null) debug.println("SunCertPathBuilder.depthFirstSearchForward()" + ": backtracking"); builder.removeFinalCertFromPath(cpList); } } }
/** * Appends an HTML representation of the given X509Certificate. * * @param sb StringBuilder to append to * @param certificate to print */ private void renderX509(StringBuilder sb, X509Certificate certificate) { X500Principal issuer = certificate.getIssuerX500Principal(); X500Principal subject = certificate.getSubjectX500Principal(); sb.append("<table cellspacing='1' cellpadding='1'>\n"); // subject addTitle(sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_TO")); try { for (Rdn name : new LdapName(subject.getName()).getRdns()) { String nameType = name.getType(); String lblKey = "service.gui.CERT_INFO_" + nameType; String lbl = R.getI18NString(lblKey); if ((lbl == null) || ("!" + lblKey + "!").equals(lbl)) lbl = nameType; final String value; Object nameValue = name.getValue(); if (nameValue instanceof byte[]) { byte[] nameValueAsByteArray = (byte[]) nameValue; value = getHex(nameValueAsByteArray) + " (" + new String(nameValueAsByteArray) + ")"; } else value = nameValue.toString(); addField(sb, lbl, value); } } catch (InvalidNameException ine) { addField(sb, R.getI18NString("service.gui.CERT_INFO_CN"), subject.getName()); } // issuer addTitle(sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_BY")); try { for (Rdn name : new LdapName(issuer.getName()).getRdns()) { String nameType = name.getType(); String lblKey = "service.gui.CERT_INFO_" + nameType; String lbl = R.getI18NString(lblKey); if ((lbl == null) || ("!" + lblKey + "!").equals(lbl)) lbl = nameType; final String value; Object nameValue = name.getValue(); if (nameValue instanceof byte[]) { byte[] nameValueAsByteArray = (byte[]) nameValue; value = getHex(nameValueAsByteArray) + " (" + new String(nameValueAsByteArray) + ")"; } else value = nameValue.toString(); addField(sb, lbl, value); } } catch (InvalidNameException ine) { addField(sb, R.getI18NString("service.gui.CERT_INFO_CN"), issuer.getName()); } // validity addTitle(sb, R.getI18NString("service.gui.CERT_INFO_VALIDITY")); addField( sb, R.getI18NString("service.gui.CERT_INFO_ISSUED_ON"), certificate.getNotBefore().toString()); addField( sb, R.getI18NString("service.gui.CERT_INFO_EXPIRES_ON"), certificate.getNotAfter().toString()); addTitle(sb, R.getI18NString("service.gui.CERT_INFO_FINGERPRINTS")); try { String sha1String = getThumbprint(certificate, "SHA1"); String md5String = getThumbprint(certificate, "MD5"); addField(sb, "SHA1:", sha1String); addField(sb, "MD5:", md5String); } catch (CertificateException e) { // do nothing as we cannot show this value } addTitle(sb, R.getI18NString("service.gui.CERT_INFO_CERT_DETAILS")); addField( sb, R.getI18NString("service.gui.CERT_INFO_SER_NUM"), certificate.getSerialNumber().toString()); addField( sb, R.getI18NString("service.gui.CERT_INFO_VER"), String.valueOf(certificate.getVersion())); addField( sb, R.getI18NString("service.gui.CERT_INFO_SIGN_ALG"), String.valueOf(certificate.getSigAlgName())); addTitle(sb, R.getI18NString("service.gui.CERT_INFO_PUB_KEY_INFO")); addField( sb, R.getI18NString("service.gui.CERT_INFO_ALG"), certificate.getPublicKey().getAlgorithm()); if (certificate.getPublicKey().getAlgorithm().equals("RSA")) { RSAPublicKey key = (RSAPublicKey) certificate.getPublicKey(); addField( sb, R.getI18NString("service.gui.CERT_INFO_PUB_KEY"), R.getI18NString( "service.gui.CERT_INFO_KEY_BYTES_PRINT", new String[] { String.valueOf(key.getModulus().toByteArray().length - 1), key.getModulus().toString(16) })); addField( sb, R.getI18NString("service.gui.CERT_INFO_EXP"), key.getPublicExponent().toString()); addField( sb, R.getI18NString("service.gui.CERT_INFO_KEY_SIZE"), R.getI18NString( "service.gui.CERT_INFO_KEY_BITS_PRINT", new String[] {String.valueOf(key.getModulus().bitLength())})); } else if (certificate.getPublicKey().getAlgorithm().equals("DSA")) { DSAPublicKey key = (DSAPublicKey) certificate.getPublicKey(); addField(sb, "Y:", key.getY().toString(16)); } addField( sb, R.getI18NString("service.gui.CERT_INFO_SIGN"), R.getI18NString( "service.gui.CERT_INFO_KEY_BYTES_PRINT", new String[] { String.valueOf(certificate.getSignature().length), getHex(certificate.getSignature()) })); sb.append("</table>\n"); }
void storeCert(X509Certificate cert) { storeCert(cert.getSubjectDN().toString(), cert); }