Crypto-View

keycloak/keycloak

Readiness score
0 of 100
How this is calculated · previous scan 0
Cryptographic posture
Quantum-vulnerable 290 Already broken 8 Reduced margin 76 Could not be determined 513 Quantum-safe 64
To address283
Key establishment117
Inventory only13
Total findings964
What was analysed
Branch main
Commit 3a720903102b161236a77ec6ec410fedc3e86545 Bump vitest from 4.0.16 to 4.1.11 in /js (#52521)
Committed 2026-09-09 18:04 UTC
Scanned 2026-09-10 01:50 UTC 1 day ago
Coverage 10716 files, 8389 java, 1 python, 1087 javascript

Earlier scans of this repository

15 scans · score 0 → 0 · compare any two
15 scans · 0 → 0 (unchanged). The filled point is the scan you are reading.
Scanned Commit Score To address
4 hours ago 61a4555fe865 main 0 804 Compare
5 hours ago 61a4555fe865 main 0 283 Compare
18 hours ago 3a720903102b main 0 283 Compare
19 hours ago 13f76e360154 0 270 Compare
21 hours ago 3a720903102b main 0 283 Compare
1 day ago 3a720903102b main 0 283 Compare
1 day ago 3a720903102b main 0 283 Compare
1 day ago this scan 3a720903102b main 0 283
1 day ago 3a720903102b main 0 257 Compare
2 days ago 68ff31182d1f main 0 245 Compare
3 days ago 0cd2f7891a69 main 0 245 Compare
3 days ago 0cd2f7891a69 main 0 245 Compare
4 days ago f5a00e4a5c2d main 0 243 Compare
10 days ago ae1a37058feb main 0 243 Compare
11 days ago 13f76e360154 0 232 Compare

Every repository in this history is re-scanned weekly.

List of cryptographic assets

SHA-1 Already broken 4 places See details

Hash algorithm through the JCA

`MessageDigest.getInstance()`. MD5 and SHA-1 are reported as already broken; SHA-256 is reported as a reduced margin rather than a defect.

This is already unsafe today, with no quantum computer involved. SHAttered and subsequent work produced practical collisions; NIST withdrew SHA-1 in 2030 guidance and it is already unacceptable for signatures.

What to do. SHA-256 as the floor, SHA-384 where the digest protects something that must remain verifiable for decades.

  1. distribution/downloads/src/main/java/CopyDependencies.java:93 MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
  2. server-spi-private/src/main/java/org/keycloak/protocol/saml/util/ArtifactBindingUtils.java:48 MessageDigest sha1Digester = MessageDigest.getInstance("SHA-1");
  3. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/ArtifactBindingTest.java:195 test path MessageDigest sha1Digester = MessageDigest.getInstance("SHA-1");
  4. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/ArtifactBindingTest.java:455 test path MessageDigest sha1Digester = MessageDigest.getInstance("SHA-1");
java.messagedigest · CWE-328
MD5 Already broken 2 places See details

Hash algorithm through the JCA

`MessageDigest.getInstance()`. MD5 and SHA-1 are reported as already broken; SHA-256 is reported as a reduced margin rather than a defect.

This is already unsafe today, with no quantum computer involved. Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest.

What to do. SHA-256 as the floor, SHA-384 where the digest protects something that must remain verifiable for decades.

  1. distribution/downloads/src/main/java/CopyDependencies.java:92 MessageDigest md5 = MessageDigest.getInstance("MD5");
  2. services/src/main/java/org/keycloak/cache/ComputedKey.java:34 return MessageDigest.getInstance("MD5");
java.messagedigest · CWE-328
RSAES-PKCS1v15 Already broken Recorded traffic 2 places See details

Cipher transformation named away from the call

A JCA transformation string - `algorithm/mode/padding` - written somewhere other than a `getInstance()` argument, which is how a codebase that centralises its cryptography passes the choice to a helper. The string is unambiguous wherever it appears: nothing but a transformation is spelled that way.

This names an encryption method as text, and passes it to code elsewhere that does the work. It is the same choice, made in a different place.

What to do. The same migration applies as to the call that consumes it. Move the constant and the call together, so the inventory keeps naming the algorithm after the change.

  1. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:59 providers.put(CryptoConstants.RSA1_5, new DefaultRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/PKCS1Padding"));
  2. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:60 providers.put(CryptoConstants.RSA1_5, new ElytronRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/PKCS1Padding"));
java.transformation · CWE-327
RSA4096-bit Quantum-vulnerable 26 places See details

X.509 certificate

A PEM certificate. The subject public-key algorithm and key size are read from the SubjectPublicKeyInfo structure, and the not-after date is reported so certificates that outlive the migration window are visible.

This is a digital identity document. Its expiry date matters: one valid for many years locks in today's algorithms for that long.

What to do. Shorten certificate lifetimes so re-issuing with a post-quantum key is routine.

  1. operator/src/test/resources/example-mtls-secret.yaml:7 test path -----BEGIN CERTIFICATE-----
  2. operator/src/test/resources/example-mtls-truststore-secret.yaml:7 test path -----BEGIN CERTIFICATE-----
  3. services/src/test/resources/truststores/keycloak.pem:1 test path -----BEGIN CERTIFICATE-----
  4. tests/base/src/test/resources/keycloak-truststore.pem:6 test path -----BEGIN CERTIFICATE-----
  5. tests/base/src/test/resources/keycloak-truststore.pem:79 test path -----BEGIN CERTIFICATE-----
  6. testsuite/integration-arquillian/servers/auth-server/common/keystore/ca.crt:1 test path -----BEGIN CERTIFICATE-----
  7. testsuite/integration-arquillian/servers/auth-server/common/keystore/ca.crt:35 test path -----BEGIN CERTIFICATE-----
  8. testsuite/integration-arquillian/servers/auth-server/common/keystore/client-ca.crt:1 test path -----BEGIN CERTIFICATE-----
  9. testsuite/integration-arquillian/servers/auth-server/common/keystore/client.crt:1 test path -----BEGIN CERTIFICATE-----
  10. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/ca.cert.pem:1 test path -----BEGIN CERTIFICATE-----
  11. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-ca@localhost.csr:1 test path -----BEGIN CERTIFICATE REQUEST-----
  12. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-ca@localhost.pem:94 test path -----BEGIN CERTIFICATE-----
  13. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-obb@localhost.cert.pem:1 test path -----BEGIN CERTIFICATE-----
  14. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-obb@localhost.csr.pem:1 test path -----BEGIN CERTIFICATE REQUEST-----
  15. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-san@localhost.cert.pem:1 test path -----BEGIN CERTIFICATE-----
  16. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem:1 test path -----BEGIN CERTIFICATE-----
  17. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/certs/ca-chain.cert.pem:35 test path -----BEGIN CERTIFICATE-----
  18. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/certs/intermediate.cert.pem:1 test path -----BEGIN CERTIFICATE-----
  19. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/csr/intermediate.csr.pem:1 test path -----BEGIN CERTIFICATE REQUEST-----
  20. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/newcerts/1000.pem:1 test path -----BEGIN CERTIFICATE-----
  21. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/newcerts/2009.pem:1 test path -----BEGIN CERTIFICATE-----
  22. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/newcerts/200A.pem:1 test path -----BEGIN CERTIFICATE-----
  23. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/newcerts/200B.pem:1 test path -----BEGIN CERTIFICATE-----
  24. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/newcerts/1000.pem:1 test path -----BEGIN CERTIFICATE-----
  25. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/newcerts/1001.pem:94 test path -----BEGIN CERTIFICATE-----
  26. testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/intermediate-ca.crt:1 test path -----BEGIN CERTIFICATE-----
pem.certificate
TLS Quantum-vulnerable Recorded traffic 19 places See details

TLS context created in code

`SSLContext.getInstance()`. The protocol version is reported; the key exchange it negotiates is classical in every TLS 1.2 and 1.3 cipher suite available today.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Every TLS cipher suite in general use negotiates a classical key exchange, so a recorded session is decryptable once that exchange falls.

What to do. Keep TLS 1.3, and track the hybrid key-exchange groups as they reach the JDK. TLS is where harvest-now-decrypt-later exposure is largest.

  1. adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java:263 theContext = SSLContext.getInstance("SSL");
  2. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SslTest.java:133 test path SSLContext context = SSLContext.getInstance("TLS");
  3. model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/JGroupsConfigurator.java:226 var sslContext = SSLContext.getInstance(TLS_PROTOCOL);
  4. model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/remote/DefaultCacheRemoteConfigProviderFactory.java:237 var sslContext = SSLContext.getInstance("TLS");
  5. operator/src/main/java/org/keycloak/operator/controllers/KeycloakClientBaseController.java:368 SSLContext sslContext = SSLContext.getInstance("TLS");
  6. operator/src/test/java/org/keycloak/operator/testsuite/utils/TrustAllSSLContext.java:48 test path sslContext = SSLContext.getInstance("TLS");
  7. services/src/main/java/org/keycloak/connections/httpclient/HttpClientBuilder.java:271 theContext = SSLContext.getInstance("TLS");
  8. services/src/main/java/org/keycloak/connections/httpclient/HttpClientBuilder.java:282 final SSLContext tlsContext = SSLContext.getInstance("TLS");
  9. services/src/main/java/org/keycloak/truststore/JSSETruststoreConfigurator.java:59 SSLContext sslctx = SSLContext.getInstance("TLS");
  10. test-framework/conformance-runner/src/main/java/org/keycloak/testframework/conformance/OpenIdConformanceServer.java:190 test path SSLContext context = SSLContext.getInstance("TLS");
  11. test-framework/core/src/main/java/org/keycloak/testframework/server/DistributionKeycloakServer.java:296 test path SSLContext sslContext = SSLContext.getInstance("TLS");
  12. test-framework/core/src/main/java/org/keycloak/testframework/server/ReadinessProbe.java:88 test path SSLContext ctx = SSLContext.getInstance("TLS");
  13. tests/conformance/src/test/java/org/keycloak/tests/conformance/vp/AbstractVpConformanceTest.java:96 test path SSLContext sslContext = SSLContext.getInstance("TLS");
  14. testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/AbstractQuarkusDeployableContainer.java:415 test path sslContext = SSLContext.getInstance("TLS");
  15. testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/containers/InfinispanServerDeployableContainer.java:175 test path SSLContext sc = SSLContext.getInstance("SSL");
  16. testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MutualTLSUtils.java:103 test path SSLContext sslContext = SSLContext.getInstance("TLS");
  17. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/SslMailServer.java:119 test path final SSLContext sslContext = SSLContext.getInstance("TLS");
  18. testsuite/integration-arquillian/util/src/main/java/org/keycloak/testsuite/utils/tls/TLSUtils.java:66 test path sslContext = SSLContext.getInstance("TLS");
  19. util/embedded-ldap/src/main/java/org/keycloak/util/ldap/TLS13StartTlsHandler.java:68 sslCtx = SSLContext.getInstance("TLS");
java.sslcontext · CWE-757
RSA2048-bit Quantum-vulnerable 17 places See details

X.509 certificate

A PEM certificate. The subject public-key algorithm and key size are read from the SubjectPublicKeyInfo structure, and the not-after date is reported so certificates that outlive the migration window are visible.

This is a digital identity document. Its expiry date matters: one valid for many years locks in today's algorithms for that long.

What to do. Shorten certificate lifetimes so re-issuing with a post-quantum key is routine.

  1. core/src/test/resources/certs/ANS-cert.pem:1 test path -----BEGIN CERTIFICATE-----
  2. core/src/test/resources/certs/UPN-cert.pem:1 test path -----BEGIN CERTIFICATE-----
  3. operator/src/test/resources/example-truststore-secret.yaml:7 test path -----BEGIN CERTIFICATE-----
  4. quarkus/tests/integration/src/test/resources/encrypted-test.crt.pem:1 test path -----BEGIN CERTIFICATE-----
  5. quarkus/tests/integration/src/test/resources/self-signed.pem:1 test path -----BEGIN CERTIFICATE-----
  6. services/src/test/resources/truststores/keycloak.pem:30 test path -----BEGIN CERTIFICATE-----
  7. tests/base/src/test/resources/keycloak-truststore.pem:46 test path -----BEGIN CERTIFICATE-----
  8. tests/base/src/test/resources/org/keycloak/tests/ssl/smtp-server.pem:1 test path -----BEGIN CERTIFICATE-----
  9. testsuite/integration-arquillian/servers/auth-server/common/keystore/ocsp/certs/ca-chain.crt:1 test path -----BEGIN CERTIFICATE-----
  10. testsuite/integration-arquillian/servers/auth-server/common/keystore/ocsp/certs/ca-chain.crt:24 test path -----BEGIN CERTIFICATE-----
  11. testsuite/integration-arquillian/servers/auth-server/common/keystore/ocsp/certs/intermediate-ca.crt:1 test path -----BEGIN CERTIFICATE-----
  12. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/newcerts/intermediate-ca-3.crt:1 test path -----BEGIN CERTIFICATE-----
  13. testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/ocsp/certs/ca-chain.crt:1 test path -----BEGIN CERTIFICATE-----
  14. testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/ocsp/certs/ca-chain.crt:24 test path -----BEGIN CERTIFICATE-----
  15. testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/ocsp/certs/intermediate-ca.crt:1 test path -----BEGIN CERTIFICATE-----
  16. testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/intermediate-ca-2.crt:1 test path -----BEGIN CERTIFICATE-----
  17. testsuite/integration-arquillian/tests/base/src/test/resources/keys/certificate.pem:1 test path -----BEGIN CERTIFICATE-----
pem.certificate
ECDH Quantum-vulnerable Recorded traffic 15 places See details

Classical key pair generated through the JCA

`KeyPairGenerator.getInstance()` with a classical algorithm. The concrete family and, where an `initialize()` call is close enough to read, the key size are resolved from the source and reported on the finding.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Generate the classical key alongside an ML-KEM or ML-DSA key and carry both until relying parties accept the post-quantum one.

  1. authz/client/src/test/java/org/keycloak/authorization/client/test/ECDSAAlgorithmTest.java:43 test path keyPair = KeyPairGenerator.getInstance("EC").genKeyPair();
  2. common/src/main/java/org/keycloak/common/util/KeyUtils.java:88 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  3. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:132 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  4. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:125 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  5. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSEcdhEsAlgorithmProvider.java:142 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BCFIPS");
  6. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:99 test path KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
  7. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:123 test path KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
  8. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:149 test path KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
  9. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/credentialbuilder/SdJwtCredentialBuilderTest.java:128 test path var holderKeyPair = KeyPairGenerator.getInstance("EC").generateKeyPair();
  10. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:159 test path KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  11. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:1354 test path KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  12. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:1605 test path KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  13. tests/base/src/test/java/org/keycloak/tests/oid4vc/presentation/OID4VPTrustMaterialDelegationTest.java:334 test path KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
  14. tests/conformance/src/test/java/org/keycloak/tests/conformance/ConformanceSigningKey.java:129 test path KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("EC");
  15. tests/conformance/src/test/java/org/keycloak/tests/conformance/vci/VciTestSigningKey.java:70 test path KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("EC");
java.keypairgenerator · CWE-327
ECDH Quantum-vulnerable Recorded traffic 15 places See details

Classical key material handled through the JCA

`KeyFactory.getInstance()` for a classical algorithm. This indicates the code parses or produces keys of that family, which is a migration surface even where it does no cryptography itself.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Include this code path in the inventory: it has to accept post-quantum key encodings before the keys themselves can change.

  1. core/src/test/java/org/keycloak/sdjwt/TestSettings.java:166 test path KeyFactory keyFactory = KeyFactory.getInstance("EC");
  2. core/src/test/java/org/keycloak/sdjwt/TestSettings.java:192 test path KeyFactory keyFactory = KeyFactory.getInstance("EC");
  3. crypto/default/src/main/java/org/keycloak/crypto/def/BCECDSACryptoProvider.java:81 KeyFactory keyFactory = KeyFactory.getInstance("EC");
  4. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:199 KeyFactory keyFactory = KeyFactory.getInstance("EC");
  5. crypto/default/src/test/java/org/keycloak/crypto/def/test/BCEcdhEsAlgorithmProviderTest.java:116 test path KeyFactory keyFactory = KeyFactory.getInstance("EC");
  6. crypto/default/src/test/java/org/keycloak/crypto/def/test/BCEcdhEsAlgorithmProviderTest.java:127 test path KeyFactory keyFactory = KeyFactory.getInstance("EC");
  7. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSECDSACryptoProvider.java:86 KeyFactory keyFactory = KeyFactory.getInstance("EC");
  8. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSEcdhEsAlgorithmProvider.java:205 KeyFactory keyFactory = KeyFactory.getInstance("EC", "BCFIPS");
  9. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/BCFIPSEcdhEsAlgorithmProviderTest.java:104 test path KeyFactory keyFactory = KeyFactory.getInstance("EC", "BCFIPS");
  10. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/BCFIPSEcdhEsAlgorithmProviderTest.java:115 test path KeyFactory keyFactory = KeyFactory.getInstance("EC", "BCFIPS");
  11. services/src/main/java/org/keycloak/keys/AbstractGeneratedEcKeyProviderFactory.java:117 KeyFactory kf = KeyFactory.getInstance("EC");
  12. services/src/main/java/org/keycloak/keys/GeneratedEcdhKeyProvider.java:58 KeyFactory kf = KeyFactory.getInstance("EC");
  13. services/src/main/java/org/keycloak/keys/GeneratedEcdsaKeyProvider.java:58 KeyFactory kf = KeyFactory.getInstance("EC");
  14. tests/base/src/test/java/org/keycloak/tests/keys/GeneratedEcdhKeyProviderTest.java:311 test path KeyFactory kf = KeyFactory.getInstance("EC");
  15. tests/base/src/test/java/org/keycloak/tests/keys/GeneratedEcdsaKeyProviderTest.java:239 test path KeyFactory kf = KeyFactory.getInstance("EC");
java.keyfactory · CWE-327
ECDSA Quantum-vulnerable 15 places See details

Elliptic-curve cryptography through BouncyCastle

A BouncyCastle elliptic-curve class. `ECDHBasicAgreement` in particular is key establishment and carries harvest-now-decrypt-later exposure.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-DSA-65 for signatures, ML-KEM-768 for key establishment.

  1. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:59 import org.bouncycastle.jce.ECNamedCurveTable;
  2. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:196 ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
  3. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:36 import org.bouncycastle.jce.ECNamedCurveTable;
  4. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:107 ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveName);
  5. crypto/default/src/test/java/org/keycloak/crypto/def/test/BCEcdhEsAlgorithmProviderTest.java:44 test path import org.bouncycastle.jce.ECNamedCurveTable;
  6. crypto/default/src/test/java/org/keycloak/crypto/def/test/BCEcdhEsAlgorithmProviderTest.java:113 test path ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
  7. crypto/default/src/test/java/org/keycloak/crypto/def/test/BCEcdhEsAlgorithmProviderTest.java:124 test path ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
  8. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSEcdhEsAlgorithmProvider.java:53 import org.bouncycastle.asn1.x9.X9ECParameters;
  9. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSEcdhEsAlgorithmProvider.java:201 X9ECParameters ecParams = NISTNamedCurves.getByName(crv);
  10. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:60 import org.bouncycastle.asn1.x9.ECNamedCurveTable;
  11. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:61 import org.bouncycastle.asn1.x9.X9ECParameters;
  12. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:154 X9ECParameters params = ECNamedCurveTable.getByName(curveName);
  13. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/BCFIPSEcdhEsAlgorithmProviderTest.java:43 test path import org.bouncycastle.asn1.x9.X9ECParameters;
  14. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/BCFIPSEcdhEsAlgorithmProviderTest.java:100 test path X9ECParameters ecParams = NISTNamedCurves.getByName(crv);
  15. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/BCFIPSEcdhEsAlgorithmProviderTest.java:111 test path X9ECParameters ecParams = NISTNamedCurves.getByName(crv);
java.bouncycastle.ec · CWE-327
RSA2048-bit Quantum-vulnerable Recorded traffic 14 places See details

Classical key pair generated through the JCA

`KeyPairGenerator.getInstance()` with a classical algorithm. The concrete family and, where an `initialize()` call is close enough to read, the key size are resolved from the source and reported on the finding.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Generate the classical key alongside an ML-KEM or ML-DSA key and carry both until relying parties accept the post-quantum one.

  1. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCertificateUtilsProviderTest.java:75 test path KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
  2. saml-core/src/test/java/org/keycloak/saml/processing/api/saml/v2/sig/SAML2SignatureTest.java:46 test path KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
  3. services/src/test/java/org/keycloak/procotol/docker/installation/DockerKeyIdentifierTest.java:27 test path final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
  4. services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java:67 test path KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
  5. services/src/test/java/org/keycloak/protocol/saml/SamlProtocolTest.java:76 test path KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
  6. tests/base/src/test/java/org/keycloak/tests/broker/trust/TrustMaterialIdentityProviderTest.java:321 test path KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
  7. tests/base/src/test/java/org/keycloak/tests/client/OIDCJwksClientRegistrationTest.java:189 test path KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
  8. tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerEndpointEncryptionTest.java:294 test path var keyGen = java.security.KeyPairGenerator.getInstance("RSA");
  9. tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java:404 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
  10. tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCIssuerTestBase.java:645 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
  11. tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java:152 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
  12. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/credentialbuilder/CredentialBuilderTest.java:41 test path var kpg = java.security.KeyPairGenerator.getInstance("RSA");
  13. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/SdJwtCredentialSignerTest.java:460 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
  14. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmManager.java:82 test path KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
java.keypairgenerator · CWE-327
RSA Quantum-vulnerable Recorded traffic 13 places See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. testsuite/integration-arquillian/servers/auth-server/common/keystore/client.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  2. testsuite/integration-arquillian/servers/auth-server/common/keystore/ocsp/private/intermediate-ca.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  3. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-ca@localhost.key.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  4. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user-obb@localhost.key.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  5. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/certs/clients/test-user@localhost.key.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  6. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/intermediate/private/intermediate.key.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  7. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/newcerts/intermediate-ca-3.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  8. testsuite/integration-arquillian/servers/auth-server/common/pki/root/ca/private/ca.key.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  9. testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/ocsp/private/intermediate-ca.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  10. testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/intermediate-ca-2.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  11. testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/intermediate-ca.key:1 test path -----BEGIN RSA PRIVATE KEY-----
  12. testsuite/integration-arquillian/tests/base/src/test/resources/keys/private2048.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
  13. testsuite/integration-arquillian/tests/base/src/test/resources/keys/private4096.pem:1 test path -----BEGIN RSA PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
ECDH256-bitsecg/secp256r1 Quantum-vulnerable Recorded traffic 10 places See details

Named elliptic curve requested

`ECGenParameterSpec` names a curve explicitly. Every standardised prime curve is broken by Shor regardless of its size, so a larger curve is not a mitigation.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-DSA-65 for signatures, ML-KEM-768 for key establishment.

  1. core/src/test/java/org/keycloak/jose/jwk/JWKTest.java:190 test path ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
  2. core/src/test/java/org/keycloak/jose/jwk/JWKTest.java:205 test path ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
  3. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:124 test path keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
  4. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:150 test path keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1"));
  5. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:160 test path keyGen.initialize(new ECGenParameterSpec("secp256r1"));
  6. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:1355 test path keyGen.initialize(new ECGenParameterSpec("secp256r1"));
  7. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:1606 test path keyGen.initialize(new ECGenParameterSpec("secp256r1"));
  8. tests/base/src/test/java/org/keycloak/tests/oid4vc/presentation/OID4VPTrustMaterialDelegationTest.java:335 test path keyGen.initialize(new ECGenParameterSpec("secp256r1"));
  9. tests/conformance/src/test/java/org/keycloak/tests/conformance/ConformanceSigningKey.java:130 test path keyGenerator.initialize(new ECGenParameterSpec("secp256r1"));
  10. tests/conformance/src/test/java/org/keycloak/tests/conformance/vci/VciTestSigningKey.java:71 test path keyGenerator.initialize(new ECGenParameterSpec("secp256r1"));
java.eccurve · CWE-327
ECDSA256-bitsecg/secp256r1 Quantum-vulnerable 9 places See details

Public key declared as a JSON Web Key

A `kty` field, with the curve read from the sibling `crv` where the family needs one. A JWKS document declares a key without naming an algorithm anywhere, so it is invisible to a scan that only looks for `alg`.

This file publishes the public keys other systems use to check this system's signatures. Everyone who trusts these keys has to accept the new kind of key before the old ones can be retired.

What to do. A published JWKS is what relying parties trust. It has to accept a post-quantum key type before the keys behind it can change, so put it early in the migration order.

jose.jwk · CWE-327
RSA Quantum-vulnerable Recorded traffic 9 places See details

Classical key pair generated through the JCA

`KeyPairGenerator.getInstance()` with a classical algorithm. The concrete family and, where an `initialize()` call is close enough to read, the key size are resolved from the source and reported on the finding.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Generate the classical key alongside an ML-KEM or ML-DSA key and carry both until relying parties accept the post-quantum one.

  1. core/src/test/java/org/keycloak/RSAVerifierTest.java:64 test path badPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  2. core/src/test/java/org/keycloak/RSAVerifierTest.java:65 test path idpPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  3. core/src/test/java/org/keycloak/RSAVerifierTest.java:91 test path KeyPair caKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  4. core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java:62 test path KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  5. core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java:82 test path KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  6. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/CRLDistributionPointTest.java:124 test path KeyPair keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
  7. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronOCSPPoviderTest.java:62 test path KeyPair keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
  8. tests/base/src/test/java/org/keycloak/tests/oauth/RefreshTokenTest.java:460 test path KeyPair rsaKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
  9. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/credentialbuilder/JwtCredentialBuilderTest.java:125 test path var holderKeyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
java.keypairgenerator · CWE-327
RSA Quantum-vulnerable Recorded traffic 8 places See details

Classical key material handled through the JCA

`KeyFactory.getInstance()` for a classical algorithm. This indicates the code parses or produces keys of that family, which is a migration surface even where it does no cryptography itself.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Include this code path in the inventory: it has to accept post-quantum key encodings before the keys themselves can change.

  1. adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java:145 KeyFactory kf = KeyFactory.getInstance("RSA", CryptoConstants.BC_PROVIDER_ID);
  2. adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java:159 KeyFactory kf = KeyFactory.getInstance("RSA", CryptoConstants.BC_PROVIDER_ID);
  3. common/src/main/java/org/keycloak/common/util/KeyUtils.java:70 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  4. core/src/main/java/org/keycloak/jose/jwk/JWKParser.java:140 KeyFactory kf = KeyFactory.getInstance("RSA");
  5. saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmldsig/RSAKeyValueType.java:103 KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
  6. saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmldsig/RSAKeyValueType.java:122 KeyFactory rsaKeyFactory = KeyFactory.getInstance("rsa");
  7. tests/base/src/test/java/org/keycloak/tests/saml/AbstractSamlTest.java:70 test path KeyFactory kfRsa = KeyFactory.getInstance("RSA");
  8. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/AbstractSamlTest.java:81 test path KeyFactory kfRsa = KeyFactory.getInstance("RSA");
java.keyfactory · CWE-327
ECDSA Quantum-vulnerable 3 places See details

JOSE algorithm declared in configuration

An `alg` value in JSON or YAML. `none` is reported as a critical defect; HS* is an HMAC and is not quantum-vulnerable; RS*, PS*, ES* and EdDSA are.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. No standardised post-quantum JOSE algorithm exists yet. Keep token lifetimes short.

jose.algorithm · CWE-327
DSA Quantum-vulnerable 2 places See details

Classical key material handled through the JCA

`KeyFactory.getInstance()` for a classical algorithm. This indicates the code parses or produces keys of that family, which is a migration surface even where it does no cryptography itself.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Include this code path in the inventory: it has to accept post-quantum key encodings before the keys themselves can change.

  1. saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmldsig/DSAKeyValueType.java:211 KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
  2. saml-core-api/src/main/java/org/keycloak/dom/xmlsec/w3/xmldsig/DSAKeyValueType.java:234 KeyFactory dsaKeyFactory = KeyFactory.getInstance("dsa");
java.keyfactory · CWE-327
ECDH Quantum-vulnerable Recorded traffic 2 places See details

Public key declared as a JSON Web Key

A `kty` field, with the curve read from the sibling `crv` where the family needs one. A JWKS document declares a key without naming an algorithm anywhere, so it is invisible to a scan that only looks for `alg`.

This file publishes the public keys other systems use to check this system's signatures. Everyone who trusts these keys has to accept the new kind of key before the old ones can be retired.

What to do. A published JWKS is what relying parties trust. It has to accept a post-quantum key type before the keys behind it can change, so put it early in the migration order.

jose.jwk · CWE-327
ECDH Quantum-vulnerable Recorded traffic 2 places See details

Classical key agreement through the JCA

`KeyAgreement.getInstance()` with ECDH, DH or XDH. Key agreement is the highest-priority class of finding: traffic recorded today is decrypted once the key exchange is broken.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-KEM-768 (FIPS 203), or a hybrid X25519+ML-KEM-768 construction that keeps the classical guarantee while adding the quantum one.

  1. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:208 KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
  2. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:183 KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
java.keyagreement · CWE-327
EdDSA Quantum-vulnerable 2 places See details

Classical key material handled through the JCA

`KeyFactory.getInstance()` for a classical algorithm. This indicates the code parses or produces keys of that family, which is a migration surface even where it does no cryptography itself.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Include this code path in the inventory: it has to accept post-quantum key encodings before the keys themselves can change.

java.keyfactory · CWE-327
RSA2048-bit Quantum-vulnerable Recorded traffic 2 places See details

Public key file

A PEM public-key block. The algorithm is read from the SubjectPublicKeyInfo.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Inventory only; a public key is not itself a secret.

pem.public-key
RSA-PSS Quantum-vulnerable 2 places See details

Classical signature algorithm through the JCA

`Signature.getInstance()` with a classical algorithm. The digest and the key algorithm are split out of the JCA name, so `SHA1withRSA` reports both the broken digest and the quantum-vulnerable key.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-DSA-65 (FIPS 204). Where the verifier cannot be changed, sign twice and publish both signatures.

  1. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:183 var signature = Signature.getInstance("RSASSA-PSS");
  2. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSignatureAlgTest.java:36 test path Signature signature = Signature.getInstance("RSASSA-PSS");
java.signature · CWE-327
ECDH384-bitsecg/secp384r1 Quantum-vulnerable Recorded traffic 1 place See details

Named elliptic curve requested

`ECGenParameterSpec` names a curve explicitly. Every standardised prime curve is broken by Shor regardless of its size, so a larger curve is not a mitigation.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. ML-DSA-65 for signatures, ML-KEM-768 for key establishment.

  1. services/src/test/java/org/keycloak/protocol/oid4vc/issuance/credentialbuilder/MdocCredentialBuilderTest.java:100 test path keyPairGenerator.initialize(new ECGenParameterSpec("secp384r1"));
java.eccurve · CWE-327
ECDH256-bit Quantum-vulnerable Recorded traffic 1 place See details

Classical key pair generated through the JCA

`KeyPairGenerator.getInstance()` with a classical algorithm. The concrete family and, where an `initialize()` call is close enough to read, the key size are resolved from the source and reported on the finding.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Generate the classical key alongside an ML-KEM or ML-DSA key and carry both until relying parties accept the post-quantum one.

  1. tests/base/src/test/java/org/keycloak/tests/oid4vc/OID4VCProofTestUtils.java:133 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", BouncyIntegration.PROVIDER);
java.keypairgenerator · CWE-327
Ed25519255-bitother/Ed25519 Quantum-vulnerable 1 place See details

JOSE algorithm declared in configuration

An `alg` value in JSON or YAML. `none` is reported as a critical defect; HS* is an HMAC and is not quantum-vulnerable; RS*, PS*, ES* and EdDSA are.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. No standardised post-quantum JOSE algorithm exists yet. Keep token lifetimes short.

jose.algorithm · CWE-327
RSA4096-bit Quantum-vulnerable Recorded traffic 1 place See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

  1. operator/src/test/resources/example-mtls-secret.yaml:41 test path -----BEGIN PRIVATE KEY-----
pem.private-key · CWE-321, CWE-327
RSA Quantum-vulnerable Recorded traffic 1 place See details

Public key declared as a JSON Web Key

A `kty` field, with the curve read from the sibling `crv` where the family needs one. A JWKS document declares a key without naming an algorithm anywhere, so it is invisible to a scan that only looks for `alg`.

This file publishes the public keys other systems use to check this system's signatures. Everyone who trusts these keys has to accept the new kind of key before the old ones can be retired.

What to do. A published JWKS is what relying parties trust. It has to accept a post-quantum key type before the keys behind it can change, so put it early in the migration order.

jose.jwk · CWE-327
RSA4096-bit Quantum-vulnerable Recorded traffic 1 place See details

Public key file

A PEM public-key block. The algorithm is read from the SubjectPublicKeyInfo.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Inventory only; a public key is not itself a secret.

pem.public-key
RSA-OAEP Quantum-vulnerable Recorded traffic 1 place See details

Classical public-key cipher through the JCA

`Cipher.getInstance()` with a transformation whose algorithm component is a public-key or legacy symmetric cipher. The transformation string is parsed into algorithm, mode and padding, so `RSA/ECB/PKCS1Padding` is separated from `RSA/ECB/OAEPWithSHA-256AndMGF1Padding`.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. For RSA encryption, move to ML-KEM-768 and keep RSA-OAEP only as the classical half of a hybrid during transition.

  1. services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java:91 test path cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
java.cipher · CWE-327
RSA-PSS Quantum-vulnerable 1 place See details

Classical key pair generated through the JCA

`KeyPairGenerator.getInstance()` with a classical algorithm. The concrete family and, where an `initialize()` call is close enough to read, the key size are resolved from the source and reported on the finding.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Generate the classical key alongside an ML-KEM or ML-DSA key and carry both until relying parties accept the post-quantum one.

  1. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSignatureAlgTest.java:28 test path KeyPair keyPair = KeyPairGenerator.getInstance("RSASSA-PSS").genKeyPair();
java.keypairgenerator · CWE-327
RSA-PSS Quantum-vulnerable 1 place See details

Classical key material handled through the JCA

`KeyFactory.getInstance()` for a classical algorithm. This indicates the code parses or produces keys of that family, which is a migration surface even where it does no cryptography itself.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. Include this code path in the inventory: it has to accept post-quantum key encodings before the keys themselves can change.

  1. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSignatureAlgTest.java:34 test path key.setPrivateKey(KeyFactory.getInstance("RSASSA-PSS").generatePrivate(kspec));
java.keyfactory · CWE-327
RSASSA-PKCS1v15 Quantum-vulnerable 1 place See details

JOSE algorithm declared in configuration

An `alg` value in JSON or YAML. `none` is reported as a critical defect; HS* is an HMAC and is not quantum-vulnerable; RS*, PS*, ES* and EdDSA are.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer. The v1.5 signature scheme of RFC 8017 section 8.2 has no classical break of its own; RSA-PSS is preferred for new work, but the quantum exposure is the same for both.

What to do. No standardised post-quantum JOSE algorithm exists yet. Keep token lifetimes short.

jose.algorithm · CWE-327
AES Reduced margin 16 places See details

Key material constructed for a named algorithm

`new SecretKeySpec(bytes, "AES")` and the other key-spec constructors name the algorithm as an argument rather than through `getInstance()`. Code that wraps raw bytes into a key this way often never calls `getInstance()` at all, so the algorithm is invisible to a scan that only looks at the factories.

This wraps raw bytes into a key for a named algorithm. It is part of the same migration as whatever uses that key.

What to do. Wherever this key is used, the same migration applies as to the call that consumes it. Trace it to the operation and treat the two together.

  1. core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java:168 SecretKeySpec aesKey = new SecretKeySpec(cekAesKey, "AES");
  2. core/src/main/java/org/keycloak/jose/jwe/enc/AesGcmEncryptionProvider.java:151 SecretKeySpec aesKey = new SecretKeySpec(cekBytes, "AES");
  3. core/src/test/java/org/keycloak/jose/JWETest.java:66 test path SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
  4. core/src/test/java/org/keycloak/jose/JWETest.java:76 test path final SecretKey aesKey = new SecretKeySpec(AES_256_KEY, "AES");
  5. core/src/test/java/org/keycloak/jose/JWETest.java:121 test path SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
  6. core/src/test/java/org/keycloak/jose/JWETest.java:140 test path SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
  7. core/src/test/java/org/keycloak/jose/JWETest.java:185 test path final SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
  8. core/src/test/java/org/keycloak/jose/JWETest.java:208 test path final SecretKey aesKey = new SecretKeySpec(AES_256_KEY, "AES");
  9. core/src/test/java/org/keycloak/jose/JWETest.java:230 test path SecretKeySpec aesKeySpec = new SecretKeySpec(aesKey, "AES");
  10. core/src/test/java/org/keycloak/jose/JWETest.java:307 test path final SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
  11. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:80 cipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(derivedKey, "AES"));
  12. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:113 cipher.init(Cipher.WRAP_MODE, new SecretKeySpec(derivedKey, "AES"));
  13. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:115 return cipher.wrap(new SecretKeySpec(cekBytes, "AES"));
  14. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWETest.java:31 test path final SecretKey aesKey = new SecretKeySpec(AES_256_KEY, "AES");
  15. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlEncryptedAssertionTest.java:69 test path SecretKey secretKey = new SecretKeySpec(secret, "AES");
  16. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlEncryptedIdTest.java:55 test path SecretKey secretKey = new SecretKeySpec(secret, "AES");
java.keyspec · CWE-327
SHA-256 Reduced margin 15 places See details

Hash algorithm through the JCA

`MessageDigest.getInstance()`. MD5 and SHA-1 are reported as already broken; SHA-256 is reported as a reduced margin rather than a defect.

A quantum computer weakens this but does not break it. Increasing the key or digest size restores the margin. Pre-image resistance falls to about 128 bits of quantum work. Adequate for most uses; SHA-384 restores the full margin where a signature must last decades.

What to do. SHA-256 as the floor, SHA-384 where the digest protects something that must remain verifiable for decades.

  1. common/src/main/java/org/keycloak/common/util/KeyUtils.java:100 return Base64Url.encode(MessageDigest.getInstance(DEFAULT_MESSAGE_DIGEST).digest(key.getEncoded()));
  2. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java:41 test path KeyGenerator keygen = KeyGenerator.getInstance("HmacSHA256");
  3. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java:33 test path SecretKeyFactory skFact = SecretKeyFactory.getInstance("HmacSHA256", BouncyIntegration.PROVIDER );
  4. operator/src/main/java/org/keycloak/operator/Utils.java:120 return MessageDigest.getInstance("SHA-256");
  5. server-spi-private/src/main/java/org/keycloak/broker/provider/AbstractIdentityProvider.java:138 md = MessageDigest.getInstance("SHA-256");
  6. services/src/main/java/org/keycloak/protocol/docker/DockerKeyIdentifier.java:37 final MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
  7. services/src/main/java/org/keycloak/protocol/oid4vc/issuance/signing/vcdm/Ed255192018Suite.java:129 MessageDigest md = MessageDigest.getInstance("SHA-256");
  8. services/src/main/java/org/keycloak/protocol/oidc/mappers/SHA256PairwiseSubMapper.java:90 sha256 = MessageDigest.getInstance(HASH_ALGORITHM);
  9. services/src/main/java/org/keycloak/protocol/oidc/par/endpoints/AbstractParEndpoint.java:88 hash = MessageDigest.getInstance("SHA-256").digest(inputData.getBytes(StandardCharsets.UTF_8));
  10. services/src/main/java/org/keycloak/services/clientpolicy/executor/PKCEEnforcerExecutor.java:230 MessageDigest md = MessageDigest.getInstance("SHA-256");
  11. services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java:282 md = MessageDigest.getInstance("SHA-256");
  12. services/src/main/java/org/keycloak/services/util/MtlsHoKTokenUtil.java:139 MessageDigest md = MessageDigest.getInstance(DIGEST_ALG);
  13. services/src/main/java/org/keycloak/utils/BrokerUtil.java:44 MessageDigest md = MessageDigest.getInstance("SHA-256");
  14. testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MutualTLSUtils.java:143 test path MessageDigest md = MessageDigest.getInstance(digestAlg);
  15. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthProofKeyForCodeExchangeTest.java:403 test path MessageDigest md = MessageDigest.getInstance("SHA-256");
java.messagedigest · CWE-328
Kerberos Reduced margin 9 places See details

Kerberos or SPNEGO authentication

`javax.security.auth.kerberos` or a GSS-API call. Kerberos itself is symmetric and survives Shor; its PKINIT certificate flow is public-key and does not. The encryption types configured for the realm decide whether it is also a present-day concern.

A quantum computer weakens this but does not break it. Increasing the key or digest size restores the margin. Kerberos is symmetric at its core, so Shor does not break it. The surrounding PKINIT certificate flow is public-key and does fall.

What to do. Restrict the realm to AES encryption types, and treat PKINIT certificates as part of the public-key migration.

java.kerberos
AES Reduced margin 6 places See details

Classical public-key cipher through the JCA

`Cipher.getInstance()` with a transformation whose algorithm component is a public-key or legacy symmetric cipher. The transformation string is parsed into algorithm, mode and padding, so `RSA/ECB/PKCS1Padding` is separated from `RSA/ECB/OAEPWithSHA-256AndMGF1Padding`.

A quantum computer weakens this but does not break it. Increasing the key or digest size restores the margin. Grover's algorithm halves the effective strength; the parameter, not the design, is the problem. The key size was not visible at this call site, so the weaker case is assumed.

What to do. For RSA encryption, move to ML-KEM-768 and keep RSA-OAEP only as the classical half of a hybrid during transition.

  1. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:142 return Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
  2. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:147 return Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
  3. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:142 return Cipher.getInstance("AES/CBC/PKCS5Padding");
  4. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:147 return Cipher.getInstance("AES/GCM/NoPadding");
  5. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:207 return Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
  6. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:212 return Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
java.cipher · CWE-327
PBKDF2 Reduced margin 2 places See details

Key material constructed for a named algorithm

`new SecretKeySpec(bytes, "AES")` and the other key-spec constructors name the algorithm as an argument rather than through `getInstance()`. Code that wraps raw bytes into a key this way often never calls `getInstance()` at all, so the algorithm is invisible to a scan that only looks at the factories.

This wraps raw bytes into a key for a named algorithm. It is part of the same migration as whatever uses that key.

What to do. Wherever this key is used, the same migration applies as to the call that consumes it. Trace it to the operation and treat the two together.

  1. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java:114 KeySpec spec = new PBEKeySpec(rawPasswordWithPadding.toCharArray(), salt, iterations, derivedKeySize);
  2. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:413 test path KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keyLength);
