Skip to content

Commit

Permalink
Merge pull request #606 from WilburZjh/exportImportRSAKeys
Browse files Browse the repository at this point in the history
Support export/import plain keys for JDK8 in FIPS Mode
  • Loading branch information
keithc-ca authored Aug 22, 2022
2 parents f8e04d2 + 8581e8a commit f2a9dfa
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 1 deletion.
119 changes: 119 additions & 0 deletions jdk/src/share/classes/sun/security/pkcs11/P11Key.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
* questions.
*/

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
* ===========================================================================
*/

package sun.security.pkcs11;

import java.io.*;
Expand Down Expand Up @@ -366,6 +372,21 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
new CK_ATTRIBUTE(CKA_SENSITIVE),
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
});
if ((SunPKCS11.mysunpkcs11 != null) && "RSA".equals(algorithm)) {
if (attributes[0].getBoolean() || attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
try {
byte[] key = SunPKCS11.mysunpkcs11.exportKey(session.id(), attributes, keyID);
RSAPrivateKey rsaPrivKey = RSAPrivateCrtKeyImpl.newKey(key);
if (rsaPrivKey instanceof RSAPrivateCrtKeyImpl) {
return new P11RSAPrivateKeyFIPS(session, keyID, algorithm, keyLength, attributes, (RSAPrivateCrtKeyImpl)rsaPrivKey);
} else {
return new P11RSAPrivateNonCRTKeyFIPS(session, keyID, algorithm, keyLength, attributes, rsaPrivKey);
}
} catch (PKCS11Exception | InvalidKeyException e) {
// Attempt failed, create a P11PrivateKey object.
}
}
}
if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
return new P11PrivateKey
(session, keyID, algorithm, keyLength, attributes);
Expand Down Expand Up @@ -500,6 +521,70 @@ public int getMinorVersion() {
}
}

// RSA CRT private key when in FIPS mode
private static final class P11RSAPrivateKeyFIPS extends P11Key
implements RSAPrivateCrtKey {

private static final long serialVersionUID = 9215872438913515220L;
private final RSAPrivateCrtKeyImpl key;

P11RSAPrivateKeyFIPS(Session session, long keyID, String algorithm,
int keyLength, CK_ATTRIBUTE[] attrs, RSAPrivateCrtKeyImpl key) {
super(PRIVATE, session, keyID, algorithm, keyLength, attrs);
this.key = key;
}

@Override
public String getFormat() {
return "PKCS#8";
}

@Override
synchronized byte[] getEncodedInternal() {
return key.getEncoded();
}

@Override
public BigInteger getModulus() {
return key.getModulus();
}

@Override
public BigInteger getPublicExponent() {
return key.getPublicExponent();
}

@Override
public BigInteger getPrivateExponent() {
return key.getPrivateExponent();
}

@Override
public BigInteger getPrimeP() {
return key.getPrimeP();
}

@Override
public BigInteger getPrimeQ() {
return key.getPrimeQ();
}

@Override
public BigInteger getPrimeExponentP() {
return key.getPrimeExponentP();
}

@Override
public BigInteger getPrimeExponentQ() {
return key.getPrimeExponentQ();
}

@Override
public BigInteger getCrtCoefficient() {
return key.getCrtCoefficient();
}
}

// RSA CRT private key
private static final class P11RSAPrivateKey extends P11Key
implements RSAPrivateCrtKey {
Expand Down Expand Up @@ -588,6 +673,40 @@ public BigInteger getCrtCoefficient() {
}
}

// RSA non-CRT private key in FIPS mode
private static final class P11RSAPrivateNonCRTKeyFIPS extends P11Key
implements RSAPrivateKey {

private static final long serialVersionUID = 1137764983777411481L;
private final RSAPrivateKey key;

P11RSAPrivateNonCRTKeyFIPS(Session session, long keyID, String algorithm,
int keyLength, CK_ATTRIBUTE[] attributes, RSAPrivateKey key) {
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
this.key = key;
}

@Override
public String getFormat() {
return "PKCS#8";
}

@Override
synchronized byte[] getEncodedInternal() {
return key.getEncoded();
}

@Override
public BigInteger getModulus() {
return key.getModulus();
}

@Override
public BigInteger getPrivateExponent() {
return key.getPrivateExponent();
}
}

