Skip to content

Commit

Permalink
PKCS#12 file-based Keystore support in FIPS mode
Browse files Browse the repository at this point in the history
Signed-off-by: Jinhang Zhang <Jinhang.Zhang@ibm.com>
  • Loading branch information
WilburZjh committed May 31, 2023
1 parent 9d6414e commit 3d9a685
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved
* ===========================================================================
*/

package com.sun.crypto.provider;

Expand Down Expand Up @@ -117,7 +122,7 @@ private static byte[] getPasswordBytes(char[] passwd) {
} else if (keyLength < 0) {
throw new InvalidKeySpecException("Key length is negative");
}
this.prf = Mac.getInstance(prfAlgo, SunJCE.getInstance());
this.prf = Mac.getInstance(prfAlgo);
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
} catch (NoSuchAlgorithmException nsae) {
// not gonna happen; re-throw just in case
Expand Down
44 changes: 43 additions & 1 deletion src/java.base/share/conf/security/java.security
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,53 @@ RestrictedSecurity1.jce.provider.2 = SUN [{CertificateFactory, X.509, Implemente
{CertStore, com.sun.security.IndexedCollection, ImplementedIn=Software}, \
{Policy, JavaPolicy, *}, {Configuration, JavaLoginConfig, *}, \
{CertPathBuilder, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \
{CertPathValidator, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}]
{CertPathValidator, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \
{KeyStore, PKCS12, *}]
RestrictedSecurity1.jce.provider.3 = SunEC [{KeyFactory, EC, ImplementedIn=Software: \
SupportedKeyClasses=java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey: \
KeySize=256}, {AlgorithmParameters, EC, *}]
RestrictedSecurity1.jce.provider.4 = SunJSSE
RestrictedSecurity1.jce.provider.5 = SunJCE [{AlgorithmParameters, PBES2, *}, \
{AlgorithmParameters, PBEWithHmacSHA1AndAES_128, *}, \
{AlgorithmParameters, PBEWithHmacSHA1AndAES_256, *}, \
{AlgorithmParameters, PBEWithHmacSHA224AndAES_128, *}, \
{AlgorithmParameters, PBEWithHmacSHA224AndAES_256, *}, \
{AlgorithmParameters, PBEWithHmacSHA256AndAES_128, *}, \
{AlgorithmParameters, PBEWithHmacSHA256AndAES_256, *}, \
{AlgorithmParameters, PBEWithHmacSHA384AndAES_128, *}, \
{AlgorithmParameters, PBEWithHmacSHA384AndAES_256, *}, \
{AlgorithmParameters, PBEWithHmacSHA512AndAES_128, *}, \
{AlgorithmParameters, PBEWithHmacSHA512AndAES_256, *}, \
{Cipher, PBEWithHmacSHA1AndAES_128, *}, \
{Cipher, PBEWithHmacSHA1AndAES_256, *}, \
{Cipher, PBEWithHmacSHA224AndAES_128, *}, \
{Cipher, PBEWithHmacSHA224AndAES_256, *}, \
{Cipher, PBEWithHmacSHA256AndAES_128, *}, \
{Cipher, PBEWithHmacSHA256AndAES_256, *}, \
{Cipher, PBEWithHmacSHA384AndAES_128, *}, \
{Cipher, PBEWithHmacSHA384AndAES_256, *}, \
{Cipher, PBEWithHmacSHA512AndAES_128, *}, \
{Cipher, PBEWithHmacSHA512AndAES_256, *}, \
{Mac, HmacPBESHA1, *}, \
{Mac, HmacPBESHA224, *}, \
{Mac, HmacPBESHA256, *}, \
{Mac, HmacPBESHA384, *}, \
{Mac, HmacPBESHA512, *}, \
{Mac, PBEWithHmacSHA1, *}, \
{Mac, PBEWithHmacSHA224, *}, \
{Mac, PBEWithHmacSHA256, *}, \
{Mac, PBEWithHmacSHA384, *}, \
{Mac, PBEWithHmacSHA512, *}, \
{SecretKeyFactory, PBEWithHmacSHA1AndAES_128, *}, \
{SecretKeyFactory, PBEWithHmacSHA1AndAES_256, *}, \
{SecretKeyFactory, PBEWithHmacSHA224AndAES_128, *}, \
{SecretKeyFactory, PBEWithHmacSHA224AndAES_256, *}, \
{SecretKeyFactory, PBEWithHmacSHA256AndAES_128, *}, \
{SecretKeyFactory, PBEWithHmacSHA256AndAES_256, *}, \
{SecretKeyFactory, PBEWithHmacSHA384AndAES_128, *}, \
{SecretKeyFactory, PBEWithHmacSHA384AndAES_256, *}, \
{SecretKeyFactory, PBEWithHmacSHA512AndAES_128, *}, \
{SecretKeyFactory, PBEWithHmacSHA512AndAES_256, *}]

RestrictedSecurity1.keystore.type = PKCS11
RestrictedSecurity1.javax.net.ssl.keyStore = NONE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import static sun.security.pkcs11.TemplateManager.O_GENERATE;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;

import sun.security.util.Debug;
import sun.security.util.DerValue;
import sun.security.util.Length;
import sun.security.util.ECUtil;
Expand All @@ -78,6 +79,8 @@ abstract class P11Key implements Key, Length {
@Serial
private static final long serialVersionUID = -2575874101938349339L;

private static final Debug debug = Debug.getInstance("p11key");

private static final String PUBLIC = "public";
private static final String PRIVATE = "private";
private static final String SECRET = "secret";
Expand Down Expand Up @@ -411,6 +414,22 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
}
} catch (PKCS11Exception | InvalidKeyException e) {
// Attempt failed, create a P11PrivateKey object.
if (debug != null) {
debug.println("Attempt failed, creating a P11PrivateKey object for RSA");
}
}
}

if (keySensitive && (SunPKCS11.mysunpkcs11 != null) && "EC".equals(algorithm)) {
try {
byte[] key = SunPKCS11.mysunpkcs11.exportKey(session.id(), attrs, keyID);
ECPrivateKey ecPrivKey = ECUtil.decodePKCS8ECPrivateKey(key);
return new P11ECPrivateKeyFIPS(session, keyID, algorithm, keyLength, attrs, ecPrivKey);
} catch (PKCS11Exception | InvalidKeySpecException e) {
// Attempt failed, create a P11PrivateKey object.
if (debug != null) {
debug.println("Attempt failed, creating a P11PrivateKey object for EC");
}
}
}

Expand Down Expand Up @@ -1283,6 +1302,39 @@ protected ECParameterSpec getParams() {
}
}

