Jdk 21 PKCS11 ECDH Key agreement failing

Pushkar Marathe pushkar.marathe at strongkey.com
Tue Aug 13 21:01:58 UTC 2024


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20240813/91f80916/attachment.htm>


More information about the security-dev mailing list