diff --git a/common/src/main/java/org/keycloak/common/util/OCSPUtils.java b/common/src/main/java/org/keycloak/common/util/OCSPUtils.java index 6a6e00c404..d2e05b5dfe 100644 --- a/common/src/main/java/org/keycloak/common/util/OCSPUtils.java +++ b/common/src/main/java/org/keycloak/common/util/OCSPUtils.java @@ -396,7 +396,7 @@ public final class OCSPUtils { } try { List purposes = signingCert.getExtendedKeyUsage(); - if (purposes != null && !purposes.contains(KeyPurposeId.id_kp_OCSPSigning.getId())) { + if (purposes == null || !purposes.contains(KeyPurposeId.id_kp_OCSPSigning.getId())) { logger.log(Level.INFO, "OCSPSigning extended usage is not set"); throw new CertPathValidatorException("Responder\'s certificate not valid for signing OCSP responses"); } diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java index 900e4217df..7a7ed30e77 100644 --- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java @@ -54,10 +54,13 @@ import java.util.List; import java.util.Set; import java.util.LinkedList; import java.util.ArrayList; +import java.util.Map; import java.util.stream.Collectors; +import javax.security.auth.x500.X500Principal; import org.keycloak.saml.common.exceptions.ProcessingException; import org.keycloak.saml.processing.core.util.XMLSignatureUtil; +import org.keycloak.truststore.TruststoreProvider; /** * @author Peter Nalyvayko @@ -464,20 +467,48 @@ public class CertificateValidator { validateExtendedKeyUsage(_certChain, _extendedKeyUsage); return this; } + + private X509Certificate findCAInTruststore(X500Principal issuer) throws GeneralSecurityException { + TruststoreProvider truststoreProvider = session.getProvider(TruststoreProvider.class); + if (truststoreProvider == null || truststoreProvider.getTruststore() == null) { + return null; + } + Map rootCerts = truststoreProvider.getRootCertificates(); + X509Certificate ca = rootCerts.get(issuer); + if (ca != null) { + ca.checkValidity(); + } + return ca; + } + private void checkRevocationUsingOCSP(X509Certificate[] certs) throws GeneralSecurityException { - if (certs.length < 2) { - // OCSP requires a responder certificate to verify OCSP - // signed response. - String message = "OCSP requires a responder certificate. OCSP cannot be used to verify the revocation status of self-signed certificates."; - throw new GeneralSecurityException(message); + if (logger.isDebugEnabled() && certs != null) { + for (X509Certificate cert : certs) { + logger.debugf("Certificate: %s", cert.getSubjectDN().getName()); + } } - for (X509Certificate cert : certs) { - logger.debugf("Certificate: %s", cert.getSubjectDN().getName()); + X509Certificate cert = null; + X509Certificate issuer = null; + + if (certs == null || certs.length == 0) { + throw new GeneralSecurityException("No certificates sent"); + } else if (certs.length > 1) { + cert = certs[0]; + issuer = certs[1]; + } else { + // only one cert => find the CA certificate using the truststore SPI + cert = certs[0]; + issuer = findCAInTruststore(cert.getIssuerX500Principal()); + if (issuer == null) { + throw new GeneralSecurityException( + String.format("No trusted CA in certificate found: %s. Add it to truststore SPI if valid.", + cert.getIssuerX500Principal())); + } } - OCSPUtils.OCSPRevocationStatus rs = ocspChecker.check(certs[0], certs[1]); + OCSPUtils.OCSPRevocationStatus rs = ocspChecker.check(cert, issuer); if (rs == null) { throw new GeneralSecurityException("Unable to check client revocation status using OCSP"); diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/client-ca.jks b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/client-ca.jks new file mode 100644 index 0000000000..674cd57347 Binary files /dev/null and b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/client-ca.jks differ diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.csr b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.csr new file mode 100644 index 0000000000..925fa37533 --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.csr @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEzjCCArYCAQAwgYgxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNQTEPMA0GA1UE +BwwGQm9zdG9uMRAwDgYDVQQKDAdSZWQgSGF0MREwDwYDVQQLDAhLZXljbG9hazES +MBAGA1UEAwwJdGVzdC11c2VyMSIwIAYJKoZIhvcNAQkBFhN0ZXN0LXVzZXJAbG9j +YWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwxZN9ePdOvlI +x1xbtxYXov/9PoqFtuc9gk9jGuQrpjeIV6rVw9SKfRpPdTcPRyRLgLTu20G8qjHP +WnalUpdZf9g1FTgEuqWqyN+wf/+l2xai8tFLsjcRMHsZAbFrM9iU8StSlLdSn+f5 +4OVi798PtmMgH6fLcmK0vxP3Ux6sxxF6M8zq/0UyiYN1fkT6pQ91A3C8JM900xb6 +ST/zBIcu//e2cqfvvLrsuflYdZVdpNJlasGcBjx7/qJwkpvZJmXXYf3eNu+dMKqq +yqZWFde8rwfL/BeqNVpQc3eBojCnIV4cIfhm4etviFsufaRAEXhDcEdh3PokbNkk +dV3CZRKiQukWrJrdr7hMO7FZe77E8NbwJtAauUcna6GrvwJy6YpmFpVRORqeOxKW ++A+m/JCHCL5MTjKeEDh43gVP0LxfKdnUiHmyFEL53GUzd3ogk+15n8pgpetbqBgy +sKFXAJ3IXClgHpLat2nBqFZsSBZhzD9og8puO4v9ioGe1QBxaXngN5ajGlw15/kg +Xr7rcoBCk5c9DBFuKYmv68OJYhAfAYJbb3lq8Gb2YGRMBOGeo1m0jpUjlTtEb/8Z +cUGU6ug70q1wIa3HPPHPUx/nO7d4uO6QqUwmTrTTF9vDBy4GB1BBNIR3NTdgvVhq +oPaoo2XVBPLuFu53w92ap9VHz0fk0JUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IC +AQCPSe8gh9BkehsdIEtPw6FVNusofuxG2fvEQOBI2lRBfXJ5LdTKOFzXbKxn8wSs +MNidFbpmyDMzhyLBTTCbGSRMUsZfPfOWJG9HknHttcwX1k8bI/a1gEVK6L/e6rRm +yqKF9pRus3EkbRCKEVMGh7CbVVwxujN2xKbuX00QLyni4OiYhpRzCJuIUkzU+Dmf +jWzrhjDhI3C6D0Mlpl1Anor5qlThwJap4Ak/fS6WlWgBA+XsPujNLu/fdutWUatn +bEuVSQuP/4LH1l86OT5aP095JQWLYTo0xrMyT6+K5U5zPjLzKDK0CoAHfpbiauRN +iPSGlEGtICtm66fVAHhbH448aRnWB+6O0GBrSO5STI8XJUNg5IyyCF8ihbDUC/9G +m9wksO0Xc0M27Ir9yuPe53f/giP/0gTw6Z01hCz3NZB6tNppHHd270c5edPI8ewf +pEpqXvvx08vgyUbW5OgK4mpjP7w/Xv6zV5hrw/mXbg7maPHA4EsgbEUTWQupjSZ7 +FFHTmVVnnnBrFHvSnb5OM+5/s80beaniDHp7zemj1+nxabeUWuDn6rTxiCFrF1+F +TCJDFdHsl3wcLVroygCaVg8TDq2UmUygQuuSn36oHCAM+jDOf4AAi/vgL/WLtJQx +rWYtLhB+Ilaoh7+lH6SepgFuQzDMa7BOrB7AQ3zsOtgsTg== +-----END CERTIFICATE REQUEST----- diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.key.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.key.pem new file mode 100644 index 0000000000..8ce8b92f98 --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.p12 b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.p12 new file mode 100644 index 0000000000..f1d93e2d6d Binary files /dev/null and b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.p12 differ diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.pem new file mode 100644 index 0000000000..f328e5653f --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/certs/clients/test-user-ca@localhost.pem @@ -0,0 +1,128 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4097 (0x1001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=MA, L=Boston, O=Red Hat, OU=Keycloak, CN=Keycloak CA/emailAddress=contact@keycloak.org + Validity + Not Before: Jun 15 13:53:53 2019 GMT + Not After : Oct 31 13:53:53 2046 GMT + Subject: C=US, ST=MA, O=Red Hat, OU=Keycloak, CN=test-user/emailAddress=test-user@localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:c3:16:4d:f5:e3:dd:3a:f9:48:c7:5c:5b:b7:16: + 17:a2:ff:fd:3e:8a:85:b6:e7:3d:82:4f:63:1a:e4: + 2b:a6:37:88:57:aa:d5:c3:d4:8a:7d:1a:4f:75:37: + 0f:47:24:4b:80:b4:ee:db:41:bc:aa:31:cf:5a:76: + a5:52:97:59:7f:d8:35:15:38:04:ba:a5:aa:c8:df: + b0:7f:ff:a5:db:16:a2:f2:d1:4b:b2:37:11:30:7b: + 19:01:b1:6b:33:d8:94:f1:2b:52:94:b7:52:9f:e7: + f9:e0:e5:62:ef:df:0f:b6:63:20:1f:a7:cb:72:62: + b4:bf:13:f7:53:1e:ac:c7:11:7a:33:cc:ea:ff:45: + 32:89:83:75:7e:44:fa:a5:0f:75:03:70:bc:24:cf: + 74:d3:16:fa:49:3f:f3:04:87:2e:ff:f7:b6:72:a7: + ef:bc:ba:ec:b9:f9:58:75:95:5d:a4:d2:65:6a:c1: + 9c:06:3c:7b:fe:a2:70:92:9b:d9:26:65:d7:61:fd: + de:36:ef:9d:30:aa:aa:ca:a6:56:15:d7:bc:af:07: + cb:fc:17:aa:35:5a:50:73:77:81:a2:30:a7:21:5e: + 1c:21:f8:66:e1:eb:6f:88:5b:2e:7d:a4:40:11:78: + 43:70:47:61:dc:fa:24:6c:d9:24:75:5d:c2:65:12: + a2:42:e9:16:ac:9a:dd:af:b8:4c:3b:b1:59:7b:be: + c4:f0:d6:f0:26:d0:1a:b9:47:27:6b:a1:ab:bf:02: + 72:e9:8a:66:16:95:51:39:1a:9e:3b:12:96:f8:0f: + a6:fc:90:87:08:be:4c:4e:32:9e:10:38:78:de:05: + 4f:d0:bc:5f:29:d9:d4:88:79:b2:14:42:f9:dc:65: + 33:77:7a:20:93:ed:79:9f:ca:60:a5:eb:5b:a8:18: + 32:b0:a1:57:00:9d:c8:5c:29:60:1e:92:da:b7:69: + c1:a8:56:6c:48:16:61:cc:3f:68:83:ca:6e:3b:8b: + fd:8a:81:9e:d5:00:71:69:79:e0:37:96:a3:1a:5c: + 35:e7:f9:20:5e:be:eb:72:80:42:93:97:3d:0c:11: + 6e:29:89:af:eb:c3:89:62:10:1f:01:82:5b:6f:79: + 6a:f0:66:f6:60:64:4c:04:e1:9e:a3:59:b4:8e:95: + 23:95:3b:44:6f:ff:19:71:41:94:ea:e8:3b:d2:ad: + 70:21:ad:c7:3c:f1:cf:53:1f:e7:3b:b7:78:b8:ee: + 90:a9:4c:26:4e:b4:d3:17:db:c3:07:2e:06:07:50: + 41:34:84:77:35:37:60:bd:58:6a:a0:f6:a8:a3:65: + d5:04:f2:ee:16:ee:77:c3:dd:9a:a7:d5:47:cf:47: + e4:d0:95 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + OpenSSL Generated Client Certificate + X509v3 Subject Key Identifier: + D6:DE:A6:F7:6B:2B:52:AF:AC:B2:1D:15:B7:F1:42:5E:EA:D3:51:C2 + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + Signature Algorithm: sha256WithRSAEncryption + 68:b1:a3:68:51:22:09:10:91:cf:40:a9:ed:c4:27:96:1e:bb: + 33:3d:e8:e2:84:e2:d6:07:16:07:32:75:4f:53:51:f7:c5:67: + 1d:9c:c4:0c:ba:82:74:a4:fc:d0:3f:15:d9:3f:38:61:81:6f: + 32:06:66:15:43:56:29:f5:73:18:89:e0:f4:72:d7:db:f1:9f: + 8e:f9:fe:ee:7f:f7:d1:70:2d:fb:89:3a:d1:fa:e0:2a:2e:c6: + e9:5c:e9:05:b3:78:77:d1:1c:43:24:c7:44:bb:0a:f6:b3:bf: + 33:36:59:99:2d:bd:dc:52:a9:08:5f:2d:88:c6:d0:ab:13:19: + 3e:38:1b:3d:86:60:b4:9e:6b:64:a6:10:c6:80:ee:39:b5:38: + 44:12:28:8c:7d:e1:e9:5c:37:d2:a4:d7:d4:8f:13:cf:bf:24: + 7b:fe:be:7f:50:a6:0e:b2:61:da:80:c0:ea:94:db:bd:9f:69: + 12:36:00:17:b0:aa:92:25:ea:e1:a8:0d:40:85:a0:fe:ea:1d: + 14:60:2a:ce:62:67:5d:96:c8:73:a5:58:a5:2c:67:32:db:c3: + 0c:2f:0a:35:b9:cf:9e:d3:26:26:85:4d:39:57:cc:ff:54:19: + a1:7c:cd:8e:ef:7a:f8:42:65:5d:da:7a:94:6c:6d:3a:8c:04: + 82:3a:bf:8d:f0:3c:79:5c:8a:b4:51:a3:24:84:30:df:b5:92: + 73:25:e3:d4:20:b2:ae:12:f4:dd:4c:b0:13:b6:c6:61:7d:95: + f4:68:c4:d3:bc:78:08:bf:33:e2:ef:12:aa:4c:ea:c3:9c:96: + 19:2d:71:0c:40:fa:23:ac:a6:f2:c3:ff:d0:ca:d7:ae:df:8d: + 0a:07:55:20:64:76:7c:96:a4:6f:74:07:a3:2d:58:b8:e3:cf: + 98:e8:88:74:64:80:b7:65:18:02:6d:81:99:48:b0:31:68:e1: + da:e0:66:0a:bc:72:d1:c2:90:54:d3:0b:64:79:f8:5f:1d:36: + a4:6c:65:88:61:b2:e1:9e:7f:f8:45:d5:86:e0:b6:be:aa:15: + e7:17:bf:00:17:69:3d:ae:aa:e1:6f:c5:01:a7:11:94:80:d5: + 1c:c4:c8:f8:35:ea:d8:56:e2:98:9f:96:6d:10:e5:c1:23:a5: + 04:18:66:21:b5:53:d5:7f:93:f6:bd:37:69:92:9b:a6:13:56: + 99:b9:c5:d9:37:e7:24:1a:d9:05:93:e9:b9:d1:46:54:21:cc: + 25:4b:d9:f1:b0:5a:e5:33:1d:ef:eb:05:90:53:76:02:3d:cf: + a0:b7:7f:be:22:25:66:fb:63:f3:10:20:9a:dc:9f:61:a4:34: + 5e:26:ee:0f:13:de:d1:b4 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt index 6976f7c404..a314899262 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt @@ -1 +1,2 @@ V 450708195701Z 1000 unknown /C=US/ST=MA/O=Red Hat/OU=Keycloak/CN=Keycloak Intermediate CA/emailAddress=contact@keycloak.org +V 461031135353Z 1001 unknown /C=US/ST=MA/O=Red Hat/OU=Keycloak/CN=test-user/emailAddress=test-user@localhost diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr.old new file mode 100644 index 0000000000..8f7e63a347 --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.attr.old @@ -0,0 +1 @@ +unique_subject = yes diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old index e69de29bb2..6976f7c404 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/index.txt.old @@ -0,0 +1 @@ +V 450708195701Z 1000 unknown /C=US/ST=MA/O=Red Hat/OU=Keycloak/CN=Keycloak Intermediate CA/emailAddress=contact@keycloak.org diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1001.pem b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1001.pem new file mode 100644 index 0000000000..f328e5653f --- /dev/null +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/newcerts/1001.pem @@ -0,0 +1,128 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4097 (0x1001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=MA, L=Boston, O=Red Hat, OU=Keycloak, CN=Keycloak CA/emailAddress=contact@keycloak.org + Validity + Not Before: Jun 15 13:53:53 2019 GMT + Not After : Oct 31 13:53:53 2046 GMT + Subject: C=US, ST=MA, O=Red Hat, OU=Keycloak, CN=test-user/emailAddress=test-user@localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:c3:16:4d:f5:e3:dd:3a:f9:48:c7:5c:5b:b7:16: + 17:a2:ff:fd:3e:8a:85:b6:e7:3d:82:4f:63:1a:e4: + 2b:a6:37:88:57:aa:d5:c3:d4:8a:7d:1a:4f:75:37: + 0f:47:24:4b:80:b4:ee:db:41:bc:aa:31:cf:5a:76: + a5:52:97:59:7f:d8:35:15:38:04:ba:a5:aa:c8:df: + b0:7f:ff:a5:db:16:a2:f2:d1:4b:b2:37:11:30:7b: + 19:01:b1:6b:33:d8:94:f1:2b:52:94:b7:52:9f:e7: + f9:e0:e5:62:ef:df:0f:b6:63:20:1f:a7:cb:72:62: + b4:bf:13:f7:53:1e:ac:c7:11:7a:33:cc:ea:ff:45: + 32:89:83:75:7e:44:fa:a5:0f:75:03:70:bc:24:cf: + 74:d3:16:fa:49:3f:f3:04:87:2e:ff:f7:b6:72:a7: + ef:bc:ba:ec:b9:f9:58:75:95:5d:a4:d2:65:6a:c1: + 9c:06:3c:7b:fe:a2:70:92:9b:d9:26:65:d7:61:fd: + de:36:ef:9d:30:aa:aa:ca:a6:56:15:d7:bc:af:07: + cb:fc:17:aa:35:5a:50:73:77:81:a2:30:a7:21:5e: + 1c:21:f8:66:e1:eb:6f:88:5b:2e:7d:a4:40:11:78: + 43:70:47:61:dc:fa:24:6c:d9:24:75:5d:c2:65:12: + a2:42:e9:16:ac:9a:dd:af:b8:4c:3b:b1:59:7b:be: + c4:f0:d6:f0:26:d0:1a:b9:47:27:6b:a1:ab:bf:02: + 72:e9:8a:66:16:95:51:39:1a:9e:3b:12:96:f8:0f: + a6:fc:90:87:08:be:4c:4e:32:9e:10:38:78:de:05: + 4f:d0:bc:5f:29:d9:d4:88:79:b2:14:42:f9:dc:65: + 33:77:7a:20:93:ed:79:9f:ca:60:a5:eb:5b:a8:18: + 32:b0:a1:57:00:9d:c8:5c:29:60:1e:92:da:b7:69: + c1:a8:56:6c:48:16:61:cc:3f:68:83:ca:6e:3b:8b: + fd:8a:81:9e:d5:00:71:69:79:e0:37:96:a3:1a:5c: + 35:e7:f9:20:5e:be:eb:72:80:42:93:97:3d:0c:11: + 6e:29:89:af:eb:c3:89:62:10:1f:01:82:5b:6f:79: + 6a:f0:66:f6:60:64:4c:04:e1:9e:a3:59:b4:8e:95: + 23:95:3b:44:6f:ff:19:71:41:94:ea:e8:3b:d2:ad: + 70:21:ad:c7:3c:f1:cf:53:1f:e7:3b:b7:78:b8:ee: + 90:a9:4c:26:4e:b4:d3:17:db:c3:07:2e:06:07:50: + 41:34:84:77:35:37:60:bd:58:6a:a0:f6:a8:a3:65: + d5:04:f2:ee:16:ee:77:c3:dd:9a:a7:d5:47:cf:47: + e4:d0:95 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + OpenSSL Generated Client Certificate + X509v3 Subject Key Identifier: + D6:DE:A6:F7:6B:2B:52:AF:AC:B2:1D:15:B7:F1:42:5E:EA:D3:51:C2 + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + Signature Algorithm: sha256WithRSAEncryption + 68:b1:a3:68:51:22:09:10:91:cf:40:a9:ed:c4:27:96:1e:bb: + 33:3d:e8:e2:84:e2:d6:07:16:07:32:75:4f:53:51:f7:c5:67: + 1d:9c:c4:0c:ba:82:74:a4:fc:d0:3f:15:d9:3f:38:61:81:6f: + 32:06:66:15:43:56:29:f5:73:18:89:e0:f4:72:d7:db:f1:9f: + 8e:f9:fe:ee:7f:f7:d1:70:2d:fb:89:3a:d1:fa:e0:2a:2e:c6: + e9:5c:e9:05:b3:78:77:d1:1c:43:24:c7:44:bb:0a:f6:b3:bf: + 33:36:59:99:2d:bd:dc:52:a9:08:5f:2d:88:c6:d0:ab:13:19: + 3e:38:1b:3d:86:60:b4:9e:6b:64:a6:10:c6:80:ee:39:b5:38: + 44:12:28:8c:7d:e1:e9:5c:37:d2:a4:d7:d4:8f:13:cf:bf:24: + 7b:fe:be:7f:50:a6:0e:b2:61:da:80:c0:ea:94:db:bd:9f:69: + 12:36:00:17:b0:aa:92:25:ea:e1:a8:0d:40:85:a0:fe:ea:1d: + 14:60:2a:ce:62:67:5d:96:c8:73:a5:58:a5:2c:67:32:db:c3: + 0c:2f:0a:35:b9:cf:9e:d3:26:26:85:4d:39:57:cc:ff:54:19: + a1:7c:cd:8e:ef:7a:f8:42:65:5d:da:7a:94:6c:6d:3a:8c:04: + 82:3a:bf:8d:f0:3c:79:5c:8a:b4:51:a3:24:84:30:df:b5:92: + 73:25:e3:d4:20:b2:ae:12:f4:dd:4c:b0:13:b6:c6:61:7d:95: + f4:68:c4:d3:bc:78:08:bf:33:e2:ef:12:aa:4c:ea:c3:9c:96: + 19:2d:71:0c:40:fa:23:ac:a6:f2:c3:ff:d0:ca:d7:ae:df:8d: + 0a:07:55:20:64:76:7c:96:a4:6f:74:07:a3:2d:58:b8:e3:cf: + 98:e8:88:74:64:80:b7:65:18:02:6d:81:99:48:b0:31:68:e1: + da:e0:66:0a:bc:72:d1:c2:90:54:d3:0b:64:79:f8:5f:1d:36: + a4:6c:65:88:61:b2:e1:9e:7f:f8:45:d5:86:e0:b6:be:aa:15: + e7:17:bf:00:17:69:3d:ae:aa:e1:6f:c5:01:a7:11:94:80:d5: + 1c:c4:c8:f8:35:ea:d8:56:e2:98:9f:96:6d:10:e5:c1:23:a5: + 04:18:66:21:b5:53:d5:7f:93:f6:bd:37:69:92:9b:a6:13:56: + 99:b9:c5:d9:37:e7:24:1a:d9:05:93:e9:b9:d1:46:54:21:cc: + 25:4b:d9:f1:b0:5a:e5:33:1d:ef:eb:05:90:53:76:02:3d:cf: + a0:b7:7f:be:22:25:66:fb:63:f3:10:20:9a:dc:9f:61:a4:34: + 5e:26:ee:0f:13:de:d1:b4 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial index dd11724042..7d802a3e71 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial @@ -1 +1 @@ -1001 +1002 diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old index 83b33d238d..dd11724042 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/pki/root/ca/serial.old @@ -1 +1 @@ -1000 +1001 diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml index 2b9b5e62dc..e371ad297f 100644 --- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml +++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml @@ -187,6 +187,7 @@ keycloak.jks keycloak.truststore client.jks + client-ca.jks ca.crt client.crt client.key diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java index 782003de4a..6f14f099d4 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java @@ -267,36 +267,45 @@ public class OAuthClient { return this; } + public Supplier getHttpClient() { + return httpClient; + } + public static CloseableHttpClient newCloseableHttpClient() { if (sslRequired) { - KeyStore keystore = null; - // load the keystore containing the client certificate - keystore type is probably jks or pkcs12 String keyStorePath = System.getProperty("client.certificate.keystore"); String keyStorePassword = System.getProperty("client.certificate.keystore.passphrase"); - try { - keystore = KeystoreUtil.loadKeyStore(keyStorePath, keyStorePassword); - } catch (Exception e) { - e.printStackTrace(); - } - - // load the trustore - KeyStore truststore = null; String trustStorePath = System.getProperty("client.truststore"); String trustStorePassword = System.getProperty("client.truststore.passphrase"); - try { - truststore = KeystoreUtil.loadKeyStore(trustStorePath, trustStorePassword); - } catch(Exception e) { - e.printStackTrace(); - } - return (CloseableHttpClient) new org.keycloak.adapters.HttpClientBuilder() - .keyStore(keystore, keyStorePassword) - .trustStore(truststore) - .hostnameVerification(org.keycloak.adapters.HttpClientBuilder.HostnameVerificationPolicy.ANY) - .build(); + return newCloseableHttpClientSSL(keyStorePath, keyStorePassword, trustStorePath, trustStorePassword); } return HttpClientBuilder.create().build(); } + public static CloseableHttpClient newCloseableHttpClientSSL(String keyStorePath, + String keyStorePassword, String trustStorePath, String trustStorePassword) { + KeyStore keystore = null; + // load the keystore containing the client certificate - keystore type is probably jks or pkcs12 + try { + keystore = KeystoreUtil.loadKeyStore(keyStorePath, keyStorePassword); + } catch (Exception e) { + e.printStackTrace(); + } + + // load the trustore + KeyStore truststore = null; + try { + truststore = KeystoreUtil.loadKeyStore(trustStorePath, trustStorePassword); + } catch (Exception e) { + e.printStackTrace(); + } + return (CloseableHttpClient) new org.keycloak.adapters.HttpClientBuilder() + .keyStore(keystore, keyStorePassword) + .trustStore(truststore) + .hostnameVerification(org.keycloak.adapters.HttpClientBuilder.HostnameVerificationPolicy.ANY) + .build(); + } + public CloseableHttpResponse doPreflightRequest() { try (CloseableHttpClient client = httpClient.get()) { HttpOptions options = new HttpOptions(getAccessTokenUrl()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509OCSPResponderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509OCSPResponderTest.java index 3573efefa6..95a3628b40 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509OCSPResponderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/x509/X509OCSPResponderTest.java @@ -18,6 +18,7 @@ package org.keycloak.testsuite.x509; +import com.google.common.base.Charsets; import org.jboss.arquillian.drone.api.annotation.Drone; import org.junit.After; import org.junit.Assert; @@ -38,6 +39,12 @@ import io.undertow.Undertow; import io.undertow.server.handlers.BlockingHandler; import org.keycloak.testsuite.util.PhantomJSBrowser; import org.openqa.selenium.WebDriver; +import java.nio.file.Paths; +import java.util.function.Supplier; +import org.apache.commons.io.IOUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.keycloak.testsuite.util.PhantomJSBrowser; +import org.openqa.selenium.WebDriver; /** * Verifies Certificate revocation using OCSP responder. @@ -85,6 +92,73 @@ public class X509OCSPResponderTest extends AbstractX509AuthenticationTest { Assert.assertThat(response.getErrorDescription(), containsString("Certificate's been revoked.")); } + @Test + public void loginFailedOnOCSPResponderRevocationCheckWithoutCA() throws Exception { + X509AuthenticatorConfigModel config = + new X509AuthenticatorConfigModel() + .setOCSPEnabled(true) + .setMappingSourceType(SUBJECTDN_EMAIL) + .setOCSPResponder("http://" + OCSP_RESPONDER_HOST + ":" + OCSP_RESPONDER_PORT + "/oscp") + .setUserIdentityMapperType(USERNAME_EMAIL); + AuthenticatorConfigRepresentation cfg = newConfig("x509-directgrant-config", config.getConfig()); + String cfgId = createConfig(directGrantExecution.getId(), cfg); + Assert.assertNotNull(cfgId); + + String keyStorePath = Paths.get(System.getProperty("client.certificate.keystore")) + .getParent().resolve("client-ca.jks").toString(); + String keyStorePassword = System.getProperty("client.certificate.keystore.passphrase"); + String trustStorePath = System.getProperty("client.truststore"); + String trustStorePassword = System.getProperty("client.truststore.passphrase"); + Supplier previous = oauth.getHttpClient(); + try { + oauth.clientId("resource-owner"); + oauth.httpClient(() -> OAuthClient.newCloseableHttpClientSSL(keyStorePath, keyStorePassword, trustStorePath, trustStorePassword)); + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "", "", null); + + assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatusCode()); + assertEquals("invalid_request", response.getError()); + + // the ocsp signer cert is issued by the same CA but no OCSP-Signing extension so error + Assert.assertThat(response.getErrorDescription(), containsString("Responder's certificate not valid for signing OCSP responses")); + } finally { + oauth.httpClient(previous); + } + } + + @Test + public void loginOKOnOCSPResponderRevocationCheckWithoutCA() throws Exception { + X509AuthenticatorConfigModel config = + new X509AuthenticatorConfigModel() + .setOCSPEnabled(true) + .setMappingSourceType(SUBJECTDN_EMAIL) + .setOCSPResponder("http://" + OCSP_RESPONDER_HOST + ":" + OCSP_RESPONDER_PORT + "/oscp") + .setOCSPResponderCertificate( + IOUtils.toString(this.getClass().getResourceAsStream(OcspHandler.OCSP_RESPONDER_CERT_PATH), Charsets.UTF_8) + .replace("-----BEGIN CERTIFICATE-----\n", "") + .replace("\n-----END CERTIFICATE-----", "")) + .setUserIdentityMapperType(USERNAME_EMAIL); + AuthenticatorConfigRepresentation cfg = newConfig("x509-directgrant-config", config.getConfig()); + String cfgId = createConfig(directGrantExecution.getId(), cfg); + Assert.assertNotNull(cfgId); + + String keyStorePath = Paths.get(System.getProperty("client.certificate.keystore")) + .getParent().resolve("client-ca.jks").toString(); + String keyStorePassword = System.getProperty("client.certificate.keystore.passphrase"); + String trustStorePath = System.getProperty("client.truststore"); + String trustStorePassword = System.getProperty("client.truststore.passphrase"); + Supplier previous = oauth.getHttpClient(); + try { + oauth.clientId("resource-owner"); + oauth.httpClient(() -> OAuthClient.newCloseableHttpClientSSL(keyStorePath, keyStorePassword, trustStorePath, trustStorePassword)); + OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("secret", "", "", null); + + // now it's OK because the certificate is fixed + assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode()); + } finally { + oauth.httpClient(previous); + } + } + @Before public void startOCSPResponder() throws Exception { ocspResponder = Undertow.builder().addHttpListener(OCSP_RESPONDER_PORT, OCSP_RESPONDER_HOST)