java.keyspec · CWE-327
PBKDF2 Reduced margin 17 places See details

Password hashing or key derivation

A `SecretKeyFactory` for PBKDF2, or a BouncyCastle password KDF. Not a quantum exposure, and part of a complete inventory.

This is how passwords are stored. Quantum computers do not meaningfully weaken it.

What to do. PBKDF2 needs a high iteration count. Argon2 through BouncyCastle is stronger.

  1. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java:37 public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
  2. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProviderFactory.java:52 return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS, getMaxPaddingLength());
  3. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java:14 public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA256";
  4. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha256PasswordHashProviderFactory.java:23 return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS, getMaxPaddingLength(), 256);
  5. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java:14 public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA512";
  6. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2Sha512PasswordHashProviderFactory.java:23 return new Pbkdf2PasswordHashProvider(ID, PBKDF2_ALGORITHM, DEFAULT_ITERATIONS, getMaxPaddingLength());
  7. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:110 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA256", 1);
  8. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:121 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA1", 1);
  9. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:135 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA256", 1);
  10. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:156 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA1", 1);
  11. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:205 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA512", 2);
  12. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:283 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA1", Pbkdf2PasswordHashProviderFactory.DEFAULT_ITERATIONS);
  13. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:329 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA512", Pbkdf2Sha512PasswordHashProviderFactory.DEFAULT_ITERATIONS);
  14. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:340 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA256", Pbkdf2Sha256PasswordHashProviderFactory.DEFAULT_ITERATIONS);
  15. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:350 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA512", Pbkdf2Sha512PasswordHashProviderFactory.DEFAULT_ITERATIONS);
  16. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:364 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA256", Pbkdf2Sha256PasswordHashProviderFactory.DEFAULT_ITERATIONS);
  17. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:372 test path assertEncoded(credential, password, credential.getPasswordSecretData().getSalt(), "PBKDF2WithHmacSHA256", Pbkdf2Sha256PasswordHashProviderFactory.DEFAULT_ITERATIONS, false);
