Skip to content

Commit bd324bd

Browse files
franferraxmartinuyakashche
authored
RH2023467: Enable FIPS keys export (#1)
RH2023467: Enable FIPS keys export Co-Authored-By: Martin Balao <mbalao@redhat.com> Co-Authored-By: Alex Kashchenko <akashche@redhat.com>
1 parent 6e74f28 commit bd324bd

File tree

6 files changed

+386
-40
lines changed

6 files changed

+386
-40
lines changed

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

Lines changed: 11 additions & 5 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-
getAliases("PKCS1"), null);
70+
add(p, "KeyFactory", "RSA",
71+
"sun.security.rsa.RSAKeyFactory$Legacy",
72+
getAliases("PKCS1"), null);
73+
74+
if (!systemFipsEnabled) {
7275
add(p, "KeyPairGenerator", "RSA",
7376
"sun.security.rsa.RSAKeyPairGenerator$Legacy",
7477
getAliases("PKCS1"), null);
@@ -98,9 +101,12 @@ public SunRsaSignEntries(Provider p) {
98101
"sun.security.rsa.RSASignature$SHA3_384withRSA", attrs);
99102
addA(p, "Signature", "SHA3-512withRSA",
100103
"sun.security.rsa.RSASignature$SHA3_512withRSA", attrs);
104+
}
105+
106+
addA(p, "KeyFactory", "RSASSA-PSS",
107+
"sun.security.rsa.RSAKeyFactory$PSS", attrs);
101108

102-
addA(p, "KeyFactory", "RSASSA-PSS",
103-
"sun.security.rsa.RSAKeyFactory$PSS", attrs);
109+
if (!systemFipsEnabled) {
104110
addA(p, "KeyPairGenerator", "RSASSA-PSS",
105111
"sun.security.rsa.RSAKeyPairGenerator$PSS", attrs);
106112
addA(p, "Signature", "RSASSA-PSS",

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

@@ -44,6 +48,8 @@
4448
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
4549
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
4650
import sun.security.pkcs11.wrapper.PKCS11Exception;
51+
import sun.security.rsa.RSAPrivateCrtKeyImpl;
52+
import sun.security.rsa.RSAUtil;
4753
import sun.security.rsa.RSAUtil.KeyType;
4854
import sun.security.util.Debug;
4955
import sun.security.util.ECUtil;
@@ -53,15 +59,21 @@ final class FIPSKeyImporter {
5359
private static final Debug debug =
5460
Debug.getInstance("sunpkcs11");
5561

56-
private static P11Key importerKey = null;
62+
private static volatile P11Key importerKey = null;
63+
private static SecretKeySpec exporterKey = null;
64+
private static volatile P11Key exporterKeyP11 = null;
5765
private static final ReentrantLock importerKeyLock = new ReentrantLock();
58-
private static CK_MECHANISM importerKeyMechanism = null;
66+
// Do not take the exporterKeyLock with the importerKeyLock held.
67+
private static final ReentrantLock exporterKeyLock = new ReentrantLock();
68+
private static volatile CK_MECHANISM importerKeyMechanism = null;
69+
private static volatile CK_MECHANISM exporterKeyMechanism = null;
5970
private static Cipher importerCipher = null;
71+
private static Cipher exporterCipher = null;
6072

61-
private static Provider sunECProvider = null;
73+
private static volatile Provider sunECProvider = null;
6274
private static final ReentrantLock sunECProviderLock = new ReentrantLock();
6375

64-
private static KeyFactory DHKF = null;
76+
private static volatile KeyFactory DHKF = null;
6577
private static final ReentrantLock DHKFLock = new ReentrantLock();
6678

6779
static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attributes)
@@ -85,7 +97,8 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
8597
debug.println("Importer Key could not be" +
8698
" generated.");
8799
}
88-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
100+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
101+
" fips key importer");
89102
}
90103
if (debug != null) {
91104
debug.println("Importer Key successfully" +
@@ -213,7 +226,8 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
213226
if (debug != null) {
214227
debug.println("Unrecognized private key type.");
215228
}
216-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
229+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
230+
" fips key importer");
217231
}
218232
} else if (keyClass == CKO_SECRET_KEY) {
219233
if (debug != null) {
@@ -226,14 +240,19 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
226240
debug.println("Private or secret key plain bytes could" +
227241
" not be obtained. Import failed.");
228242
}
229-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
243+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
244+
" fips key importer");
230245
}
231-
importerCipher.init(Cipher.ENCRYPT_MODE, importerKey,
232-
new IvParameterSpec((byte[])importerKeyMechanism.pParameter),
233-
null);
234246
attributes = new CK_ATTRIBUTE[attrsMap.size()];
235247
attrsMap.values().toArray(attributes);
236-
encKeyBytes = importerCipher.doFinal(keyBytes);
248+
importerKeyLock.lock();
249+
try {
250+
// No need to reset the cipher object because no multi-part
251+
// operations are performed.
252+
encKeyBytes = importerCipher.doFinal(keyBytes);
253+
} finally {
254+
importerKeyLock.unlock();
255+
}
237256
attributes = token.getAttributes(TemplateManager.O_IMPORT,
238257
keyClass, keyType, attributes);
239258
keyID = token.p11.C_UnwrapKey(hSession,
@@ -242,13 +261,155 @@ static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attribu
242261
debug.println("Imported key ID: " + keyID);
243262
}
244263
} catch (Throwable t) {
245-
throw new PKCS11Exception(CKR_GENERAL_ERROR);
264+
if (t instanceof PKCS11Exception) {
265+
throw (PKCS11Exception)t;
266+
}
267+
throw new PKCS11Exception(CKR_GENERAL_ERROR,
268+
t.getMessage());
246269
} finally {
247270
importerKey.releaseKeyID();
248271
}
249272
return Long.valueOf(keyID);
250273
}
251274

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

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 static final String PUBLIC = "public";
@@ -379,7 +384,8 @@ static PrivateKey privateKey(Session session, long keyID, String algorithm,
379384
new CK_ATTRIBUTE(CKA_SENSITIVE),
380385
new CK_ATTRIBUTE(CKA_EXTRACTABLE),
381386
});
382-
if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
387+
if (!plainKeySupportEnabled && (attributes[1].getBoolean() ||
388+
(attributes[2].getBoolean() == false))) {
383389
return new P11PrivateKey
384390
(session, keyID, algorithm, keyLength, attributes);
385391
} else {
@@ -461,7 +467,8 @@ private static class P11SecretKey extends P11Key implements SecretKey {
461467
}
462468
public String getFormat() {
463469
token.ensureValid();
464-
if (sensitive || (extractable == false)) {
470+
if (!plainKeySupportEnabled &&
471+
(sensitive || (extractable == false))) {
465472
return null;
466473
} else {
467474
return "RAW";

0 commit comments

Comments
 (0)