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
4347import sun .security .pkcs11 .wrapper .CK_MECHANISM ;
4448import static sun .security .pkcs11 .wrapper .PKCS11Constants .*;
4549import sun .security .pkcs11 .wrapper .PKCS11Exception ;
50+ import sun .security .rsa .RSAPrivateCrtKeyImpl ;
51+ import sun .security .rsa .RSAUtil ;
4652import sun .security .rsa .RSAUtil .KeyType ;
4753import sun .security .util .Debug ;
4854import 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}
0 commit comments