Example #1
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;
     }
   }
 }
Example #2
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 #3
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);
  }
  /**
   * 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");
  }
  /*
   * 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);
      }
    }
  }