Ejemplo n.º 1
0
  private static void runTest(String[] certStrs, String[] trustedCertStrs) throws Exception {

    CertificateFactory cf = CertificateFactory.getInstance("X509");

    // Generate the CertPath from the certs named in certStrs
    ArrayList<X509Certificate> certs = new ArrayList<>();
    for (String certStr : certStrs) {
      certs.add(generateCert(certStr, cf));
    }
    CertPath cp = cf.generateCertPath(certs);

    // Generate the set of Trust Anchors from the certs named in
    // trustedCertStrs
    Set<TrustAnchor> trustAnchors = new HashSet<>();
    for (String trustedCertStr : trustedCertStrs) {
      TrustAnchor ta = new TrustAnchor(generateCert(trustedCertStr, cf), null);
      trustAnchors.add(ta);
    }
    PKIXParameters params = new PKIXParameters(trustAnchors);
    params.setDate(new Date(114, 3, 1)); // 2014-03-01
    params.setRevocationEnabled(false);

    // Attempt to validate the CertPath. If no exception thrown, successful.
    CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
    cpv.validate(cp, params);
    System.out.println("CertPath validation successful.");
  }
Ejemplo n.º 2
0
  private void checkPolicyProcessingAtDomainMatch() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    X509Certificate root =
        (X509Certificate)
            cf.generateCertificate(this.getClass().getResourceAsStream("qvRooCa3.crt"));
    X509Certificate ca1 =
        (X509Certificate)
            cf.generateCertificate(this.getClass().getResourceAsStream("suvaRoot1.crt"));
    X509Certificate ca2 =
        (X509Certificate)
            cf.generateCertificate(this.getClass().getResourceAsStream("suvaEmail1.crt"));
    X509Certificate ee =
        (X509Certificate) cf.generateCertificate(this.getClass().getResourceAsStream("suvaEE.crt"));

    List certchain = new ArrayList();
    certchain.add(ee);
    certchain.add(ca2);
    certchain.add(ca1);

    Set trust = new HashSet();
    trust.add(new TrustAnchor(root, null));

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
    PKIXParameters param = new PKIXParameters(trust);
    param.setRevocationEnabled(false);
    param.setDate(new Date(0x156445410b4L)); // around 1st August 2016

    CertPath cp = cf.generateCertPath(certchain);

    MyChecker checker = new MyChecker();
    param.addCertPathChecker(checker);

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, param);
  }
Ejemplo n.º 3
0
 private Subject createSubject() throws IOException {
   try {
     Certificate[] chain = engine.getSession().getPeerCertificates();
     CertPath certPath = cf.generateCertPath(asList(chain));
     return new Subject(false, Collections.<Principal>emptySet(), singleton(certPath), emptySet());
   } catch (SSLPeerUnverifiedException e) {
     throw new IOException("Failed to establish identity of SSL peer: " + e.getMessage(), e);
   } catch (CertificateException e) {
     throw new IOException("Certificate failure: " + e.getMessage(), e);
   }
 }
Ejemplo n.º 4
0
  private void testExceptions() throws Exception {
    byte[] enc = {(byte) 0, (byte) 2, (byte) 3, (byte) 4, (byte) 5};
    MyCertPath mc = new MyCertPath(enc);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    ByteArrayInputStream is;
    byte[] arr;

    ObjectOutputStream oOut = new ObjectOutputStream(os);
    oOut.writeObject(mc);
    oOut.flush();
    oOut.close();

    try {
      CertificateFactory cFac = CertificateFactory.getInstance("X.509", "BC");
      arr = os.toByteArray();
      is = new ByteArrayInputStream(arr);
      cFac.generateCertPath(is);
    } catch (CertificateException e) {
      // ignore okay
    }

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    List certCol = new ArrayList();

    certCol.add(cf.generateCertificate(new ByteArrayInputStream(certA)));
    certCol.add(cf.generateCertificate(new ByteArrayInputStream(certB)));
    certCol.add(cf.generateCertificate(new ByteArrayInputStream(certC)));
    certCol.add(cf.generateCertificate(new ByteArrayInputStream(certD)));

    CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX", "BC");
    X509CertSelector select = new X509CertSelector();
    select.setSubject(((X509Certificate) certCol.get(0)).getSubjectX500Principal().getEncoded());

    Set trustanchors = new HashSet();
    trustanchors.add(
        new TrustAnchor(
            (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(rootCertBin)), null));

    CertStore certStore =
        CertStore.getInstance("Collection", new CollectionCertStoreParameters(certCol));

    PKIXBuilderParameters params = new PKIXBuilderParameters(trustanchors, select);
    params.addCertStore(certStore);

    try {
      CertPathBuilderResult result = pathBuilder.build(params);
      CertPath path = result.getCertPath();
      fail("found cert path in circular set");
    } catch (CertPathBuilderException e) {
      // expected
    }
  }
