Skip to content

Commit 6ac8ac9

Browse files
committed
Support export/import plain keys in FIPS Mode for JDK17
Signed-off-by: Jinhang Zhang <[email protected]>
1 parent f937c26 commit 6ac8ac9

File tree

5 files changed

+314
-2
lines changed

5 files changed

+314
-2
lines changed

src/java.base/share/classes/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@
372372
exports jdk.internal.invoke to
373373
jdk.incubator.foreign;
374374
exports openj9.internal.security to
375+
jdk.crypto.cryptoki,
375376
jdk.crypto.ec;
376377

377378
// the service types defined by the APIs in this module

src/java.base/share/lib/security/default.policy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ grant codeBase "jrt:/jdk.crypto.cryptoki" {
154154
"accessClassInPackage.sun.security.*";
155155
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
156156
permission java.lang.RuntimePermission "loadLibrary.j2pkcs11";
157+
permission java.lang.RuntimePermission
158+
"accessClassInPackage.openj9.internal.security";
157159
permission java.util.PropertyPermission "sun.security.pkcs11.allowSingleThreadedModules", "read";
158160
permission java.util.PropertyPermission "sun.security.pkcs11.disableKeyExtraction", "read";
159161
permission java.util.PropertyPermission "os.name", "read";

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
* questions.
2424
*/
2525

26+
/*
27+
* ===========================================================================
28+
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
29+
* ===========================================================================
30+
*/
31+
2632
package sun.security.pkcs11;
2733

2834
import java.io.*;
@@ -380,6 +386,19 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
380386
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
381387
});
382388
if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
389+
if ((SunPKCS11.mysunpkcs11 != null) && "RSA".equals(algorithm)) {
390+
try {
391+
byte[] key = SunPKCS11.mysunpkcs11.exportKey(session.id(), attributes, keyID);
392+
RSAPrivateKey rsaPrivKey = RSAPrivateCrtKeyImpl.newKey(KeyType.RSA, "PKCS#8", key);
393+
if (rsaPrivKey instanceof RSAPrivateCrtKeyImpl privImpl) {
394+
return new P11RSAPrivateKeyFIPS(session, keyID, algorithm, keyLength, attributes, privImpl);
395+
} else {
396+
return new P11RSAPrivateNonCRTKeyFIPS(session, keyID, algorithm, keyLength, attributes, rsaPrivKey);
397+
}
398+
} catch (PKCS11Exception | InvalidKeyException e) {
399+
// Attempt failed, create a P11PrivateKey object.
400+
}
401+
}
383402
return new P11PrivateKey
384403
(session, keyID, algorithm, keyLength, attributes);
385404
} else {
@@ -522,6 +541,70 @@ public int getMinorVersion() {
522541
}
523542
}
524543

544+
// RSA CRT private key when in FIPS mode
545+
private static final class P11RSAPrivateKeyFIPS extends P11Key
546+
implements RSAPrivateCrtKey {
547+
548+
private static final long serialVersionUID = 9215872438913515220L;
549+
private final RSAPrivateCrtKeyImpl key;
550+
551+
P11RSAPrivateKeyFIPS(Session session, long keyID, String algorithm,
552+
int keyLength, CK_ATTRIBUTE[] attrs, RSAPrivateCrtKeyImpl key) {
553+
super(PRIVATE, session, keyID, algorithm, keyLength, attrs);
554+
this.key = key;
555+
}
556+
557+
@Override
558+
public String getFormat() {
559+
return "PKCS#8";
560+
}
561+
562+
@Override
563+
synchronized byte[] getEncodedInternal() {
564+
return key.getEncoded();
565+
}
566+
567+
@Override
568+
public BigInteger getModulus() {
569+
return key.getModulus();
570+
}
571+
572+
@Override
573+
public BigInteger getPublicExponent() {
574+
return key.getPublicExponent();
575+
}
576+
577+
@Override
578+
public BigInteger getPrivateExponent() {
579+
return key.getPrivateExponent();
580+
}
581+
582+
@Override
583+
public BigInteger getPrimeP() {
584+
return key.getPrimeP();
585+
}
586+
587+
@Override
588+
public BigInteger getPrimeQ() {
589+
return key.getPrimeQ();
590+
}
591+
592+
@Override
593+
public BigInteger getPrimeExponentP() {
594+
return key.getPrimeExponentP();
595+
}
596+
597+
@Override
598+
public BigInteger getPrimeExponentQ() {
599+
return key.getPrimeExponentQ();
600+
}
601+
602+
@Override
603+
public BigInteger getCrtCoefficient() {
604+
return key.getCrtCoefficient();
605+
}
606+
}
607+
525608
// RSA CRT private key
526609
private static final class P11RSAPrivateKey extends P11Key
527610
implements RSAPrivateCrtKey {
@@ -609,6 +692,40 @@ public BigInteger getCrtCoefficient() {
609692
}
610693
}
611694