// EC private key when in FIPS mode
private static final class P11ECPrivateKeyFIPS extends P11Key
implements ECPrivateKey {
private static final long serialVersionUID = -7786054399510515515L;
private final ECPrivateKey key;

P11ECPrivateKeyFIPS(Session session, long keyID, String algorithm,
int keyLength, CK_ATTRIBUTE[] attrs, ECPrivateKey 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 getS() {
return key.getS();
}

@Override
public ECParameterSpec getParams() {
return key.getParams();
}
}

private static final class P11ECPrivateKey extends P11ECPrivateKeyInternal
implements ECPrivateKey {
@Serial
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@

import java.io.*;
import java.util.*;
import java.math.BigInteger;

import java.security.*;
import java.security.interfaces.*;
import java.security.spec.InvalidKeySpecException;
import java.util.function.Consumer;

import javax.crypto.BadPaddingException;
Expand All @@ -56,14 +58,17 @@

import jdk.internal.misc.InnocuousThread;
import openj9.internal.security.RestrictedSecurity;
import sun.security.rsa.RSAUtil.KeyType;
import sun.security.util.Debug;
import sun.security.util.ECUtil;
import sun.security.util.ResourcesMgr;
import static sun.security.util.SecurityConstants.PROVIDER_VER;
import static sun.security.util.SecurityProviderConstants.getAliases;

import sun.security.pkcs11.Secmod.*;
import sun.security.pkcs11.TemplateManager;
import sun.security.pkcs11.wrapper.*;
import sun.security.rsa.RSAPrivateCrtKeyImpl;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*;

Expand Down Expand Up @@ -527,10 +532,17 @@ byte[] exportKey(long hSession, CK_ATTRIBUTE[] attributes, long keyId) throws PK
}
}

private static BigInteger getBigIntegerOrZero(Map<Long, CK_ATTRIBUTE> ckAttrsMap, long attributeType) {
CK_ATTRIBUTE attribute = ckAttrsMap.get(attributeType);
return (attribute != null) ? attribute.getBigInteger() : BigInteger.ZERO;
}