Ejemplo n.º 5
0
  private PKIXCertPathBuilderResult buildCertPath(
      boolean searchAllCertStores, List<List<Vertex>> adjList) throws CertPathBuilderException {
    // Init shared variables and build certification path
    pathCompleted = false;
    trustAnchor = null;
    finalPublicKey = null;
    policyTreeResult = null;
    LinkedList<X509Certificate> certPathList = new LinkedList<>();
    try {
      buildForward(adjList, certPathList, searchAllCertStores);
    } catch (GeneralSecurityException | IOException e) {
      if (debug != null) {
        debug.println("SunCertPathBuilder.engineBuild() exception in " + "build");
        e.printStackTrace();
      }
      throw new SunCertPathBuilderException(
          "unable to find valid " + "certification path to requested target",
          e,
          new AdjacencyList(adjList));
    }

    // construct SunCertPathBuilderResult
    try {
      if (pathCompleted) {
        if (debug != null) debug.println("SunCertPathBuilder.engineBuild() " + "pathCompleted");

        // we must return a certpath which has the target
        // as the first cert in the certpath - i.e. reverse
        // the certPathList
        Collections.reverse(certPathList);

        return new SunCertPathBuilderResult(
            cf.generateCertPath(certPathList),
            trustAnchor,
            policyTreeResult,
            finalPublicKey,
            new AdjacencyList(adjList));
      }
    } catch (CertificateException e) {
      if (debug != null) {
        debug.println("SunCertPathBuilder.engineBuild() exception " + "in wrap-up");
        e.printStackTrace();
      }
      throw new SunCertPathBuilderException(
          "unable to find valid " + "certification path to requested target",
          e,
          new AdjacencyList(adjList));
    }

    return null;
  }
Ejemplo n.º 6
0
  private X509Certificate[] doValidate(X509Certificate[] chain, PKIXBuilderParameters params)
      throws CertificateException {
    try {
      setDate(params);

      // do the validation
      CertPathValidator validator = CertPathValidator.getInstance("PKIX");
      CertPath path = factory.generateCertPath(Arrays.asList(chain));
      certPathLength = chain.length;
      PKIXCertPathValidatorResult result =
          (PKIXCertPathValidatorResult) validator.validate(path, params);

      return toArray(path, result.getTrustAnchor());
    } catch (GeneralSecurityException e) {
      if (e instanceof CertPathValidatorException) {
        // check cause
        Throwable cause = e.getCause();
        if (cause != null && cause instanceof OCSPResponse.UnreliableException) {
          throw new ValidatorException(ValidatorException.T_OCSP_RESPONSE_UNRELIABLE);
        }
      }
      throw new ValidatorException("PKIX path validation failed: " + e.toString(), e);
    }
  }