java.kdf
unknown Could not be determined 22 places See details

Key pair algorithm chosen at runtime

`KeyPairGenerator.getInstance(x)` where the argument is an identifier. The algorithm cannot be resolved without running the program, so this is reported as an unknown rather than assumed to be classical.

This code picks its encryption method while it runs, so a scan cannot tell which one it ends up using. Somebody has to check the configuration.

What to do. Trace the value to its configuration source and record the concrete algorithm in the cryptographic inventory by hand.

  1. common/src/main/java/org/keycloak/common/util/KeyUtils.java:79 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(curveName);
  2. core/src/main/java/org/keycloak/jose/jwk/AKPUtils.java:32 KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
  3. core/src/main/java/org/keycloak/jose/jwk/EdECUtilsImpl.java:108 publicKey = KeyFactory.getInstance(crv).generatePublic(keySpec);
  4. core/src/test/java/org/keycloak/jose/jwk/AKPJWKTest.java:80 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
  5. core/src/test/java/org/keycloak/jose/jwk/JWKTest.java:285 test path Signature signature = Signature.getInstance(javaAlgorithm);
  6. core/src/test/java/org/keycloak/jose/jwk/JWKTest.java:292 test path Signature verifier = Signature.getInstance(javaAlgorithm);
  7. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:130 return KeyPairGenerator.getInstance(algorithm, BouncyIntegration.PROVIDER);
  8. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java:136 return KeyFactory.getInstance(algorithm, BouncyIntegration.PROVIDER);
  9. crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryptionJWEAlgorithmProvider.java:36 return Cipher.getInstance(jcaAlgorithmName);
  10. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryptionJWEAlgorithmProvider.java:55 return Cipher.getInstance(jcaAlgorithmName);
  11. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:127 return KeyPairGenerator.getInstance(algorithm);
  12. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:137 return KeyFactory.getInstance(algorithm);
  13. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java:199 return Signature.getInstance(javaAlgorithm);
  14. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:197 return KeyPairGenerator.getInstance(algorithm, BouncyIntegration.PROVIDER);
  15. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:202 return KeyFactory.getInstance(algorithm , BouncyIntegration.PROVIDER);
  16. saml-core/src/main/java/org/keycloak/saml/SignatureAlgorithm.java:87 return Signature.getInstance(javaSignatureAlgorithm);
  17. saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java:212 sig = Signature.getInstance(PicketLinkFederationConstants.DSA_SIGNATURE_ALGORITHM);
  18. saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/SignatureUtil.java:214 sig = Signature.getInstance(PicketLinkFederationConstants.RSA_SIGNATURE_ALGORITHM);
  19. services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java:112 test path Signature signature = Signature.getInstance(javaAlgorithm);
  20. services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java:119 test path Signature verifier = Signature.getInstance(javaAlgorithm);
  21. tests/base/src/test/java/org/keycloak/tests/oid4vc/presentation/OID4VPVerifierTestBase.java:123 test path KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyType.EC);
  22. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/LogoutTokenUtil.java:46 test path Signature signature = Signature.getInstance(JavaAlgorithm.RS256);
