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); }
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); }
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"); } } }
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."); }
/** * 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); } } }
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()); } }
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); } }
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); } }
/** * 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"); } }
/** * 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); } }
/** * 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); } }