Jdk 21 PKCS11 ECDH Key agreement failing

Daniel Jeliński djelinski1 at gmail.com
Mon Aug 19 05:52:03 UTC 2024


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