java.keypairgenerator.variable · CWE-327
unknown Could not be determined 5 places See details

Key store holding classical key material

`KeyStore.getInstance("JKS"|"PKCS12"|"BCFKS")`. The store format itself is not the issue; it is the inventory point where the classical private keys of this application live.

This is the application's key cupboard. It is worth knowing what is in it before planning any replacement.

What to do. Record which keys this store holds. A key store is where a migration either happens or silently does not.

java.keystore
unknown Could not be determined 3 places See details

Non-cryptographic randomness near key material

`new Random()` or `Math.random()` in a file that also imports `java.security`, `javax.crypto` or BouncyCastle. `java.util.Random` is a linear congruential generator and its output is predictable from a handful of samples. The import check is what keeps this from firing on every retry jitter and test fixture in the tree.

Part of this code uses a predictable source of random numbers. If any key comes from it, that key can be guessed today, with no quantum computer needed.

What to do. `java.security.SecureRandom`. This is a classical defect, not a quantum one, and it is worth fixing first.

java.random.insecure · CWE-338
unknown Could not be determined 2 places See details

Private key committed to the repository

A PEM private-key block. The header names the algorithm where the format is the legacy one; for PKCS#8 the algorithm OID is read out of the DER. A private key in version control is a present-day incident before it is a quantum question.

