Skip to content

Commit 46ffa10

Browse files
franferraxmartinuyakashche
committed
RH2023467: Enable FIPS keys export
Backport-Of: rh-openjdk/jdk@bd324bd Co-Authored-By: Martin Balao <[email protected]> Co-Authored-By: Alex Kashchenko <[email protected]>
1 parent ff26db7 commit 46ffa10

File tree

5 files changed

+387
-33
lines changed

5 files changed

+387
-33
lines changed

src/java.base/share/classes/sun/security/rsa/SunRsaSignEntries.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,13 @@ public SunRsaSignEntries(Provider p) {
6565
attrs.put("SupportedKeyClasses",
6666
"java.security.interfaces.RSAPublicKey" +
6767
"|java.security.interfaces.RSAPrivateKey");
68+
}
6869

69-
add(p, "KeyFactory", "RSA",
70-
"sun.security.rsa.RSAKeyFactory$Legacy",
71-
rsaAliases, null);
70+
add(p, "KeyFactory", "RSA",
71+
"sun.security.rsa.RSAKeyFactory$Legacy",
72+
rsaAliases, null);
73+
74+
if (!systemFipsEnabled) {
7275
add(p, "KeyPairGenerator", "RSA",
7376
"sun.security.rsa.RSAKeyPairGenerator$Legacy",
7477
rsaAliases, null);
@@ -99,10 +102,13 @@ public SunRsaSignEntries(Provider p) {
99102
add(p, "Signature", "SHA512/256withRSA",
100103
"sun.security.rsa.RSASignature$SHA512_256withRSA",
101104
createAliasesWithOid(rsaOid + ".16"), attrs);
105+
}
102106

103-
add(p, "KeyFactory", "RSASSA-PSS",
104-
"sun.security.rsa.RSAKeyFactory$PSS",
105-
rsapssAliases, null);
107+
add(p, "KeyFactory", "RSASSA-PSS",
108+
"sun.security.rsa.RSAKeyFactory$PSS",
109+
rsapssAliases, null);
110+
111+
if (!systemFipsEnabled) {
106112
add(p, "KeyPairGenerator", "RSASSA-PSS",
107113
"sun.security.rsa.RSAKeyPairGenerator$PSS",
108114
rsapssAliases, null);

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

Lines changed: 211 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@
2929
import java.security.KeyFactory;
3030
import java.security.Provider;
3131
import java.security.Security;
32+
import java.security.interfaces.RSAPrivateCrtKey;
33+
import java.security.interfaces.RSAPrivateKey;
3234
import java.util.HashMap;
3335
import java.util.Map;
3436
import java.util.concurrent.locks.ReentrantLock;
3537

3638
import javax.crypto.Cipher;
39+
import javax.crypto.SecretKeyFactory;
40+
import javax.crypto.spec.SecretKeySpec;
3741
import javax.crypto.spec.DHPrivateKeySpec;
3842
import javax.crypto.spec.IvParameterSpec;
3943

@@ -43,6 +47,8 @@
4347
import sun.security.pkcs11.wrapper.CK_MECHANISM;
4448
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
4549
import sun.security.pkcs11.wrapper.PKCS11Exception;
50+
import sun.security.rsa.RSAPrivateCrtKeyImpl;
51+
import sun.security.rsa.RSAUtil;
4652
import sun.security.rsa.RSAUtil.KeyType;
4753
import sun.security.util.Debug;
4854
import sun.security.util.ECUtil;
@@ -52,15 +58,21 @@ final class FIPSKeyImporter {
5258
private static final Debug debug =
5359
Debug.getInstance("sunpkcs11");
5460

55-
private static P11Key importerKey = null;
61+
private static volatile P11Key importerKey = null;
62+
private static SecretKeySpec exporterKey = null;
63+
private static volatile P11Key exporterKeyP11 = null;
5664
private static final ReentrantLock importerKeyLock = new ReentrantLock();
57-
private static CK_MECHANISM importerKeyMechanism = null;
65+
// Do not take the exporterKeyLock with the importerKeyLock held.
66+
private static final ReentrantLock exporterKeyLock = new ReentrantLock();
67+
private static volatile CK_MECHANISM importerKeyMechanism = null;
68+
private static volatile CK_MECHANISM exporterKeyMechanism = null;
5869
private static Cipher importerCipher = null;
70+
private static Cipher exporterCipher = null;
5971

60-
private static Provider sunECProvider = null;
72+
private static volatile Provider sunECProvider = null;
6173
private static final ReentrantLock sunECProviderLock = new ReentrantLock();
6274

63-
private static KeyFactory DHKF = null;
75+
private static volatile KeyFactory DHKF = null;
6476
private static final ReentrantLock DHKFLock = new ReentrantLock();
6577

6678
static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attributes)
@@ -84,7 +96,8 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
8496
debug.println("Importer Key could not be" +
8597
" generated.");
8698
}
87-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
99+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
100+
" fips key importer");
88101
}
89102
if (debug != null) {
90103
debug.println("Importer Key successfully" +
@@ -212,7 +225,8 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
212225
if (debug != null) {
213226
debug.println("Unrecognized private key type.");
214227
}
215-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
228+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
229+
" fips key importer");
216230
}
217231
} else if (keyClass == CKO_SECRET_KEY) {
218232
if (debug != null) {
@@ -225,14 +239,19 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
225239
debug.println("Private or secret key plain bytes could" +
226240
" not be obtained. Import failed.");
227241
}
228-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
242+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
243+
" fips key importer");
229244
}
230-
importerCipher.init(Cipher.ENCRYPT_MODE, importerKey,
231-
new IvParameterSpec((byte[])importerKeyMechanism.pParameter),
232-
null);
233245
attributes = new CK_ATTRIBUTE[attrsMap.size()];
234246
attrsMap.values().toArray(attributes);
235-
encKeyBytes = importerCipher.doFinal(keyBytes);
247+
importerKeyLock.lock();
248+
try {
249+
// No need to reset the cipher object because no multi-part
250+
// operations are performed.
251+
encKeyBytes = importerCipher.doFinal(keyBytes);
252+
} finally {
253+
importerKeyLock.unlock();
254+
}
236255
attributes = token.getAttributes(TemplateManager.O_IMPORT,
237256
keyClass, keyType, attributes);
238257
keyID = token.p11.C_UnwrapKey(hSession,
@@ -241,13 +260,155 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
241260
debug.println("Imported key ID: " + keyID);
242261
}
243262
} catch (Throwable t) {
244-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
263+
if (t instanceof PKCS11Exception) {
264+
throw (PKCS11Exception)t;
265+
}
266+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
267+
t.getMessage());
245268
} finally {
246269
importerKey.releaseKeyID();
247270
}
248271
return Long.valueOf(keyID);
249272
}
250273