Ejemplo n.º 7
0
  /** 读取指定路径下APK文件签名 */
  @SuppressWarnings({"unchecked"})
  public static String getJarSignature(String filePath) throws Exception {
    if (null == filePath) {
      return null;
    }
    String resultSign = "";
    String resultKey = "";
    List<ZipEntry> names = new ArrayList<ZipEntry>();
    ZipFile zf = new ZipFile(filePath);
    Enumeration<ZipEntry> zi = (Enumeration<ZipEntry>) zf.entries();
    while (zi.hasMoreElements()) {
      ZipEntry ze = zi.nextElement();
      String name = ze.getName();
      if (name.startsWith("META-INF/") && (name.endsWith(".RSA") || name.endsWith(".DSA"))) {
        names.add(ze);
      }
    }
    Collections.sort(
        names,
        new Comparator<ZipEntry>() {
          @Override
          public int compare(ZipEntry obj1, ZipEntry obj2) {
            if (obj1 != null && obj2 != null) {
              return obj1.getName().compareToIgnoreCase(obj2.getName());
            }
            return 0;
          }
        });
    for (ZipEntry ze : names) {
      InputStream is = zf.getInputStream(ze);
      try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        CertPath cp = cf.generateCertPath(is, "PKCS7");
        List<?> list = cp.getCertificates();
        for (Object obj : list) {
          if (!(obj instanceof X509Certificate)) continue;
          X509Certificate cert = (X509Certificate) obj;
          StringBuilder builder = new StringBuilder();
          builder.setLength(0);
          byte[] key = getPKBytes(cert.getPublicKey());
          for (byte aKey : key) {
            builder.append(String.format("%02X", aKey));
          }
          resultKey += builder.toString();
          builder.setLength(0);
          byte[] signature = cert.getSignature();

          for (byte aSignature : signature) {
            builder.append(String.format("%02X", aSignature));
          }
          resultSign += builder.toString();
        }
      } catch (CertificateException e) {
        Logger.i(e.toString());
      }
      is.close();
    }
    if (!TextUtils.isEmpty(resultKey) && !TextUtils.isEmpty(resultSign)) {
      return hashCode(resultKey) + "," + hashCode(resultSign);
    }
    return null;
  }
Ejemplo n.º 8
0
  /**
   * Este método realiza a validação da cadeia de certificados. Caso checkCRL esteja true, então é
   * feita a validação de revogação dos certificados em relação as suas CRLs. Todos os certificados
   * da cadeia são verifificados, não apenas o certificados apresentado, mas também os das ACs
   * intermediárias. Caso a cadeia de certificados esteja válida, então validateChain retorna void.
   * Caso contrário uma exceção é lançada.
   *
   * @throws ChainValidationException indica que houve um problema na validação da cadeia.
   */
  public void validateChain(Date dtSigned) throws ChainValidationException {
    try {
      final CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
      // CertificateFactory cf = CertificateFactory.getInstance( "X.509");
      final CertPath cp = cf.generateCertPath(this.certChain);

      final PKIXParameters params = new PKIXParameters(trustedAnchors);

      params.setExplicitPolicyRequired(false); // Nao obrigatorio, pois
      // false e o default
      params.setRevocationEnabled(this.checkCRL);
      // params.setRevocationEnabled(false);

      if (this.checkCRL) {
        if (crls == null) crls = getCRLs(certChain.toArray(new X509Certificate[certChain.size()]));
        final Collection col = new ArrayList();
        col.addAll(this.crls);
        for (X509Certificate cert : this.certificates) col.add(cert);
        final CollectionCertStoreParameters csParams = new CollectionCertStoreParameters(col);
        final CertStore cs = CertStore.getInstance("Collection", csParams);
        final List certStores = new Vector();
        certStores.add(cs);
        params.setCertStores(certStores);
      }

      params.setTrustAnchors(this.trustedAnchors);
      params.setDate(dtSigned);

      final CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
      // CertPathValidator cpv = CertPathValidator.getInstance("PKIX");

      PKIXCertPathValidatorResult result = null;

      // Estamos com o seguinte problema: Quando utilizamos as rotinas da
      // SUN, funciona, mas seria necessário possuir todas as CRLs,
      // inclusive as mais antiga, pois quando informamos a data, ele
      // exclui CRLs que nao estão válidas nessa data.

      result = (PKIXCertPathValidatorResult) cpv.validate(cp, params);
    } catch (final CertificateException e) {
      throw new ChainValidationException(
          "Falha na criação do caminho dos certificados (CertPath)!"
              + " Verifique se a cadeia de certificados existente é uma válida!\n",
          e);
    } catch (final InvalidAlgorithmParameterException e) {
      throw new ChainValidationException(
          "Falha na leitura dos certificados raizes (TrustedAnchor)! "
              + "Verifique se os certificados raizes passados são válidos!\n",
          e);
    } catch (final NoSuchAlgorithmException e) {
      throw new ChainValidationException(
          "Falha na criação do CertStore! Os parâmetros passados"
              + " para a criação do CertStore podem estar com problemas!\n",
          e);
    } catch (final NoSuchProviderException e) {
      throw new ChainValidationException(
          "O provedor criptográfico especificado não está disponível!\n", e);
    } catch (final CertPathValidatorException e) {
      // for (X509CRLObject x : (Collection<X509CRLObject>) this.crls)
      // System.out.println(x.getIssuerDN() + " - " + x.getThisUpdate()
      // + " - " + x.getNextUpdate());
      //
      throw new ChainValidationException(
          "Não foi possível validar a cadeia de certificados!\n Caso as CRLs"
              + " tenham sido verificadas é possível que algum certificado da cadeia esteja revogado!\n"
              + e);
    }
  }
