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;
  }
Example #9
0
 /** 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();
   }
 }
Example #12
0
  /**
   * 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();
 }
Example #14
0
  /**
   * 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);
    }
  }
Example #16
0
 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;
  }
Example #18
0
 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);
 }
Example #19
0
  /**
   * 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();
 }
Example #23
0
 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;
 }
Example #25
0
  /**
   * 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;
        }
      }
    }
  }
Example #26
0
  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);
  }
Example #27
0
  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);
 }