2929import java .security .KeyFactory ;
3030import java .security .Provider ;
3131import java .security .Security ;
32+ import java .security .interfaces .RSAPrivateCrtKey ;
33+ import java .security .interfaces .RSAPrivateKey ;
3234import java .util .HashMap ;
3335import java .util .Map ;
3436import java .util .concurrent .locks .ReentrantLock ;
3537
3638import javax .crypto .Cipher ;
39+ import javax .crypto .SecretKeyFactory ;
40+ import javax .crypto .spec .SecretKeySpec ;
3741import javax .crypto .spec .DHPrivateKeySpec ;
3842import javax .crypto .spec .IvParameterSpec ;
3943
4448import static sun .security .pkcs11 .wrapper .PKCS11Constants .*;
4549import static sun .security .pkcs11 .wrapper .PKCS11Exception .*;
4650import sun .security .pkcs11 .wrapper .PKCS11Exception ;
51+ import sun .security .rsa .RSAPrivateCrtKeyImpl ;
52+ import sun .security .rsa .RSAUtil ;
4753import sun .security .rsa .RSAUtil .KeyType ;
4854import sun .security .util .Debug ;
4955import 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}
0 commit comments