Ejemplo n.º 9
0
  /**
   * Vérification chaine de certificats.
   *
   * @param password
   * @param anchors
   * @param certs
   * @param crls
   * @throws CertPathValidatorException si le chemin de certification n'est pas valide
   * @throws KeyStoreException
   * @throws NoSuchAlgorithmException
   * @throws CertificateException
   * @throws IOException
   * @throws InvalidAlgorithmParameterException
   * @throws CertPathBuilderException
   * @throws NoSuchProviderException
   */
  protected static void checkTrusted(
      X509Certificate[] anchors,
      Certificate[] certs,
      Collection<?> crls,
      String provider,
      boolean isCheckCrl)
      throws CertPathValidatorException, NoSuchAlgorithmException, CertificateException,
          InvalidAlgorithmParameterException, NoSuchProviderException {

    /* Construct a valid path. */
    List<TrustAnchor> listAnchors = new ArrayList<TrustAnchor>();

    for (X509Certificate cert : anchors) {
      TrustAnchor ta = new TrustAnchor(cert, null);
      listAnchors.add(ta);
    }

    Set anchorSet = new HashSet(listAnchors);
    List<X509Certificate> lstChaine = new ArrayList<X509Certificate>();
    for (Certificate cc0 : certs) {
      lstChaine.add((X509Certificate) cc0);
    }
    CollectionCertStoreParameters params = new CollectionCertStoreParameters(lstChaine);
    CertStore store = CertStore.getInstance("Collection", params, provider);

    CertStore crlStore = null;
    if (isCheckCrl) {
      CollectionCertStoreParameters revoked = new CollectionCertStoreParameters(crls);
      crlStore = CertStore.getInstance("Collection", revoked, provider);
    }

    // create certificate path
    CertificateFactory factory = CertificateFactory.getInstance("X.509", provider);
    List certChain = new ArrayList();

    certChain.add(lstChaine.get(0));
    // certChain.add(interCert);

    CertPath certPath = factory.generateCertPath(certChain);
    Set trust = anchorSet; // Collections.singleton(new TrustAnchor(rootCert,
    // null));
    // perform validation
    CertPathValidator validator = CertPathValidator.getInstance("PKIX", provider);
    PKIXParameters param = new PKIXParameters(trust);

    param.addCertStore(store);
    param.setDate(new Date());

    if (isCheckCrl) {
      param.addCertStore(crlStore);
      param.setRevocationEnabled(true);
    } else {
      param.setRevocationEnabled(false);
    }

    // CertPathValidatorResult result = validator.validate(certPath, param);
    validator.validate(certPath, param);
    if (log.isInfoEnabled()) {
      log.info("certificate path validated");
    }
  }
