Details
-
Bug
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
2.1.6
-
None
Description
crypto.verifyTrust can fail when the DN of the issuer is more than once in the truststore
lets assume the following situation of 2 totally separated PKI,
- PKI 1
ROOT CA A <- INTERMEDIATE CA A <- END CERT A
- PKI 2
ROOT CA B <- INTERMEDIATE CA B <- END CERT B
- Subject Distinguished Name of INTERMEDIATE CA A happens to be equal to Subject Distinguished Name of INTERMEDIATE CA B
- truststore contains CA's of the 2 PKI: it contains ROOT CA A, ROOT CA B, INTERMEDIATE CA A & INTERMEDIATE CA B
-> the CertPath object constructed in verifyTrust method in the org.apache.wss4j.common.crypto.Merlin class can contain the intermediate of PKI2 even
if the end certificate is cryptograhically signed by intermediate of PKI 1, hence the PKIX CertPathValidator fails
this is because there is only a string comparison when determining the issuer of a certificate before putting it to the CertPath object, i think there should be a signature verification too before putting the issuer on the CertPath object
reproducer (java 8 / wss4j-ws-security-common-2.1.6 )
import java.security.cert.X509Certificate; import java.security.cert.CertificateFactory; import java.io.ByteArrayInputStream; import java.util.Properties; import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.crypto.CryptoFactory; import java.util.Base64; public class Validate { public static void main(String[] args) { try { //end cert A byte [] decoded = Base64.getDecoder().decode("MIIC+DCCAeCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDEw9JTlRFUk1FRElBVEUgQ0EwHhcNMTYwNzE2MTYwMjAwWhcNMjYwNzE2MTUwNDAwWjBGMUQwQgYDVQQDEztFTkQgQ0VSVCBTSUdORUQgQlkgSU5URVJNRURJQVRFIFRIQVQgSVMgU0lHTkVEIEJZIFJPT1QgQ0EgQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANokxXPsi4KargS5z/IqtYTvNqpcWwEUjwAMuCwgymQsZDqBU8N9oUS4aLqZErZ9T8vUrNFuHEdqKDo9iH5gY3JOirlhFD05wxBxsHF9lUcCI/hXT3VBfEIW6xGnkhCJxV/ye5Yq7uM1UWFhVAxWgNlZnOsP/uMU1EUmhwqFEYum/JfWbLQZCb3G7Oraxatq2NNIk+Huvca9cEgqNXYdiBaaPyU390iML1PN9rKTGlLaWoCLj9VyuaIsOrsD+MF6MJx16p6O4G7P7lx8fZkxbk0y5keF0WNEyBnZ9+YiVOY8EPLQVB/GySBLK0n9Z4RV2RNIL+rAuw61gn05+gpXrLsCAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBAFJyt2LMeO7QEjZI82N5VcMTVSlKDee0E2pzHeMPOip80wD+/Xx+PKkTyRiuSHwwK6yz/URf6P1ucHbUMIwcXTKiCY5/2imJlzC8CXoLNnwfduBP3MzyBz1L6ecV6fXJkwWzBjhaPZmZ2cISmkiNIK0vobT6PZ/ikmtCk2zyU6XFNTHssSGmZrBS6Muk+O0iT+v1DU6A7T2122cIEu5GEaR3cidcRi0c4Y4yZ8+vP8JqrQZmHe35FyHKvu/+z9/GYCQsbOT5x5ybhB3jtE60qIzYDNaOfmoxKW3b4JUpGpE5fzAz+9jwbtixjZGh2KPU/KsXBv0bIeM8qo7/aV23XbM="); //end cert B //byte [] decoded = Base64.getDecoder().decode("MIIC+DCCAeCgAwIBAgIBAzANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9JTlRFUk1FRElBVEUgQ0EwHhcNMTYwNzE2MTUyMDAwWhcNMjYwNzE2MTUwNzAwWjBGMUQwQgYDVQQDEztFTkQgQ0VSVCBTSUdORUQgQlkgSU5URVJNRURJQVRFIFRIQVQgSVMgU0lHTkVEIEJZIFJPT1QgQ0EgQjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN4Z8W4mmFoKWpCK4u427dE/mogExnerWufa1gvUfeQqUiZfln8VzUZmJMFsQy3y2Ze6T3Hj2ao1AuKUT2ouZS5MLSeKrN+UOEoqkYeb/vSNZQETJGEPhqvuEeHPbrpUqK90ioqhVRq+YDeesYO5f9LGcjSOin16aMx7voeJh+DQ1/3EpcydQs13aaC9mwpFJfqRKQzMnVAYkowO9gT8EoM57FVz8LWimXjnHZuZaRIriUA8jxSsA2AUa2M/4Nuza1idbrAwhWZO7J4IVkp0PzSucx71ebiSwE8kDPOy86SEURDnSEtOcvpiOVbGCaAc+4vNH/OVjcSluDBUDIwBmScCAwEAAaMdMBswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggEBAEyjZ55G4YbZR6P7QhbsQN4OrNLEJZYC822FmXVQjM540izo5sLtx2D8sR6JweGDnEtOFKgWrdwkILRrNWaZ+qws4mHYOhCcOgy/XQ1OLOHgetNu6TWvbLr6sjBGEkGABGJ6NPhpv+Z9N8qtHL9u/9e/HVkVK3e4sMtejic1t9LVlJ8mkHGBJ5qu/3jIzcuHncyXX9G/Pqsw/jkIWXSRgZQEyORpxE7J4VvFwr+D5A72bozLxgpIqSOE+xsUFXvTL89p4jlCrGeqQj/TLAKapltLcwNWljVGp4Qlk1aOM5FDIQV+eUd9y/zWcHusx1NqxI6qx9V6NjQRpvTDezZyyVg="); X509Certificate[] certs = new X509Certificate[1]; certs[0]= (X509Certificate)CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(decoded)); Properties p = new Properties(); p.setProperty("org.apache.ws.security.crypto.merlin.truststore.file", "truststore.jks"); p.setProperty("org.apache.ws.security.crypto.merlin.truststore.type", "jks"); p.setProperty("org.apache.ws.security.crypto.merlin.truststore.password", "wss4j"); Crypto crypto = CryptoFactory.getInstance(p); crypto.verifyTrust(certs, false,null); } catch (Exception e) { e.printStackTrace(); } } }
output of java -Dorg.slf4j.simpleLogger.defaultLogLevel=trace -Djava.security.debug=certpath Validate
[main] DEBUG org.apache.wss4j.common.crypto.Merlin - The TrustStore truststore.jks of type jks has been loaded [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Searching keystore for cert with issuer CN=INTERMEDIATE CA and serial 4 [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Keystore alias root ca b has issuer CN=ROOT CA B and serial 1 [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Keystore alias root ca a has issuer CN=ROOT CA A and serial 1 [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Keystore alias intermediate ca signed by root ca b has issuer CN=ROOT CA B and serial 2 [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Keystore alias intermediate ca signed by root ca a has issuer CN=ROOT CA A and serial 2 [main] DEBUG org.apache.wss4j.common.crypto.Merlin - No issuer serial match found in keystore [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Searching keystore for cert with Subject CN=INTERMEDIATE CA [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Subject certificate match found using keystore alias intermediate ca signed by root ca b [main] DEBUG org.apache.wss4j.common.crypto.Merlin - Preparing to validate certificate path for issuer CN=INTERMEDIATE CA certpath: PKIXCertPathValidator.engineValidate()... certpath: X509CertSelector.match(SN: 2 Issuer: CN=ROOT CA A Subject: CN=INTERMEDIATE CA) certpath: X509CertSelector.match: subject DNs don't match certpath: NO - don't try this trustedCert certpath: X509CertSelector.match(SN: 1 Issuer: CN=ROOT CA B Subject: CN=ROOT CA B) certpath: X509CertSelector.match returning: true certpath: YES - try this trustedCert certpath: anchor.getTrustedCert().getSubjectX500Principal() = CN=ROOT CA B certpath: -------------------------------------------------------------- certpath: Executing PKIX certification path validation algorithm. certpath: Checking cert1 - Subject: CN=INTERMEDIATE CA certpath: Set of critical extensions: {2.5.29.19} certpath: -Using checker1 ... [sun.security.provider.certpath.UntrustedChecker] certpath: -checker1 validation succeeded certpath: -Using checker2 ... [sun.security.provider.certpath.AlgorithmChecker] certpath: -checker2 validation succeeded certpath: -Using checker3 ... [sun.security.provider.certpath.KeyChecker] certpath: KeyChecker.verifyCAKeyUsage() ---checking CA key usage... certpath: KeyChecker.verifyCAKeyUsage() CA key usage verified. certpath: -checker3 validation succeeded certpath: -Using checker4 ... [sun.security.provider.certpath.ConstraintsChecker] certpath: ---checking basic constraints... certpath: i = 1, maxPathLength = 2 certpath: after processing, maxPathLength = 1 certpath: basic constraints verified. certpath: ---checking name constraints... certpath: prevNC = null, newNC = null certpath: mergedNC = null certpath: name constraints verified. certpath: -checker4 validation succeeded certpath: -Using checker5 ... [sun.security.provider.certpath.PolicyChecker] certpath: PolicyChecker.checkPolicy() ---checking certificate policies... certpath: PolicyChecker.checkPolicy() certIndex = 1 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: explicitPolicy = 3 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: policyMapping = 3 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: inhibitAnyPolicy = 3 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: policyTree = anyPolicy ROOT certpath: PolicyChecker.processPolicies() no policies present in cert certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: explicitPolicy = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: policyMapping = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: inhibitAnyPolicy = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: policyTree = null certpath: PolicyChecker.checkPolicy() certificate policies verified certpath: -checker5 validation succeeded certpath: -Using checker6 ... [sun.security.provider.certpath.BasicChecker] certpath: ---checking timestamp:Sat Jul 16 19:02:50 CEST 2016... certpath: timestamp verified. certpath: ---checking subject/issuer name chaining... certpath: subject/issuer name chaining verified. certpath: ---checking signature... certpath: signature verified. certpath: BasicChecker.updateState issuer: CN=ROOT CA B; subject: CN=INTERMEDIATE CA; serial#: 2 certpath: -checker6 validation succeeded certpath: cert1 validation succeeded. certpath: Checking cert2 - Subject: CN=END CERT SIGNED BY INTERMEDIATE THAT IS SIGNED BY ROOT CA A certpath: Set of critical extensions: {2.5.29.19} certpath: -Using checker1 ... [sun.security.provider.certpath.UntrustedChecker] certpath: -checker1 validation succeeded certpath: -Using checker2 ... [sun.security.provider.certpath.AlgorithmChecker] certpath: -checker2 validation succeeded certpath: -Using checker3 ... [sun.security.provider.certpath.KeyChecker] certpath: -checker3 validation succeeded certpath: -Using checker4 ... [sun.security.provider.certpath.ConstraintsChecker] certpath: ---checking basic constraints... certpath: i = 2, maxPathLength = 1 certpath: after processing, maxPathLength = 1 certpath: basic constraints verified. certpath: ---checking name constraints... certpath: prevNC = null, newNC = null certpath: mergedNC = null certpath: name constraints verified. certpath: -checker4 validation succeeded certpath: -Using checker5 ... [sun.security.provider.certpath.PolicyChecker] certpath: PolicyChecker.checkPolicy() ---checking certificate policies... certpath: PolicyChecker.checkPolicy() certIndex = 2 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: explicitPolicy = 2 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: policyMapping = 2 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: inhibitAnyPolicy = 2 certpath: PolicyChecker.checkPolicy() BEFORE PROCESSING: policyTree = null certpath: PolicyChecker.processPolicies() no policies present in cert certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: explicitPolicy = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: policyMapping = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: inhibitAnyPolicy = 2 certpath: PolicyChecker.checkPolicy() AFTER PROCESSING: policyTree = null certpath: PolicyChecker.checkPolicy() certificate policies verified certpath: -checker5 validation succeeded certpath: -Using checker6 ... [sun.security.provider.certpath.BasicChecker] certpath: ---checking timestamp:Sat Jul 16 19:02:50 CEST 2016... certpath: timestamp verified. certpath: ---checking subject/issuer name chaining... certpath: subject/issuer name chaining verified. certpath: ---checking signature... certpath: X509CertSelector.match(SN: 1 Issuer: CN=ROOT CA A Subject: CN=ROOT CA A) certpath: X509CertSelector.match: subject DNs don't match certpath: NO - don't try this trustedCert certpath: X509CertSelector.match(SN: 2 Issuer: CN=ROOT CA B Subject: CN=INTERMEDIATE CA) certpath: X509CertSelector.match: subject DNs don't match certpath: NO - don't try this trustedCert org.apache.wss4j.common.ext.WSSecurityException: Error during certificate path validation: signature check failed Original Exception was java.security.cert.CertPathValidatorException: signature check failed at org.apache.wss4j.common.crypto.Merlin.verifyTrust(Merlin.java:895) at Validate.main(Validate.java:25) Caused by: java.security.cert.CertPathValidatorException: signature check failed at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:135) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:212) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140) at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79) at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292) at org.apache.wss4j.common.crypto.Merlin.verifyTrust(Merlin.java:890) ... 1 more Caused by: java.security.SignatureException: Signature does not match. at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:449) at sun.security.provider.certpath.BasicChecker.verifySignature(BasicChecker.java:166) at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:147) at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125) ... 6 more