Esempio n. 1
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);
  }
Esempio n. 2
0
  private void validateWithExtendedKeyUsage() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    X509Certificate rootCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(extTrust));
    X509Certificate interCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(extCA));
    X509Certificate finalCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(extEE));

    List list = new ArrayList();
    list.add(rootCert);
    list.add(interCert);
    list.add(finalCert);

    CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
    CertStore store = CertStore.getInstance("Collection", ccsp, "BC");
    Date validDate = new Date(rootCert.getNotBefore().getTime() + 60 * 60 * 1000);
    // validating path
    List certchain = new ArrayList();
    certchain.add(finalCert);
    certchain.add(interCert);
    CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain);
    Set trust = new HashSet();
    trust.add(new TrustAnchor(rootCert, null));

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
    PKIXParameters param = new PKIXParameters(trust);
    param.addCertStore(store);
    param.setDate(validDate);
    param.setRevocationEnabled(false);

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, param);
  }
Esempio n. 3
0
  public void testEmptyPath() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
    X509Certificate rootCert =
        (X509Certificate)
            cf.generateCertificate(new ByteArrayInputStream(CertPathTest.rootCertBin));

    List list = new ArrayList();
    list.add(rootCert);
    CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
    CertStore store = CertStore.getInstance("Collection", ccsp, "BC");

    List certchain = new ArrayList();
    CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain);
    Set trust = new HashSet();
    trust.add(new TrustAnchor(rootCert, null));

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
    PKIXParameters param = new PKIXParameters(trust);
    param.addCertStore(store);
    MyChecker checker = new MyChecker();
    param.addCertPathChecker(checker);

    try {
      cpv.validate(cp, param);
    } catch (CertPathValidatorException e) {
      if (!"Certification path is empty.".equals(e.getMessage())) {
        fail("message mismatch");
      }
    }
  }
Esempio n. 4
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.");
  }
Esempio n. 5
0
 /**
  * Handles server certificate validation. Flags for validity and certificate chain verification
  * decides this functions behavior.
  *
  * <p>Implements X509TrustManager.
  */
 public void checkServerTrusted(X509Certificate[] chain, String authType)
     throws CertificateException {
   try {
     Set<TrustAnchor> trust = new HashSet<TrustAnchor>();
     // All CAs must in an *installed* CA path be valid as trust
     // anchors
     Enumeration<String> aliases = trust_store.aliases();
     while (aliases.hasMoreElements()) {
       String alias = aliases.nextElement();
       if (trust_store.isCertificateEntry(alias)) {
         trust.add(new TrustAnchor((X509Certificate) trust_store.getCertificate(alias), null));
       }
     }
     CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
     PKIXParameters param = new PKIXParameters(trust);
     param.setDate(new Date());
     param.setRevocationEnabled(enable_revocation_test);
     List<X509Certificate> certchain = new ArrayList<X509Certificate>();
     for (X509Certificate cert : chain) {
       if (!cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal())) {
         certchain.add(cert);
       }
     }
     CertPath cp = CertificateFactory.getInstance("X.509").generateCertPath(certchain);
     cpv.validate(cp, param);
   } catch (GeneralSecurityException e) {
     if (!allow_invalidcert) {
       throw new CertificateException(e);
     }
   }
 }
Esempio n. 6
0
  private void checkCircProcessing() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    X509Certificate caCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(circCA));
    X509Certificate crlCaCert =
        (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(circCRLCA));
    X509CRL crl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(circCRL));

    List list = new ArrayList();

    list.add(caCert);
    list.add(crlCaCert);
    list.add(crl);

    CertStoreParameters ccsp = new CollectionCertStoreParameters(list);
    CertStore store = CertStore.getInstance("Collection", ccsp);

    Date validDate = new Date(crl.getThisUpdate().getTime() + 60 * 60 * 1000);

    // validating path
    List certchain = new ArrayList();

    certchain.add(crlCaCert);
    CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain);

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

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
    // PKIXParameters param = new PKIXParameters(trust);

    PKIXBuilderParameters param = new PKIXBuilderParameters(trust, null);
    X509CertSelector certSelector = new X509CertSelector();
    certSelector.setCertificate(crlCaCert);
    param.setTargetCertConstraints(certSelector);
    param.addCertStore(store);
    param.setRevocationEnabled(true);
    param.setDate(validDate);

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, param);
  }
 protected static CertPathValidatorResult processAttrCert2(
     CertPath certPath, ExtendedPKIXParameters pkixParams) throws CertPathValidatorException {
   CertPathValidator validator = null;
   try {
     validator = CertPathValidator.getInstance("PKIX", "BC");
   } catch (NoSuchProviderException e) {
     throw new ExtCertPathValidatorException("Support class could not be created.", e);
   } catch (NoSuchAlgorithmException e) {
     throw new ExtCertPathValidatorException("Support class could not be created.", e);
   }
   try {
     return validator.validate(certPath, pkixParams);
   } catch (CertPathValidatorException e) {
     throw new ExtCertPathValidatorException(
         "Certification path for issuer certificate of attribute certificate could not be validated.",
         e);
   } catch (InvalidAlgorithmParameterException e) {
     // must be a programming error
     throw new RuntimeException(e.getMessage());
   }
 }