Ejemplo n.º 10
0
  public void performTest() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    X509Certificate rootCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(rootCertBin));
    X509Certificate interCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(interCertBin));
    X509Certificate finalCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(finalCertBin));

    // Testing CertPath generation from List
    List list = new ArrayList();
    list.add(interCert);
    CertPath certPath1 = cf.generateCertPath(list);

    // Testing CertPath encoding as PkiPath
    byte[] encoded = certPath1.getEncoded("PkiPath");

    // Testing CertPath generation from InputStream
    ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
    CertPath certPath2 = cf.generateCertPath(inStream, "PkiPath");

    // Comparing both CertPathes
    if (!certPath2.equals(certPath1)) {
      fail("CertPath differ after encoding and decoding.");
    }

    encoded = certPath1.getEncoded("PKCS7");

    // Testing CertPath generation from InputStream
    inStream = new ByteArrayInputStream(encoded);
    certPath2 = cf.generateCertPath(inStream, "PKCS7");

    // Comparing both CertPathes
    if (!certPath2.equals(certPath1)) {
      fail("CertPath differ after encoding and decoding.");
    }

    encoded = certPath1.getEncoded("PEM");

    // Testing CertPath generation from InputStream
    inStream = new ByteArrayInputStream(encoded);
    certPath2 = cf.generateCertPath(inStream, "PEM");

    // Comparing both CertPathes
    if (!certPath2.equals(certPath1)) {
      fail("CertPath differ after encoding and decoding.");
    }

    //
    // empty list test
    //
    list = new ArrayList();

    CertPath certPath = CertificateFactory.getInstance("X.509", "BC").generateCertPath(list);
    if (certPath.getCertificates().size() != 0) {
      fail("list wrong size.");
    }

    //
    // exception tests
    //
    testExceptions();
  }
Ejemplo n.º 11
0
  /**
   * Uses the provided PKI method to find the corresponding public key and verify the provided
   * signature.
   *
   * @param paymentRequest Payment request to verify.
   * @param trustStore KeyStore of trusted root certificate authorities.
   * @return verification data, or null if no PKI method was specified in the {@link
   *     Protos.PaymentRequest}.
   * @throws PaymentProtocolException if payment request could not be verified.
   */
  @Nullable
  public static PkiVerificationData verifyPaymentRequestPki(
      Protos.PaymentRequest paymentRequest, KeyStore trustStore) throws PaymentProtocolException {
    List<X509Certificate> certs = null;
    try {
      final String pkiType = paymentRequest.getPkiType();
      if ("none".equals(pkiType))
        // Nothing to verify. Everything is fine. Move along.
        return null;

      String algorithm;
      if ("x509+sha256".equals(pkiType)) algorithm = "SHA256withRSA";
      else if ("x509+sha1".equals(pkiType)) algorithm = "SHA1withRSA";
      else throw new PaymentProtocolException.InvalidPkiType("Unsupported PKI type: " + pkiType);

      Protos.X509Certificates protoCerts =
          Protos.X509Certificates.parseFrom(paymentRequest.getPkiData());
      if (protoCerts.getCertificateCount() == 0)
        throw new PaymentProtocolException.InvalidPkiData(
            "No certificates provided in message: server config error");

      // Parse the certs and turn into a certificate chain object. Cert factories can parse both DER
      // and base64.
      // The ordering of certificates is defined by the payment protocol spec to be the same as what
      // the Java
      // crypto API requires - convenient!
      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
      certs = Lists.newArrayList();
      for (ByteString bytes : protoCerts.getCertificateList())
        certs.add((X509Certificate) certificateFactory.generateCertificate(bytes.newInput()));
      CertPath path = certificateFactory.generateCertPath(certs);

      // Retrieves the most-trusted CAs from keystore.
      PKIXParameters params = new PKIXParameters(trustStore);
      // Revocation not supported in the current version.
      params.setRevocationEnabled(false);

      // Now verify the certificate chain is correct and trusted. This let's us get an identity
      // linked pubkey.
      CertPathValidator validator = CertPathValidator.getInstance("PKIX");
      PKIXCertPathValidatorResult result =
          (PKIXCertPathValidatorResult) validator.validate(path, params);
      PublicKey publicKey = result.getPublicKey();
      // OK, we got an identity, now check it was used to sign this message.
      Signature signature = Signature.getInstance(algorithm);
      // Note that we don't use signature.initVerify(certs.get(0)) here despite it being the most
      // obvious
      // way to set it up, because we don't care about the constraints specified on the
      // certificates: any
      // cert that links a key to a domain name or other identity will do for us.
      signature.initVerify(publicKey);
      Protos.PaymentRequest.Builder reqToCheck = paymentRequest.toBuilder();
      reqToCheck.setSignature(ByteString.EMPTY);
      signature.update(reqToCheck.build().toByteArray());
      if (!signature.verify(paymentRequest.getSignature().toByteArray()))
        throw new PaymentProtocolException.PkiVerificationException(
            "Invalid signature, this payment request is not valid.");

      // Signature verifies, get the names from the identity we just verified for presentation to
      // the user.
      final X509Certificate cert = certs.get(0);
      String displayName = X509Utils.getDisplayNameFromCertificate(cert, true);
      if (displayName == null)
        throw new PaymentProtocolException.PkiVerificationException(
            "Could not extract name from certificate");
      // Everything is peachy. Return some useful data to the caller.
      return new PkiVerificationData(displayName, publicKey, result.getTrustAnchor());
    } catch (InvalidProtocolBufferException e) {
      // Data structures are malformed.
      throw new PaymentProtocolException.InvalidPkiData(e);
    } catch (CertificateException e) {
      // The X.509 certificate data didn't parse correctly.
      throw new PaymentProtocolException.PkiVerificationException(e);
    } catch (NoSuchAlgorithmException e) {
      // Should never happen so don't make users have to think about it. PKIX is always present.
      throw new RuntimeException(e);
    } catch (InvalidAlgorithmParameterException e) {
      throw new RuntimeException(e);
    } catch (CertPathValidatorException e) {
      // The certificate chain isn't known or trusted, probably, the server is using an SSL root we
      // don't
      // know about and the user needs to upgrade to a new version of the software (or import a root
      // cert).
      throw new PaymentProtocolException.PkiVerificationException(e, certs);
    } catch (InvalidKeyException e) {
      // Shouldn't happen if the certs verified correctly.
      throw new PaymentProtocolException.PkiVerificationException(e);
    } catch (SignatureException e) {
      // Something went wrong during hashing (yes, despite the name, this does not mean the sig was
      // invalid).
      throw new PaymentProtocolException.PkiVerificationException(e);
    } catch (KeyStoreException e) {
      throw new RuntimeException(e);
    }
  }