A secret key is stored in this repository's files. Anyone who can read the repository can use it. This needs attention today, regardless of quantum computers.

What to do. Revoke and rotate the key, then keep key material out of the repository. Record the algorithm in the inventory.

pem.private-key · CWE-321, CWE-327
unknown Could not be determined 1 place See details

X.509 certificate

A PEM certificate. The subject public-key algorithm and key size are read from the SubjectPublicKeyInfo structure, and the not-after date is reported so certificates that outlive the migration window are visible.

This is a digital identity document. Its expiry date matters: one valid for many years locks in today's algorithms for that long.

What to do. Shorten certificate lifetimes so re-issuing with a post-quantum key is routine.

pem.certificate
unknown Could not be determined 1 place See details

Key material constructed for a named algorithm

`new SecretKeySpec(bytes, "AES")` and the other key-spec constructors name the algorithm as an argument rather than through `getInstance()`. Code that wraps raw bytes into a key this way often never calls `getInstance()` at all, so the algorithm is invisible to a scan that only looks at the factories.

This wraps raw bytes into a key for a named algorithm. It is part of the same migration as whatever uses that key.

What to do. Wherever this key is used, the same migration applies as to the call that consumes it. Trace it to the operation and treat the two together.

  1. server-spi/src/main/java/org/keycloak/models/utils/HmacOTP.java:161 SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
