Jdk 21 PKCS11 ECDH Key agreement failing

Valerie Peng valerie.peng at oracle.com
Mon Aug 19 18:06:42 UTC 2024


Yes, key value extraction is disallowed for PKCS11 provider in FIPS mode.
When you call KeyAgreement.generateSecret(), a native key is generated and its key value would be extracted and return which would be rejected for provider in FIPS mode. Please try the KeyAgreement.generateSecret(String) call which would not extract the key value and return the generated key which you'd use with the same provider afterwards.

Valerie

-----Original Message-----
From: security-dev <security-dev-retn at openjdk.org> On Behalf Of Daniel Jelinski
Sent: Sunday, August 18, 2024 10:52 PM
To: Pushkar Marathe <pushkar.marathe at strongkey.com>
Cc: security-dev at openjdk.org
Subject: Re: Jdk 21 PKCS11 ECDH Key agreement failing

Hi Pushkar,
The failure is not unexpected. In FIPS mode you are not allowed to extract secret keys, and ka.generateSecret() does just that.

Try:
SecretKey Z = ka.generateSecret("TlsPremasterSecret");
it should work even in FIPS mode.

CKD_NULL is valid when shared data is null, and I don't see why it would be disallowed in FIPS mode.
Regards,
Daniel

wt., 13 sie 2024 o 23:02 Pushkar Marathe <pushkar.marathe at strongkey.com> napisał(a):
>
> Hi
>
> I have some java code written using javax.crypto package which does a derivation using ht ECDH algorithm. This code is run against a HSM card and uses key pair on the hsm. Example code below:
>
>
> Provider CRYPTOKI_PROVIDER = Security.getProvider("SunPKCS11");
>             CRYPTOKI_PROVIDER = CRYPTOKI_PROVIDER.configure(PKCS11_CFG_LOCATION);
>             Security.addProvider(CRYPTOKI_PROVIDER);
>
> //Generate ephemeral EC key
>                 KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", BC_FIPS_PROVIDER);
>                 kpgen.initialize(new ECGenParameterSpec("secp256r1"), FIPS_DRBG);
>                 KeyPair keyPair = kpgen.generateKeyPair();
>                 ECPublicKey epubKey = (ECPublicKey) keyPair.getPublic();
>                 ECPrivateKey eprivKey = (ECPrivateKey) 
> keyPair.getPrivate();
>
>                 PublicKey pubkey = null;
>                 if (keystore.containsAlias("alias")) {
>                     pubkey = keystore.getCertificate(mapkey).getPublicKey();
>                 }
>
>                 if (pubkey == null) {
>                     cryptoCommon.logp(Level.WARNING, classname, "wrapSymmetricKey", "CRYPTO-ERR-1041", mapkey);
>                     throw new InvalidKeyException(mapkey);
>                 }
>
>                 KeyAgreement ka = KeyAgreement.getInstance("ECDH", CRYPTOKI_PROVIDER);
>                 ka.init(eprivKey, CRYPTOKI_RNG);
>                 ka.doPhase(pubkey, true);
>                 byte[] Z = ka.generateSecret();
>
>
> Now when the HSM has FIPS mode turned on, the same code above starts failing at the highlighted line above. I believe this is because of the ECDH1_DERIVE_PARAMS  because the default KDF used which is CKD_NULL is not allowed in FIPS mode. I couldnt find a way to change that to a FIPS approved param and make the code work.
>
> I was looking at some source code and found the code below in the file P11ECDHKeyAgreement.java (https://github.com/openjdk/jdk/blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java):
>
> protected byte[] engineGenerateSecret() throws IllegalStateException {
>         if ((privateKey == null) || (publicValue == null)) {
>             throw new IllegalStateException("Not initialized correctly");
>         }
>         Session session = null;
>         long privKeyID = privateKey.getKeyID();
>         try {
>             session = token.getOpSession();
>             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
>                 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
>                 new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET),
>             };
>             CK_ECDH1_DERIVE_PARAMS ckParams =
>                     new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue);
>             attributes = token.getAttributes
>                 (O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
>             long keyID = token.p11.C_DeriveKey(session.id(),
>                     new CK_MECHANISM(mechanism, ckParams), privKeyID,
>                     attributes);
>             attributes = new CK_ATTRIBUTE[] {
>                 new CK_ATTRIBUTE(CKA_VALUE)
>             };
>             token.p11.C_GetAttributeValue(session.id(), keyID, attributes);
>             byte[] secret = attributes[0].getByteArray();
>             token.p11.C_DestroyObject(session.id(), keyID);
>             return secret;
>         } catch (PKCS11Exception e) {
>             throw new ProviderException("Could not derive key", e);
>         } finally {
>             privateKey.releaseKeyID();
>             publicValue = null;
>             token.releaseSession(session);
>         }
>     }
>
>
> As we see here that the Params is taking CKD_NULL as the first param as highlighted below and i dont see code that lets me change that.
>
> Is there an approach i could take to make the above code work with HSM in FIPS mode and with the ability to change the params?
>
> There are some examples from the hsm provider which i was able to 
> modify to make it work but its not using javax.crypto but their 
> CRYPTOKI implementation. The way i made it work was to specify
>
> CK_ECDH1_DERIVE_PARAMS params
>                 = new CK_ECDH1_DERIVE_PARAMS(KDF.CKD_SHA224_NIST_KDF,
>                         "",
>                         ""
>                 );
>
> in the sample code to change the params. But i was looking for a way to do this with the java code i have.
>
>
> Thank you
> Pushkar


More information about the security-dev mailing list