274+
static void exportKey(SunPKCS11 sunPKCS11, long hSession, long hObject,
275+
long keyClass, long keyType, Map<Long, CK_ATTRIBUTE> sensitiveAttrs)
276+
throws PKCS11Exception {
277+
Token token = sunPKCS11.getToken();
278+
if (debug != null) {
279+
debug.println("Private or Secret key will be exported in" +
280+
" system FIPS mode.");
281+
}
282+
if (exporterKeyP11 == null) {
283+
try {
284+
exporterKeyLock.lock();
285+
if (exporterKeyP11 == null) {
286+
if (exporterKeyMechanism == null) {
287+
// Exporter Key creation has not been tried yet. Try it.
288+
createExporterKey(token);
289+
}
290+
if (exporterKeyP11 == null || exporterCipher == null) {
291+
if (debug != null) {
292+
debug.println("Exporter Key could not be" +
293+
" generated.");
294+
}
295+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
296+
" fips key exporter");
297+
}
298+
if (debug != null) {
299+
debug.println("Exporter Key successfully" +
300+
" generated.");
301+
}
302+
}
303+
} finally {
304+
exporterKeyLock.unlock();
305+
}
306+
}
307+
long exporterKeyID = exporterKeyP11.getKeyID();
308+
try {
309+
byte[] wrappedKeyBytes = token.p11.C_WrapKey(hSession,
310+
exporterKeyMechanism, exporterKeyID, hObject);
311+
byte[] plainExportedKey = null;
312+
exporterKeyLock.lock();
313+
try {
314+
// No need to reset the cipher object because no multi-part
315+
// operations are performed.
316+
plainExportedKey = exporterCipher.doFinal(wrappedKeyBytes);
317+
} finally {
318+
exporterKeyLock.unlock();
319+
}
320+
if (keyClass == CKO_PRIVATE_KEY) {
321+
exportPrivateKey(sensitiveAttrs, keyType, plainExportedKey);
322+
} else if (keyClass == CKO_SECRET_KEY) {
323+
checkAttrs(sensitiveAttrs, "CKO_SECRET_KEY", CKA_VALUE);
324+
// CKA_VALUE is guaranteed to be present, since sensitiveAttrs'
325+
// size is greater than 0 and no invalid attributes exist
326+
sensitiveAttrs.get(CKA_VALUE).pValue = plainExportedKey;
327+
} else {
328+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
329+
" fips key exporter");
330+
}
331+
} catch (Throwable t) {
332+
if (t instanceof PKCS11Exception) {
333+
throw (PKCS11Exception)t;
334+
}
335+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
336+
t.getMessage());
337+
} finally {
338+
exporterKeyP11.releaseKeyID();
339+
}
340+
}
341+
342+
private static void exportPrivateKey(
343+
Map<Long, CK_ATTRIBUTE> sensitiveAttrs, long keyType,
344+
byte[] plainExportedKey) throws Throwable {
345+
if (keyType == CKK_RSA) {
346+
checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_RSA",
347+
CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2,
348+
CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT);
349+
RSAPrivateKey rsaPKey = RSAPrivateCrtKeyImpl.newKey(
350+
RSAUtil.KeyType.RSA, "PKCS#8", plainExportedKey
351+
);
352+
CK_ATTRIBUTE attr;
353+
if ((attr = sensitiveAttrs.get(CKA_PRIVATE_EXPONENT)) != null) {
354+
attr.pValue = rsaPKey.getPrivateExponent().toByteArray();
355+
}
356+
if (rsaPKey instanceof RSAPrivateCrtKey) {
357+
RSAPrivateCrtKey rsaPCrtKey = (RSAPrivateCrtKey) rsaPKey;
358+
if ((attr = sensitiveAttrs.get(CKA_PRIME_1)) != null) {
359+
attr.pValue = rsaPCrtKey.getPrimeP().toByteArray();
360+
}
361+
if ((attr = sensitiveAttrs.get(CKA_PRIME_2)) != null) {
362+
attr.pValue = rsaPCrtKey.getPrimeQ().toByteArray();
363+
}
364+
if ((attr = sensitiveAttrs.get(CKA_EXPONENT_1)) != null) {
365+
attr.pValue = rsaPCrtKey.getPrimeExponentP().toByteArray();
366+
}
367+
if ((attr = sensitiveAttrs.get(CKA_EXPONENT_2)) != null) {
368+
attr.pValue = rsaPCrtKey.getPrimeExponentQ().toByteArray();
369+
}
370+
if ((attr = sensitiveAttrs.get(CKA_COEFFICIENT)) != null) {
371+
attr.pValue = rsaPCrtKey.getCrtCoefficient().toByteArray();
372+
}
373+
} else {
374+
checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_RSA",
375+
CKA_PRIVATE_EXPONENT);
376+
}
377+
} else if (keyType == CKK_DSA) {
378+
checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_DSA", CKA_VALUE);
379+
// CKA_VALUE is guaranteed to be present, since sensitiveAttrs'
380+
// size is greater than 0 and no invalid attributes exist
381+
sensitiveAttrs.get(CKA_VALUE).pValue =
382+
new sun.security.provider.DSAPrivateKey(plainExportedKey)
383+
.getX().toByteArray();
384+
} else if (keyType == CKK_EC) {
385+
checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_EC", CKA_VALUE);
386+
// CKA_VALUE is guaranteed to be present, since sensitiveAttrs'
387+
// size is greater than 0 and no invalid attributes exist
388+
sensitiveAttrs.get(CKA_VALUE).pValue =
389+
ECUtil.decodePKCS8ECPrivateKey(plainExportedKey)
390+
.getS().toByteArray();
391+
} else {
392+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
393+
" unsupported CKO_PRIVATE_KEY key type: " + keyType);
394+
}
395+
}
396+
397+
private static void checkAttrs(Map<Long, CK_ATTRIBUTE> sensitiveAttrs,
398+
String keyName, long... validAttrs)
399+
throws PKCS11Exception {
400+
int sensitiveAttrsCount = sensitiveAttrs.size();
401+
if (sensitiveAttrsCount <= validAttrs.length) {
402+
int validAttrsCount = 0;
403+
for (long validAttr : validAttrs) {
404+
if (sensitiveAttrs.containsKey(validAttr)) validAttrsCount++;
405+
}
406+
if (validAttrsCount == sensitiveAttrsCount) return;
407+
}
408+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
409+
" invalid attribute types for a " + keyName + " key object");
410+
}
411+
251412
private static void createImporterKey(Token token) {
252413
if (debug != null) {
253414
debug.println("Generating Importer Key...");
@@ -278,13 +439,51 @@ private static void createImporterKey(Token token) {
278439
}
279440
if (importerKey != null) {
280441
importerCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
442+
importerCipher.init(Cipher.ENCRYPT_MODE, importerKey,
443+
new IvParameterSpec(
444+
(byte[])importerKeyMechanism.pParameter), null);
281445
}
282446
} catch (Throwable t) {
283447
// best effort
284448
importerKey = null;
285449
importerCipher = null;
286450
// importerKeyMechanism value is kept initialized to indicate that
287451
// Importer Key creation has been tried and failed.
452+
if (debug != null) {
453+
debug.println("Error generating the Importer Key");
454+
}
455+
}
456+
}
457+
458+
private static void createExporterKey(Token token) {
459+
if (debug != null) {
460+
debug.println("Generating Exporter Key...");
461+
}
462+
byte[] iv = new byte[16];
463+
JCAUtil.getSecureRandom().nextBytes(iv);
464+
exporterKeyMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv);
465+
byte[] exporterKeyRaw = new byte[32];
466+
JCAUtil.getSecureRandom().nextBytes(exporterKeyRaw);
467+
exporterKey = new SecretKeySpec(exporterKeyRaw, "AES");
468+
try {
469+
SecretKeyFactory skf = SecretKeyFactory.getInstance("AES");
470+
exporterKeyP11 = (P11Key)(skf.translateKey(exporterKey));
471+
if (exporterKeyP11 != null) {
472+
exporterCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
473+
exporterCipher.init(Cipher.DECRYPT_MODE, exporterKey,
474+
new IvParameterSpec(
475+
(byte[])exporterKeyMechanism.pParameter), null);
476+
}
477+
} catch (Throwable t) {
478+
// best effort
479+
exporterKey = null;
480+
exporterKeyP11 = null;
481+
exporterCipher = null;
482+
// exporterKeyMechanism value is kept initialized to indicate that
483+
// Exporter Key creation has been tried and failed.
484+
if (debug != null) {
485+
debug.println("Error generating the Exporter Key");
486+
}
288487
}
289488
}
290489
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import javax.crypto.interfaces.*;
3838
import javax.crypto.spec.*;
3939