java.keyspec · CWE-327
unknown Could not be determined 8 places See details

Cryptographic library in the dependency manifest

A dependency known to implement classical asymmetric cryptography. Its presence is inventory, not a finding about this codebase: the library may never be called with a quantum-vulnerable algorithm.

The project depends on a cryptography library. Listed so the inventory is complete; it is not by itself a problem.

What to do. Check the version. Several of these libraries have shipped ML-KEM and ML-DSA support since 2024, so the migration may need an upgrade rather than a replacement.

  1. adapters/saml/core/pom.xml:66 <artifactId>bcprov-jdk18on</artifactId>
  2. adapters/spi/adapter-spi/pom.xml:41 <artifactId>bcprov-jdk18on</artifactId>
  3. adapters/spi/jboss-adapter-core/pom.xml:58 <artifactId>bcprov-jdk18on</artifactId>
  4. crypto/default/pom.xml:59 <artifactId>bcprov-jdk18on</artifactId>
  5. dependencies/server-min/pom.xml:44 <artifactId>bcprov-jdk18on</artifactId>
  6. integration/client-cli/client-cli-dist/pom.xml:59 <artifactId>bcprov-jdk18on</artifactId>
  7. testsuite/integration-arquillian/tests/pom.xml:1645 test path <artifactId>bcprov-jdk18on</artifactId>
  8. testsuite/utils/pom.xml:48 test path <artifactId>bcprov-jdk18on</artifactId>
