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

Reply via email to