40+
import jdk.internal.access.SharedSecrets;
41+
4042
import sun.security.rsa.RSAUtil.KeyType;
4143
import sun.security.rsa.RSAPublicKeyImpl;
4244
import sun.security.rsa.RSAPrivateCrtKeyImpl;
@@ -69,6 +71,9 @@
6971
*/
7072
abstract class P11Key implements Key, Length {
7173

74+
private static final boolean plainKeySupportEnabled = SharedSecrets
75+
.getJavaSecuritySystemConfiguratorAccess().isPlainKeySupportEnabled();
76+
7277
private static final long serialVersionUID = -2575874101938349339L;
7378

7479
private final static String PUBLIC = "public";
@@ -378,7 +383,8 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
378383
new CK_ATTRIBUTE(CKA_SENSITIVE),
379384
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
380385
});
381-
if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
386+
if (!plainKeySupportEnabled && (attributes[1].getBoolean() ||
387+
(attributes[2].getBoolean() == false))) {
382388
return new P11PrivateKey
383389
(session, keyID, algorithm, keyLength, attributes);
384390
} else {
@@ -460,7 +466,8 @@ private static class P11SecretKey extends P11Key implements SecretKey {
460466
}
461467
public String getFormat() {
462468
token.ensureValid();
463-
if (sensitive || (extractable == false)) {
469+
if (!plainKeySupportEnabled &&
470+
(sensitive || (extractable == false))) {
464471
return null;
465472
} else {
466473
return "RAW";

0 commit comments

Comments
 (0)