Esempio n. 8
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);
    }
  }
Esempio n. 9
0
  public void performTest() throws Exception {
    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    // initialise CertStore
    X509Certificate rootCert =
        (X509Certificate)
            cf.generateCertificate(new ByteArrayInputStream(CertPathTest.rootCertBin));
    X509Certificate interCert =
        (X509Certificate)
            cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin));
    X509Certificate finalCert =
        (X509Certificate)
            cf.generateCertificate(new ByteArrayInputStream(CertPathTest.finalCertBin));
    X509CRL rootCrl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(CertPathTest.rootCrlBin));
    X509CRL interCrl = (X509CRL) cf.generateCRL(new ByteArrayInputStream(CertPathTest.interCrlBin));
    List list = new ArrayList();
    list.add(rootCert);
    list.add(interCert);
    list.add(finalCert);
    list.add(rootCrl);
    list.add(interCrl);
    CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
    CertStore store = CertStore.getInstance("Collection", ccsp, "BC");
    Date validDate = new Date(rootCrl.getThisUpdate().getTime() + 60 * 60 * 1000);
    // validating path
    List certchain = new ArrayList();
    certchain.add(finalCert);
    certchain.add(interCert);
    CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain);
    Set trust = new HashSet();
    trust.add(new TrustAnchor(rootCert, null));

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC");
    PKIXParameters param = new PKIXParameters(trust);
    param.addCertStore(store);
    param.setDate(validDate);
    MyChecker checker = new MyChecker();
    param.addCertPathChecker(checker);

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) cpv.validate(cp, param);
    PolicyNode policyTree = result.getPolicyTree();
    PublicKey subjectPublicKey = result.getPublicKey();

    if (checker.getCount() != 2) {
      fail("checker not evaluated for each certificate");
    }

    if (!subjectPublicKey.equals(finalCert.getPublicKey())) {
      fail("wrong public key returned");
    }

    //
    // invalid path containing a valid one test
    //
    try {
      // initialise CertStore
      rootCert =
          (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(AC_RAIZ_ICPBRASIL));
      interCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(AC_PR));
      finalCert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(schefer));

      list = new ArrayList();
      list.add(rootCert);
      list.add(interCert);
      list.add(finalCert);

      ccsp = new CollectionCertStoreParameters(list);
      store = CertStore.getInstance("Collection", ccsp);
      validDate = new Date(finalCert.getNotBefore().getTime() + 60 * 60 * 1000);

      // validating path
      certchain = new ArrayList();
      certchain.add(finalCert);
      certchain.add(interCert);
      cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain);
      trust = new HashSet();
      trust.add(new TrustAnchor(rootCert, null));

      cpv = CertPathValidator.getInstance("PKIX", "BC");
      param = new PKIXParameters(trust);
      param.addCertStore(store);
      param.setRevocationEnabled(false);
      param.setDate(validDate);

      result = (PKIXCertPathValidatorResult) cpv.validate(cp, param);
      policyTree = result.getPolicyTree();
      subjectPublicKey = result.getPublicKey();

      fail("Invalid path validated");
    } catch (Exception e) {
      if (!(e instanceof CertPathValidatorException
          && e.getMessage().startsWith("Could not validate certificate signature."))) {
        fail("unexpected exception", e);
      }
    }

    checkCircProcessing();
    checkPolicyProcessingAtDomainMatch();
    validateWithExtendedKeyUsage();
    testEmptyPath();
  }
  /**
   * 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);
    }
  }
Esempio n. 11
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");
    }
  }
Esempio n. 12
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);
    }
  }
Esempio n. 13
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);
    }
  }