695+
// RSA non-CRT private key in FIPS mode
696+
private static final class P11RSAPrivateNonCRTKeyFIPS extends P11Key
697+
implements RSAPrivateKey {
698+
699+
private static final long serialVersionUID = 1137764983777411481L;
700+
private final RSAPrivateKey key;
701+
702+
P11RSAPrivateNonCRTKeyFIPS(Session session, long keyID, String algorithm,
703+
int keyLength, CK_ATTRIBUTE[] attributes, RSAPrivateKey key) {
704+
super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
705+
this.key = key;
706+
}
707+
708+
@Override
709+
public String getFormat() {
710+
return "PKCS#8";
711+
}
712+
713+
@Override
714+
synchronized byte[] getEncodedInternal() {
715+
return key.getEncoded();
716+
}
717+
718+
@Override
719+
public BigInteger getModulus() {
720+
return key.getModulus();
721+
}
722+
723+
@Override
724+
public BigInteger getPrivateExponent() {
725+
return key.getPrivateExponent();
726+
}
727+
}
728+
612729
// RSA non-CRT private key
613730
private static final class P11RSAPrivateNonCRTKey extends P11Key
614731
implements RSAPrivateKey {

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,29 @@
2323
* questions.
2424
*/
2525

26+
/*
27+
* ===========================================================================
28+
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
29+
* ===========================================================================
30+
*/
31+
2632
package sun.security.pkcs11;
2733

2834
import java.io.*;
2935
import java.util.*;
3036

3137
import java.security.*;
38+
import java.security.InvalidAlgorithmParameterException;
39+
import java.security.InvalidKeyException;
3240
import java.security.interfaces.*;
41+
import java.util.function.Consumer;
3342

43+
import javax.crypto.BadPaddingException;
44+
import javax.crypto.Cipher;
45+
import javax.crypto.IllegalBlockSizeException;
46+
import javax.crypto.NoSuchPaddingException;
3447
import javax.crypto.interfaces.*;
48+
import javax.crypto.spec.IvParameterSpec;
3549

3650
import javax.security.auth.Subject;
3751
import javax.security.auth.login.LoginException;
@@ -43,13 +57,14 @@
4357
import com.sun.crypto.provider.ChaCha20Poly1305Parameters;
4458

4559
import jdk.internal.misc.InnocuousThread;
60+
import openj9.internal.security.FIPSConfigurator;
4661
import sun.security.util.Debug;
4762
import sun.security.util.ResourcesMgr;
4863
import static sun.security.util.SecurityConstants.PROVIDER_VER;
4964
import static sun.security.util.SecurityProviderConstants.getAliases;
5065

5166
import sun.security.pkcs11.Secmod.*;
52-
67+
import sun.security.pkcs11.TemplateManager;
5368
import sun.security.pkcs11.wrapper.*;
5469
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
5570
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
@@ -89,6 +104,11 @@ public final class SunPKCS11 extends AuthProvider {
89104

90105
static NativeResourceCleaner cleaner;
91106

107+
// This is the SunPKCS11 provider instance
108+
// there can only be a single PKCS11 provider in
109+
// FIPS mode.
110+
static SunPKCS11 mysunpkcs11;
111+
92112
Token getToken() {
93113
return token;
94114
}
@@ -379,6 +399,29 @@ private static <T> T checkNull(T obj) {
379399
if (nssModule != null) {
380400
nssModule.setProvider(this);
381401
}
402+
403+
// When FIPS mode is enabled, configure p11 object to FIPS mode
404+
// and pass the parent object so it can callback.
405+
if (FIPSConfigurator.enableFIPS()) {
406+
if (debug != null) {
407+
System.out.println("FIPS mode in SunPKCS11");
408+
}
409+
410+
@SuppressWarnings("unchecked")
411+
Consumer<SunPKCS11> consumer = (Consumer<SunPKCS11>) p11;
412+
consumer.accept(this);
413+
mysunpkcs11 = this;
414+
415+
Session session = null;
416+
try {
417+
session = token.getOpSession();
418+
p11.C_Login(session.id(), CKU_USER, new char[] {});
419+
} catch (PKCS11Exception e) {
420+
throw e;
421+
} finally {
422+
token.releaseSession(session);
423+
}
424+
}
382425
} catch (Exception e) {
383426
if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) {
384427
throw new UnsupportedOperationException
@@ -411,6 +454,94 @@ public int hashCode() {
411454
return System.identityHashCode(this);
412455
}
413456

457+
byte[] exportKey(long hSession, CK_ATTRIBUTE[] attributes, long keyId) throws PKCS11Exception {
458+
// Generating the secret key that will be used for wrapping and unwrapping.
459+
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) });
460+
Session wrapKeyGenSession = token.getObjSession();
461+
P11Key wrapKey;
462+
463+
try {
464+
long genKeyId = token.p11.C_GenerateKey(wrapKeyGenSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrapKeyAttributes);
465+
wrapKey = (P11Key)P11Key.secretKey(wrapKeyGenSession, genKeyId, "AES", 256 >> 3, null);
466+
} catch (PKCS11Exception e) {
467+
throw e;
468+
} finally {
469+
token.releaseSession(wrapKeyGenSession);
470+
}
471+
472+
// Wrapping the private key inside the PKCS11 device using the generated secret key.
473+
CK_MECHANISM wrapMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, new byte[16]);
474+
long wrapKeyId = wrapKey.getKeyID();
475+
byte[] wrappedKeyBytes = token.p11.C_WrapKey(hSession, wrapMechanism, wrapKeyId, keyId);
476+
477+
// Unwrapping to obtain the private key.
478+
byte[] unwrappedKeyBytes;
479+
try {
480+
Cipher unwrapCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
481+
unwrapCipher.init(Cipher.DECRYPT_MODE, wrapKey, new IvParameterSpec((byte[])wrapMechanism.pParameter), null);
482+
unwrappedKeyBytes = unwrapCipher.doFinal(wrappedKeyBytes);
483+
return unwrappedKeyBytes;
484+
} catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException e) {
485+
throw new PKCS11Exception(CKR_GENERAL_ERROR, null);
486+
} finally {
487+
wrapKey.releaseKeyID();
488+
}
489+
}
490+
491+
long importKey(long hSession, CK_ATTRIBUTE[] attributes) throws PKCS11Exception {
492+
long unwrappedKeyId, keyClass = 0, keyType = 0;
493+
byte[] keyBytes = null;
494+
// Extract key information.
495+
for (CK_ATTRIBUTE attr : attributes) {
496+
if (attr.type == CKA_CLASS) {
497+
keyClass = attr.getLong();
498+
}
499+
if (attr.type == CKA_KEY_TYPE) {
500+
keyType = attr.getLong();
501+
}
502+
if (attr.type == CKA_VALUE) {
503+
keyBytes = attr.getByteArray();
504+
}
505+
}
506+
507+
if ((keyClass == CKO_SECRET_KEY) && (keyBytes != null) && (keyBytes.length > 0)) {
508+
// Generate key used for wrapping and unwrapping of the secret key.
509+
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)});
510+
Session wrapKeyGenSession = token.getObjSession();
511+
P11Key wrapKey;
512+
513+
try {
514+
long keyId = token.p11.C_GenerateKey(wrapKeyGenSession.id(), new CK_MECHANISM(CKM_AES_KEY_GEN), wrapKeyAttributes);
515+
wrapKey = (P11Key)P11Key.secretKey(wrapKeyGenSession, keyId, "AES", 256 >> 3, null);
516+
} catch (PKCS11Exception e) {
517+
throw e;
518+
} finally {
519+
token.releaseSession(wrapKeyGenSession);
520+
}
521+
522+
long wrapKeyId = wrapKey.getKeyID();
523+
try {
524+
// Wrap the external secret key.
525+
CK_MECHANISM wrapMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, new byte[16]);
526+
Cipher wrapCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
527+
wrapCipher.init(Cipher.ENCRYPT_MODE, wrapKey, new IvParameterSpec((byte[])wrapMechanism.pParameter), null);
528+
byte[] wrappedBytes = wrapCipher.doFinal(keyBytes);
529+
530+
// Unwrap the secret key.
531+
CK_ATTRIBUTE[] unwrapAttributes = token.getAttributes(TemplateManager.O_IMPORT, keyClass, keyType, attributes);
532+
unwrappedKeyId = token.p11.C_UnwrapKey(hSession, wrapMechanism, wrapKeyId, wrappedBytes, unwrapAttributes);
533+
} catch (PKCS11Exception | NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | IllegalBlockSizeException e) {
534+
throw new PKCS11Exception(CKR_GENERAL_ERROR, null);
535+
} finally {
536+
wrapKey.releaseKeyID();
537+
}
538+
} else {
539+
// Unsupported key type or invalid bytes.
540+
throw new PKCS11Exception(CKR_GENERAL_ERROR, null);
541+
}
542+
return Long.valueOf(unwrappedKeyId);
543+
}
544+
414545
private static final class Descriptor {
415546
final String type;
416547
final String algorithm;

0 commit comments

Comments
 (0)