Ejemplo n.º 12
0
  /**
   * Uses the provided PKI method to find the corresponding public key and verify the provided
   * signature. Returns null if no PKI method was specified in the {@link Protos.PaymentRequest}.
   */
  public @Nullable PkiVerificationData verifyPki() throws PaymentRequestException {
    try {
      if (pkiVerificationData != null) return pkiVerificationData;
      if (paymentRequest.getPkiType().equals("none"))
        // Nothing to verify. Everything is fine. Move along.
        return null;

      String algorithm;
      if (paymentRequest.getPkiType().equals("x509+sha256")) algorithm = "SHA256withRSA";
      else if (paymentRequest.getPkiType().equals("x509+sha1")) algorithm = "SHA1withRSA";
      else
        throw new PaymentRequestException.InvalidPkiType(
            "Unsupported PKI type: " + paymentRequest.getPkiType());

      Protos.X509Certificates protoCerts =
          Protos.X509Certificates.parseFrom(paymentRequest.getPkiData());
      if (protoCerts.getCertificateCount() == 0)
        throw new PaymentRequestException.InvalidPkiData(
            "No certificates provided in message: server config error");

      // Parse the certs and turn into a certificate chain object. Cert factories can parse both DER
      // and base64.
      // The ordering of certificates is defined by the payment protocol spec to be the same as what
      // the Java
      // crypto API requires - convenient!
      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
      List<X509Certificate> certs = Lists.newArrayList();
      for (ByteString bytes : protoCerts.getCertificateList())
        certs.add((X509Certificate) certificateFactory.generateCertificate(bytes.newInput()));
      CertPath path = certificateFactory.generateCertPath(certs);

      // Retrieves the most-trusted CAs from keystore.
      PKIXParameters params = new PKIXParameters(createKeyStore(trustStorePath));
      // Revocation not supported in the current version.
      params.setRevocationEnabled(false);

      // Now verify the certificate chain is correct and trusted. This let's us get an identity
      // linked pubkey.
      CertPathValidator validator = CertPathValidator.getInstance("PKIX");
      PKIXCertPathValidatorResult result =
          (PKIXCertPathValidatorResult) validator.validate(path, params);
      PublicKey publicKey = result.getPublicKey();
      // OK, we got an identity, now check it was used to sign this message.
      Signature signature = Signature.getInstance(algorithm);
      // Note that we don't use signature.initVerify(certs.get(0)) here despite it being the most
      // obvious
      // way to set it up, because we don't care about the constraints specified on the
      // certificates: any
      // cert that links a key to a domain name or other identity will do for us.
      signature.initVerify(publicKey);
      Protos.PaymentRequest.Builder reqToCheck = paymentRequest.toBuilder();
      reqToCheck.setSignature(ByteString.EMPTY);
      signature.update(reqToCheck.build().toByteArray());
      if (!signature.verify(paymentRequest.getSignature().toByteArray()))
        throw new PaymentRequestException.PkiVerificationException(
            "Invalid signature, this payment request is not valid.");

      // Signature verifies, get the names from the identity we just verified for presentation to
      // the user.
      X500Principal principal = certs.get(0).getSubjectX500Principal();
      // At this point the Java crypto API falls flat on its face and dies - there's no clean way to
      // get the
      // different parts of the certificate name except for parsing the string. That's hard because
      // of various
      // custom escaping rules and the usual crap. So, use Bouncy Castle to re-parse the string into
      // binary form
      // again and then look for the names we want. Fail!
      org.spongycastle.asn1.x500.X500Name name = new X500Name(principal.getName());
      String entityName = null, orgName = null;
      for (RDN rdn : name.getRDNs()) {
        AttributeTypeAndValue pair = rdn.getFirst();
        if (pair.getType().equals(RFC4519Style.cn))
          entityName = ((ASN1String) pair.getValue()).getString();
        else if (pair.getType().equals(RFC4519Style.o))
          orgName = ((ASN1String) pair.getValue()).getString();
      }
      if (entityName == null && orgName == null)
        throw new PaymentRequestException.PkiVerificationException(
            "Invalid certificate, no CN or O fields");
      // Everything is peachy. Return some useful data to the caller.
      PkiVerificationData data =
          new PkiVerificationData(entityName, orgName, publicKey, result.getTrustAnchor());
      // Cache the result so we don't have to re-verify if this method is called again.
      pkiVerificationData = data;
      return data;
    } catch (InvalidProtocolBufferException e) {
      // Data structures are malformed.
      throw new PaymentRequestException.InvalidPkiData(e);
    } catch (CertificateException e) {
      // The X.509 certificate data didn't parse correctly.
      throw new PaymentRequestException.PkiVerificationException(e);
    } catch (NoSuchAlgorithmException e) {
      // Should never happen so don't make users have to think about it. PKIX is always present.
      throw new RuntimeException(e);
    } catch (InvalidAlgorithmParameterException e) {
      throw new RuntimeException(e);
    } catch (CertPathValidatorException e) {
      // The certificate chain isn't known or trusted, probably, the server is using an SSL root we
      // don't
      // know about and the user needs to upgrade to a new version of the software (or import a root
      // cert).
      throw new PaymentRequestException.PkiVerificationException(e);
    } catch (InvalidKeyException e) {
      // Shouldn't happen if the certs verified correctly.
      throw new PaymentRequestException.PkiVerificationException(e);
    } catch (SignatureException e) {
      // Something went wrong during hashing (yes, despite the name, this does not mean the sig was
      // invalid).
      throw new PaymentRequestException.PkiVerificationException(e);
    } catch (IOException e) {
      throw new PaymentRequestException.PkiVerificationException(e);
    } catch (KeyStoreException e) {
      throw new RuntimeException(e);
    }
  }
Ejemplo n.º 13
0
  /*
   * 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);
      }
    }
  }
Ejemplo n.º 14
0
  // FIXME: This is super naive, fix it.
  public static CertPath getCertPath(X509Certificate[] certs) throws CertificateException {

    CertificateFactory factory = CertificateFactory.getInstance("X.509");
    return factory.generateCertPath(Arrays.asList(certs));
  }