// RSA non-CRT private key
private static final class P11RSAPrivateNonCRTKey extends P11Key
implements RSAPrivateKey {
Expand Down
133 changes: 133 additions & 0 deletions jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,29 @@
* questions.
*/

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
* ===========================================================================
*/

package sun.security.pkcs11;

import java.io.*;
import java.util.*;

import java.security.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.interfaces.*;
import java.util.function.Consumer;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.interfaces.*;
import javax.crypto.spec.IvParameterSpec;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
Expand All @@ -42,10 +56,13 @@
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;

import openj9.internal.security.FIPSConfigurator;

import sun.security.util.Debug;
import sun.security.util.ResourcesMgr;

import sun.security.pkcs11.Secmod.*;
import sun.security.pkcs11.TemplateManager;

import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
Expand Down Expand Up @@ -89,6 +106,11 @@ public final class SunPKCS11 extends AuthProvider {

private TokenPoller poller;

// This is the SunPKCS11 provider instance
// there can only be a single PKCS11 provider in
// FIPS mode.
static SunPKCS11 mysunpkcs11;

Token getToken() {
return token;
}
Expand Down Expand Up @@ -368,6 +390,29 @@ public SunPKCS11(String configName, InputStream configStream) {
if (nssModule != null) {
nssModule.setProvider(this);
}

// When FIPS mode is enabled, configure p11 object to FIPS mode
// and pass the parent object so it can callback.
if (FIPSConfigurator.enableFIPS()) {
if (debug != null) {
System.out.println("FIPS mode in SunPKCS11");
}

@SuppressWarnings("unchecked")
Consumer<SunPKCS11> consumer = (Consumer<SunPKCS11>) p11;
consumer.accept(this);
mysunpkcs11 = this;

Session session = null;
try {
session = token.getOpSession();
p11.C_Login(session.id(), CKU_USER, new char[] {});
} catch (PKCS11Exception e) {
throw e;
} finally {
token.releaseSession(session);
}
}
} catch (Exception e) {
if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) {
throw new UnsupportedOperationException
Expand Down Expand Up @@ -404,6 +449,94 @@ private static String[] s(String ...aliases) {
return aliases;
}

byte[] exportKey(long hSession, CK_ATTRIBUTE[] attributes, long keyId) throws PKCS11Exception {
// Generating the secret key that will be used for wrapping and unwrapping.
CK_ATTRIBUTE[] wrapKeyAttributes = token.getAttributes(TemplateManager.O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3) });
Session wrapKeyGenSession = token.getObjSession();
P11Key wrapKey;

try {
long genKeyId = token.p11.C_GenerateKey(wrapKeyGenSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrapKeyAttributes);
wrapKey = (P11Key)P11Key.secretKey(wrapKeyGenSession, genKeyId, "AES", 256 >> 3, null);
} catch (PKCS11Exception e) {
throw e;
} finally {
token.releaseSession(wrapKeyGenSession);
}

// Wrapping the private key inside the PKCS11 device using the generated secret key.
CK_MECHANISM wrapMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, new byte[16]);
long wrapKeyId = wrapKey.getKeyID();
byte[] wrappedKeyBytes = token.p11.C_WrapKey(hSession, wrapMechanism, wrapKeyId, keyId);

// Unwrapping to obtain the private key.
byte[] unwrappedKeyBytes;
try {
Cipher unwrapCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
unwrapCipher.init(Cipher.DECRYPT_MODE, wrapKey, new IvParameterSpec((byte[])wrapMechanism.pParameter), null);
unwrappedKeyBytes = unwrapCipher.doFinal(wrappedKeyBytes);
return unwrappedKeyBytes;
} catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException e) {
throw new PKCS11Exception(CKR_GENERAL_ERROR);
} finally {
wrapKey.releaseKeyID();
}
}

long importKey(long hSession, CK_ATTRIBUTE[] attributes) throws PKCS11Exception {
long unwrappedKeyId, keyClass = 0, keyType = 0;
byte[] keyBytes = null;
// Extract key information.
for (CK_ATTRIBUTE attr : attributes) {
if (attr.type == CKA_CLASS) {
keyClass = attr.getLong();
}
if (attr.type == CKA_KEY_TYPE) {
keyType = attr.getLong();
}
if (attr.type == CKA_VALUE) {
keyBytes = attr.getByteArray();
}
}

if ((keyClass == CKO_SECRET_KEY) && (keyBytes != null) && (keyBytes.length > 0)) {
// Generate key used for wrapping and unwrapping of the secret key.
CK_ATTRIBUTE[] wrapKeyAttributes = token.getAttributes(TemplateManager.O_GENERATE, CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3)});
Session wrapKeyGenSession = token.getObjSession();
P11Key wrapKey;

try {
long keyId = token.p11.C_GenerateKey(wrapKeyGenSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrapKeyAttributes);
wrapKey = (P11Key)P11Key.secretKey(wrapKeyGenSession, keyId, "AES", 256 >> 3, null);
} catch (PKCS11Exception e) {
throw e;
} finally {
token.releaseSession(wrapKeyGenSession);
}

long wrapKeyId = wrapKey.getKeyID();
try {
// Wrap the external secret key.
CK_MECHANISM wrapMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, new byte[16]);
Cipher wrapCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
wrapCipher.init(Cipher.ENCRYPT_MODE, wrapKey, new IvParameterSpec((byte[])wrapMechanism.pParameter), null);
byte[] wrappedBytes = wrapCipher.doFinal(keyBytes);

// Unwrap the secret key.
CK_ATTRIBUTE[] unwrapAttributes = token.getAttributes(TemplateManager.O_IMPORT, keyClass, keyType, attributes);
unwrappedKeyId = token.p11.C_UnwrapKey(hSession, wrapMechanism, wrapKeyId, wrappedBytes, unwrapAttributes);
} catch (PKCS11Exception | NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException e) {
throw new PKCS11Exception(CKR_GENERAL_ERROR);
} finally {
wrapKey.releaseKeyID();
}
} else {
// Unsupported key type or invalid bytes.
throw new PKCS11Exception(CKR_GENERAL_ERROR);
}
return Long.valueOf(unwrappedKeyId);
}

private static final class Descriptor {
final String type;
final String algorithm;
Expand Down
Loading

0 comments on commit f2a9dfa

Please sign in to comment.