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