dep.crypto-library
CSPRNG Quantum-safe 38 places See details

Random number generation

`SecureRandom`. A platform CSPRNG is not a quantum exposure; it is recorded because an inventory that omits the randomness source is incomplete. `SHA1PRNG` is named explicitly where it appears, since it is a legacy algorithm even though its output is adequate.

This is where the software gets its random numbers. Quantum computers do not weaken it.

What to do. No action. Prefer the platform default over naming an algorithm.

  1. adapters/saml/core/src/main/java/org/keycloak/adapters/cloned/HttpClientBuilder.java:265 new SecureRandom());
  2. common/src/main/java/org/keycloak/common/util/KeyUtils.java:89 SecureRandom randomGen = new SecureRandom();
  3. common/src/main/java/org/keycloak/common/util/SecretGenerator.java:34 private static final SecureRandom SECURE_RANDOM = new SecureRandom();
  4. core/src/main/java/org/keycloak/jose/jwe/JWEUtils.java:32 new SecureRandom().nextBytes(buf);
  5. core/src/main/java/org/keycloak/mdoc/MdocCredential.java:45 private static final SecureRandom RANDOM = new SecureRandom();
  6. core/src/main/java/org/keycloak/sdjwt/SdJwtUtils.java:43 private static final SecureRandom RANDOM = new SecureRandom();
  7. core/src/test/java/org/keycloak/jose/jwk/JWKTest.java:141 test path SecureRandom randomGen = new SecureRandom();
  8. crypto/default/src/main/java/org/keycloak/crypto/def/BCCertificateUtilsProvider.java:97 SecureRandom random = new SecureRandom();
  9. crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java:133 SecureRandom randomGen = new SecureRandom();
  10. crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultSecureRandomTest.java:36 test path SecureRandom sc1 = new SecureRandom();
  11. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronCertificateUtilsProvider.java:99 SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
  12. crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronEcdhEsAlgorithmProvider.java:126 SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG");
  13. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java:42 test path SecureRandom random = isWindows() ? SecureRandom.getInstance("Windows-PRNG") : SecureRandom.getInstance("NativePRNG");
  14. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSecureRandomTest.java:43 test path SecureRandom sc1 = new SecureRandom();
  15. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSCertificateUtilsProvider.java:98 SecureRandom random = new SecureRandom();
  16. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSEcdhEsAlgorithmProvider.java:143 SecureRandom randomGen = SecureRandom.getInstance("DEFAULT", "BCFIPS");
  17. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java:347 SecureRandom secRandom = new SecureRandom();
  18. crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPSRsaKeyEncryptionJWEAlgorithmProvider.java:41 .withSecureRandom(SecureRandom.getInstance("DEFAULT"));
  19. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SecureRandomTest.java:40 test path SecureRandom sc1 = new SecureRandom();
  20. federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPAttributeMapper.java:94 SecureRandom r = new SecureRandom();
  21. model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java:85 return InfinispanConnectionProvider.NODE_PREFIX + new SecureRandom().nextInt(1000000);
  22. model/jpa/src/main/java/org/keycloak/models/jpa/MigrationModelAdapter.java:90 sb.append(RESOURCE_TAG_CHARSET[new SecureRandom().nextInt(RESOURCE_TAG_CHARSET.length)]);
  23. operator/src/test/java/org/keycloak/operator/testsuite/utils/TrustAllSSLContext.java:49 test path sslContext.init(null, trustAllCerts, new SecureRandom());
  24. saml-core/src/main/java/org/keycloak/saml/RandomSecret.java:37 SecureRandom random = new SecureRandom();
  25. server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java:128 SecureRandom secureRandom = new SecureRandom();
  26. server-spi-private/src/main/java/org/keycloak/credential/hash/Salt.java:8 SecureRandom secureRandom = new SecureRandom();
  27. server-spi/src/main/java/org/keycloak/models/utils/HmacOTP.java:51 SecureRandom r = new SecureRandom();
  28. services/src/main/java/org/keycloak/connections/httpclient/HttpClientBuilder.java:273 new SecureRandom());
  29. services/src/main/java/org/keycloak/protocol/docker/installation/compose/DockerComposeCertsDirectory.java:30 keyGen.initialize(2048, new SecureRandom());
  30. services/src/main/java/org/keycloak/protocol/saml/DefaultSamlArtifactResolver.java:104 SecureRandom handleGenerator = new SecureRandom();
  31. services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java:56 test path keyGen.initialize(2048, new SecureRandom());
  32. services/src/test/java/org/keycloak/procotol/docker/installation/DockerKeyIdentifierTest.java:28 test path keyGen.initialize(2048, new SecureRandom());
  33. test-framework/core/src/main/java/org/keycloak/testframework/server/DistributionKeycloakServer.java:297 test path sslContext.init(null, new TrustManager[] { new NullTrustManager() }, new SecureRandom());
  34. tests/base/src/test/java/org/keycloak/tests/oid4vc/issuance/signing/OID4VCKeyAttestationTest.java:129 test path private static final SecureRandom RANDOM = new SecureRandom();
  35. tests/base/src/test/java/org/keycloak/tests/oid4vc/presentation/OID4VPTrustMaterialDelegationTest.java:326 test path private static final SecureRandom RANDOM = new SecureRandom();
  36. tests/conformance/src/test/java/org/keycloak/tests/conformance/ConformanceSigningKey.java:75 test path private static final SecureRandom RANDOM = new SecureRandom();
  37. tests/conformance/src/test/java/org/keycloak/tests/conformance/vci/VciTestSigningKey.java:62 test path private static final SecureRandom RANDOM = new SecureRandom();
  38. util/embedded-ldap/src/main/java/org/keycloak/util/ldap/TLS13StartTlsHandler.java:72 new SecureRandom());
java.rng
HMAC Quantum-safe 13 places See details

