|
23 | 23 | * questions. |
24 | 24 | */ |
25 | 25 |
|
| 26 | +/* |
| 27 | + * =========================================================================== |
| 28 | + * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved |
| 29 | + * =========================================================================== |
| 30 | + */ |
| 31 | + |
26 | 32 | package sun.security.pkcs11; |
27 | 33 |
|
28 | 34 | import java.io.*; |
29 | 35 | import java.util.*; |
30 | 36 |
|
31 | 37 | import java.security.*; |
| 38 | +import java.security.InvalidAlgorithmParameterException; |
| 39 | +import java.security.InvalidKeyException; |
32 | 40 | import java.security.interfaces.*; |
| 41 | +import java.util.function.Consumer; |
33 | 42 |
|
| 43 | +import javax.crypto.BadPaddingException; |
| 44 | +import javax.crypto.Cipher; |
| 45 | +import javax.crypto.IllegalBlockSizeException; |
| 46 | +import javax.crypto.NoSuchPaddingException; |
34 | 47 | import javax.crypto.interfaces.*; |
| 48 | +import javax.crypto.spec.IvParameterSpec; |
35 | 49 |
|
36 | 50 | import javax.security.auth.Subject; |
37 | 51 | import javax.security.auth.login.LoginException; |
|
43 | 57 | import com.sun.crypto.provider.ChaCha20Poly1305Parameters; |
44 | 58 |
|
45 | 59 | import jdk.internal.misc.InnocuousThread; |
| 60 | +import openj9.internal.security.FIPSConfigurator; |
46 | 61 | import sun.security.util.Debug; |
47 | 62 | import sun.security.util.ResourcesMgr; |
48 | 63 | import static sun.security.util.SecurityConstants.PROVIDER_VER; |
49 | 64 | import static sun.security.util.SecurityProviderConstants.getAliases; |
50 | 65 |
|
51 | 66 | import sun.security.pkcs11.Secmod.*; |
52 | | - |
| 67 | +import sun.security.pkcs11.TemplateManager; |
53 | 68 | import sun.security.pkcs11.wrapper.*; |
54 | 69 | import static sun.security.pkcs11.wrapper.PKCS11Constants.*; |
55 | 70 | import static sun.security.pkcs11.wrapper.PKCS11Exception.*; |
@@ -89,6 +104,11 @@ public final class SunPKCS11 extends AuthProvider { |
89 | 104 |
|
90 | 105 | static NativeResourceCleaner cleaner; |
91 | 106 |
|
| 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 | + |
92 | 112 | Token getToken() { |
93 | 113 | return token; |
94 | 114 | } |
@@ -379,6 +399,29 @@ private static <T> T checkNull(T obj) { |
379 | 399 | if (nssModule != null) { |
380 | 400 | nssModule.setProvider(this); |
381 | 401 | } |
| 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 | + } |
382 | 425 | } catch (Exception e) { |
383 | 426 | if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) { |
384 | 427 | throw new UnsupportedOperationException |
@@ -411,6 +454,94 @@ public int hashCode() { |
411 | 454 | return System.identityHashCode(this); |
412 | 455 | } |
413 | 456 |
|
| 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 | + |
414 | 545 | private static final class Descriptor { |
415 | 546 | final String type; |
416 | 547 | final String algorithm; |
|
0 commit comments