public long importKey(long hSession, CK_ATTRIBUTE[] attributes) throws PKCS11Exception {
long keyClass = 0;
long keyType = 0;
byte[] keyBytes = null;
Map<Long, CK_ATTRIBUTE> ckAttrsMap = new HashMap<>();

// Extract key information.
for (CK_ATTRIBUTE attr : attributes) {
if (attr.type == CKA_CLASS) {
Expand All @@ -539,12 +551,60 @@ public long importKey(long hSession, CK_ATTRIBUTE[] attributes) throws PKCS11Exc
if (attr.type == CKA_KEY_TYPE) {
keyType = attr.getLong();
}
if (attr.type == CKA_VALUE) {
keyBytes = attr.getByteArray();
ckAttrsMap.put(attr.type, attr);
}

if (keyClass == CKO_PRIVATE_KEY) {
if (keyType == CKK_RSA) {
try {
keyBytes = RSAPrivateCrtKeyImpl.newKey(
KeyType.RSA,
null,
getBigIntegerOrZero(ckAttrsMap, CKA_MODULUS),
getBigIntegerOrZero(ckAttrsMap, CKA_PUBLIC_EXPONENT),
getBigIntegerOrZero(ckAttrsMap, CKA_PRIVATE_EXPONENT),
getBigIntegerOrZero(ckAttrsMap, CKA_PRIME_1),
getBigIntegerOrZero(ckAttrsMap, CKA_PRIME_2),
getBigIntegerOrZero(ckAttrsMap, CKA_EXPONENT_1),
getBigIntegerOrZero(ckAttrsMap, CKA_EXPONENT_2),
getBigIntegerOrZero(ckAttrsMap, CKA_COEFFICIENT)
).getEncoded();
} catch (InvalidKeyException e) {
throw new PKCS11Exception(0x00000005L, null);
}
} else if (keyType == CKK_EC) {
CK_ATTRIBUTE ckaECParams = ckAttrsMap.get(CKA_EC_PARAMS);
if (ckaECParams == null) {
throw new PKCS11Exception(0x00000005L, "CKA_EC_PARAMS attribute is missing");
}
try {
keyBytes = ECUtil.generateECPrivateKey(
getBigIntegerOrZero(ckAttrsMap, CKA_VALUE),
ECUtil.getECParameterSpec(
Security.getProvider("SunEC"),
ckaECParams.getByteArray())
).getEncoded();
// If key is private and of EC type, NSS may require CKA_NETSCAPE_DB
// attribute to unwrap it. Otherwise, C_UnwrapKey will produce an Exception.
if (token.config.getNssNetscapeDbWorkaround() && !ckAttrsMap.containsKey(CKA_NETSCAPE_DB)) {
ckAttrsMap.put(CKA_NETSCAPE_DB, new CK_ATTRIBUTE(CKA_NETSCAPE_DB, BigInteger.ZERO));
}
} catch (IOException | InvalidKeySpecException e) {
throw new PKCS11Exception(0x00000005L, null);
}
}
} else if (keyClass == CKO_SECRET_KEY) {
CK_ATTRIBUTE ckaValue = ckAttrsMap.get(CKA_VALUE);
if (ckaValue == null) {
throw new PKCS11Exception(0x00000005L, "CKA_VALUE attribute is missing");
}
keyBytes = ckaValue.getByteArray();
}

if ((keyClass == CKO_SECRET_KEY) && (keyBytes != null) && (keyBytes.length > 0)) {
if ((keyBytes != null) && (keyBytes.length > 0)
&& ((keyClass == CKO_SECRET_KEY)
|| ((keyClass == CKO_PRIVATE_KEY) && ((keyType == CKK_EC) || (keyType == CKK_RSA))))
) {
// 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();
Expand All @@ -568,7 +628,12 @@ public long importKey(long hSession, CK_ATTRIBUTE[] attributes) throws PKCS11Exc
byte[] wrappedBytes = wrapCipher.doFinal(keyBytes);

// Unwrap the secret key.
CK_ATTRIBUTE[] unwrapAttributes = token.getAttributes(TemplateManager.O_IMPORT, keyClass, keyType, attributes);
// Need additional attributes for EC private key.
CK_ATTRIBUTE[] unwrapAttributes = token.getAttributes(
TemplateManager.O_IMPORT,
keyClass,
keyType,
ckAttrsMap.values().toArray(new CK_ATTRIBUTE[ckAttrsMap.size()]));
return token.p11.C_UnwrapKey(hSession, wrapMechanism, wrapKeyId, wrappedBytes, unwrapAttributes);
} catch (PKCS11Exception | NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException e) {
throw new PKCS11Exception(0x00000005L, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,26 @@ public static void loadNative() {
new HashMap<String,PKCS11>();

static boolean isKey(CK_ATTRIBUTE[] attrs) {
for (CK_ATTRIBUTE attr : attrs) {
if ((attr.type == CKA_CLASS) && (attr.getLong() == CKO_SECRET_KEY)) {
return true;
boolean isPrivateKey = false;
boolean hasKey = false;

for (CK_ATTRIBUTE attr : attrs) {
if (attr.type == CKA_CLASS) {
if (attr.getLong() == CKO_SECRET_KEY) {
return true;
} else if (attr.getLong() == CKO_PRIVATE_KEY) {
isPrivateKey = true;
}
} else if (attr.type == CKA_KEY_TYPE) {
hasKey = true;
if (!((attr.getLong() == CKK_RSA) || (attr.getLong() == CKK_EC))) {
isPrivateKey = false;
}
}
}

return isPrivateKey && hasKey;
}
return false;
}

// This is the SunPKCS11 provider instance
// there can only be a single PKCS11 provider in
Expand Down

0 comments on commit 3d9a685

Please sign in to comment.