Key material constructed for a named algorithm

`new SecretKeySpec(bytes, "AES")` and the other key-spec constructors name the algorithm as an argument rather than through `getInstance()`. Code that wraps raw bytes into a key this way often never calls `getInstance()` at all, so the algorithm is invisible to a scan that only looks at the factories.

This wraps raw bytes into a key for a named algorithm. It is part of the same migration as whatever uses that key.

What to do. Wherever this key is used, the same migration applies as to the call that consumes it. Trace it to the operation and treat the two together.

  1. common/src/test/java/org/keycloak/common/util/KeyUtilsTest.java:18 test path SecretKeySpec expected = new SecretKeySpec(secretBytes, "HmacSHA256");
  2. core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java:169 SecretKeySpec hmacKey = new SecretKeySpec(cekMacKey, "HMACSHA2");
  3. core/src/test/java/org/keycloak/jose/HmacTest.java:47 test path SecretKey secretKey = new SecretKeySpec(UUID.randomUUID().toString().getBytes(), "HmacSHA256");
  4. core/src/test/java/org/keycloak/jose/HmacTest.java:53 test path SecretKey secretKey = new SecretKeySpec("secret".getBytes(), "HmacSHA256");
  5. core/src/test/java/org/keycloak/jose/JWETest.java:67 test path SecretKey hmacKey = new SecretKeySpec(HMAC_SHA256_KEY, "HMACSHA2");
  6. core/src/test/java/org/keycloak/jose/JWETest.java:77 test path final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA512_KEY, "HMACSHA2");
  7. core/src/test/java/org/keycloak/jose/JWETest.java:122 test path SecretKey hmacKey = new SecretKeySpec(HMAC_SHA256_KEY, "HMACSHA2");
  8. core/src/test/java/org/keycloak/jose/JWETest.java:186 test path final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA256_KEY, "HMACSHA2");
  9. core/src/test/java/org/keycloak/jose/JWETest.java:209 test path final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA512_KEY, "HMACSHA2");
  10. core/src/test/java/org/keycloak/jose/JWETest.java:308 test path final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA256_KEY, "HMACSHA2");
  11. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWETest.java:32 test path final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA512_KEY, "HMACSHA2");
  12. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java:34 test path SecretKey secretKey = skFact.generateSecret(new SecretKeySpec(UUID.randomUUID().toString().getBytes(), "HmacSHA256"));
  13. server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java:228 return secret != null ? new SecretKeySpec(secret.getBytes(), "HmacSHA256") : null;
java.keyspec · CWE-327
CSPRNG Quantum-safe 6 places See details

Random number generation

`crypto.randomBytes()`, `randomUUID()` or `getRandomValues()`. A platform CSPRNG is not a quantum exposure; it is recorded because an inventory that omits the randomness source is incomplete. `Math.random()` is a separate, present-day defect.

This is where the software gets its random numbers. Quantum computers do not weaken it.

What to do. No action.

  1. js/apps/account-ui/test/support/testbed.ts:16 test path realm: crypto.randomUUID(),
  2. js/apps/admin-ui/src/components/dynamic/ClaimDisplayComponent.tsx:29 const generateId = () => crypto.randomUUID();
  3. js/apps/admin-ui/test/clients/authorization.spec.ts:48 test path const clientId = `client-authentication-${crypto.randomUUID()}`;
  4. js/apps/admin-ui/test/realm-settings/events.spec.ts:21 test path const realmName = `events-realm-settings-${crypto.randomUUID()}`;
  5. js/apps/admin-ui/test/support/testbed.ts:12 test path crypto.randomUUID(),
  6. js/themes-vendor/src/main/js/web-crypto-shim.js:44 crypto.getRandomValues(arr);
js.rng
Argon2 Quantum-safe 4 places See details

Password hashing or key derivation

A `SecretKeyFactory` for PBKDF2, or a BouncyCastle password KDF. Not a quantum exposure, and part of a complete inventory.

This is how passwords are stored. Quantum computers do not meaningfully weaken it.

What to do. PBKDF2 needs a high iteration count. Argon2 through BouncyCastle is stronger.

  1. crypto/default/src/main/java/org/keycloak/crypto/hash/Argon2PasswordHashProvider.java:19 import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
  2. crypto/default/src/main/java/org/keycloak/crypto/hash/Argon2PasswordHashProvider.java:124 Argon2BytesGenerator generator = new Argon2BytesGenerator();
  3. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:65 test path import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
  4. testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/PasswordHashingTest.java:428 test path Argon2BytesGenerator generator = new Argon2BytesGenerator();
java.kdf
HMAC Quantum-safe 2 places See details

Classical public-key cipher through the JCA

`Cipher.getInstance()` with a transformation whose algorithm component is a public-key or legacy symmetric cipher. The transformation string is parsed into algorithm, mode and padding, so `RSA/ECB/PKCS1Padding` is separated from `RSA/ECB/OAEPWithSHA-256AndMGF1Padding`.

No known quantum attack changes how strong this is. A keyed MAC is not affected by Shor and only marginally by Grover.

What to do. For RSA encryption, move to ML-KEM-768 and keep RSA-OAEP only as the classical half of a hybrid during transition.

  1. crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java:41 test path KeyGenerator keygen = KeyGenerator.getInstance("HmacSHA256");
  2. crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java:33 test path SecretKeyFactory skFact = SecretKeyFactory.getInstance("HmacSHA256", BouncyIntegration.PROVIDER );
java.cipher · CWE-327
HMAC Quantum-safe 1 place See details

JOSE algorithm declared in configuration

An `alg` value in JSON or YAML. `none` is reported as a critical defect; HS* is an HMAC and is not quantum-vulnerable; RS*, PS*, ES* and EdDSA are.

No known quantum attack changes how strong this is. A keyed MAC is not affected by Shor and only marginally by Grover.

What to do. No standardised post-quantum JOSE algorithm exists yet. Keep token lifetimes short.

jose.algorithm · CWE-327

Cryptographic assets

Algorithm Assessment What it means Occurrences
unknown Could not be determined The algorithm could not be established from the source - chosen at runtime, or decided somewhere this scan does not reach. 513
RSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 132
TLS Quantum-vulnerable Every TLS cipher suite in general use negotiates a classical key exchange, so a recorded session is decryptable once that exchange falls. 74
ECDH Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 46
CSPRNG Quantum-safe A cryptographically secure random number generator provided by the platform. Not weakened by a quantum computer. 44
ECDSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 27
AES Reduced margin Grover's algorithm halves the effective strength; the parameter, not the design, is the problem. The key size was not visible at this call site, so the weaker case is assumed. 22
PBKDF2 Reduced margin Not broken by a quantum computer, but weak against modern GPU cracking at low iteration counts, which is a present-day concern. 19
Kerberos Reduced margin Kerberos is symmetric at its core, so Shor does not break it. The surrounding PKINIT certificate flow is public-key and does fall. 19
HMAC Quantum-safe A keyed MAC is not affected by Shor and only marginally by Grover. 16
SHA-256 Reduced margin Pre-image resistance falls to about 128 bits of quantum work. Adequate for most uses; SHA-384 restores the full margin where a signature must last decades. 16
SHA-1 Already broken SHAttered and subsequent work produced practical collisions; NIST withdrew SHA-1 in 2030 guidance and it is already unacceptable for signatures. 4
Argon2 Quantum-safe The current recommended password hashing function. Not affected by Shor, and memory-hard against Grover. 4
RSA-PSS Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 4
DSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 2
MD5 Already broken Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest. 2
EdDSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 2
RSAES-PKCS1v15 Already broken PKCS#1 v1.5 encryption padding is vulnerable to Bleichenbacher oracles today, and the underlying RSA is broken by Shor. 2
Ed25519 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 1
RSA-OAEP Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 1
RSASSA-PKCS1v15 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. The v1.5 signature scheme of RFC 8017 section 8.2 has no classical break of its own; RSA-PSS is preferred for new work, but the quantum exposure is the same for both. 1

Imported cryptographic libraries

Library Files
javax.net.ssl — the TLS client and server 55
org.bouncycastle — BouncyCastle, whose low-level API bypasses the JCA algorithm strings. It has shipped ML-KEM and ML-DSA since 1.79 40
org.ietf.jgss — GSS-API, usually Kerberos or SPNEGO 7
@noble/hashes — hash functions 1
java.security — the JCA — algorithms are selected by string 443