summaryrefslogtreecommitdiff
path: root/backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch
blob: 19acaf02423b2541a8556e01101d54022f66a779 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
From d055ada2383eaf28d7b28dd7b0b639e2515279e1 Mon Sep 17 00:00:00 2001
From: jinlun <jinlun@huawei.com>
Date: Tue, 20 Feb 2024 14:41:43 +0800
Subject: [PATCH] Bug 1666891 - Add PK11_Pub{Wrap,Unwrap}SymKeyWithMechanism
 r=mt,rrelyea Summary

This is useful for RSA-OAEP support.

The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
be present for PKCS#11 calls. This provides required context for OAEP.
However, PK11_PubWrapSymKey lacks a way of providing this context and
historically silently converted CKM_RSA_PKCS_OAEP to CKM_RSA_PKCS when
a RSA key is provided. Introducing a new call will let us indicate
parameters and potentially support other mechanisms in the future.
This call mirrors the earlier calls introduced for RSA-PSS:
PK11_SignWithMechanism and PK11_VerifyWithMechanism.

The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
be present for PKCS#11 calls. This provides required context for OAEP.
However, PK11_PubUnwrapSymKey lacks a way of providing this context,
and additionally lacked a way of indicating which mechanism type to use
for the unwrap operation (instead detecting it by key type). Introducing
a new call will let us indicate parameters and potentially support other
mechanisms in the future.

Signed-off-by: Alexander Scheel <ascheel@redhat.com>

Differential Revision: https://phabricator.services.mozilla.com/D93424
---
 gtests/pk11_gtest/pk11_rsaoaep_unittest.cc | 67 ++++++++++++++++++++++
 lib/nss/nss.def                            |  7 +++
 lib/pk11wrap/pk11pub.h                     | 12 ++++
 lib/pk11wrap/pk11skey.c                    | 51 ++++++++++++----
 4 files changed, 126 insertions(+), 11 deletions(-)

diff --git a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
index 3a986b4..d14eb9c 100644
--- a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
+++ b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
@@ -116,4 +116,71 @@ INSTANTIATE_TEST_CASE_P(
 INSTANTIATE_TEST_CASE_P(
     WycheproofOaep2048Sha512Sha512Test, RsaOaepWycheproofTest,
     ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha512WycheproofVectors));
+
+TEST(Pkcs11RsaOaepTest, TestOaepWrapUnwrap) {
+  const size_t kRsaKeyBits = 2048;
+  const size_t kwrappedBufLen = 4096;
+
+  SECStatus rv = SECFailure;
+
+  ScopedSECKEYPrivateKey priv;
+  ScopedSECKEYPublicKey pub;
+  PK11RSAGenParams rsa_params;
+  rsa_params.keySizeInBits = kRsaKeyBits;
+  rsa_params.pe = 65537;
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(slot, nullptr);
+
+  SECKEYPublicKey* p_pub_tmp = nullptr;
+  priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
+                                  &rsa_params, &p_pub_tmp, false, false,
+                                  nullptr));
+  pub.reset(p_pub_tmp);
+
+  ASSERT_NE(priv.get(), nullptr);
+  ASSERT_NE(pub.get(), nullptr);
+
+  ScopedPK11SymKey to_wrap(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+
+  CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256,
+                                         CKZ_DATA_SPECIFIED, NULL, 0};
+
+  SECItem param = {siBuffer, (unsigned char*)&oaep_params, sizeof(oaep_params)};
+
+  ScopedSECItem wrapped(SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
+  rv = PK11_PubWrapSymKeyWithMechanism(pub.get(), CKM_RSA_PKCS_OAEP, &param,
+                                       to_wrap.get(), wrapped.get());
+  ASSERT_EQ(rv, SECSuccess);
+
+  PK11SymKey* p_unwrapped_tmp = nullptr;
+
+  // This fails because this method is broken and assumes CKM_RSA_PKCS and
+  // doesn't understand OAEP.
+  p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC,
+                                         CKA_DECRYPT, 16);
+  ASSERT_EQ(p_unwrapped_tmp, nullptr);
+
+  ScopedPK11SymKey unwrapped;
+  p_unwrapped_tmp = PK11_PubUnwrapSymKeyWithMechanism(
+      priv.get(), CKM_RSA_PKCS_OAEP, &param, wrapped.get(), CKM_AES_CBC,
+      CKA_DECRYPT, 16);
+  ASSERT_NE(p_unwrapped_tmp, nullptr);
+
+  unwrapped.reset(p_unwrapped_tmp);
+
+  // Extract key's value in order to validate decryption worked.
+  rv = PK11_ExtractKeyValue(to_wrap.get());
+  ASSERT_EQ(rv, SECSuccess);
+
+  rv = PK11_ExtractKeyValue(unwrapped.get());
+  ASSERT_EQ(rv, SECSuccess);
+
+  // References owned by PKCS#11 layer; no need to scope and free.
+  SECItem* expectedItem = PK11_GetKeyData(to_wrap.get());
+  SECItem* actualItem = PK11_GetKeyData(unwrapped.get());
+
+  ASSERT_EQ(SECITEM_CompareItem(actualItem, expectedItem), 0);
+}
 }  // namespace nss_test
diff --git a/lib/nss/nss.def b/lib/nss/nss.def
index 1840b8d..4055a98 100644
--- a/lib/nss/nss.def
+++ b/lib/nss/nss.def
@@ -1181,3 +1181,10 @@ SECMOD_GetSystemFIPSEnabled;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.59 {    # NSS 3.59 release
+;+    global:
+PK11_PubWrapSymKeyWithMechanism;
+PK11_PubUnwrapSymKeyWithMechanism;
+;+    local:
+;+       *;
+;+};
diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h
index 5edcbf9..3af8487 100644
--- a/lib/pk11wrap/pk11pub.h
+++ b/lib/pk11wrap/pk11pub.h
@@ -354,6 +354,11 @@ void *PK11_GetSymKeyUserData(PK11SymKey *symKey);
 
 SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
                              PK11SymKey *symKey, SECItem *wrappedKey);
+SECStatus PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
+                                          CK_MECHANISM_TYPE mechType,
+                                          SECItem *param,
+                                          PK11SymKey *symKey,
+                                          SECItem *wrappedKey);
 SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params,
                           PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey);
 /* move a key to 'slot' optionally set the key attributes according to either
@@ -448,6 +453,13 @@ PK11SymKey *PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
  */
 PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey,
                                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
+PK11SymKey *PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *key,
+                                              CK_MECHANISM_TYPE mechType,
+                                              SECItem *param,
+                                              SECItem *wrapppedKey,
+                                              CK_MECHANISM_TYPE target,
+                                              CK_ATTRIBUTE_TYPE operation,
+                                              int keySize);
 PK11SymKey *PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
                                               SECItem *wrappedKey, CK_MECHANISM_TYPE target,
                                               CK_ATTRIBUTE_TYPE operation, int keySize,
diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
index 996c039..eed833a 100644
--- a/lib/pk11wrap/pk11skey.c
+++ b/lib/pk11wrap/pk11skey.c
@@ -1248,13 +1248,23 @@ PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx)
                                  symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
 }
 
-/*
- * This function does a straight public key wrap (which only RSA can do).
- * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
- * Diffie-Hellman Ciphers. */
+/* This function does a straight public key wrap with the CKM_RSA_PKCS
+ * mechanism. */
 SECStatus
 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
                    PK11SymKey *symKey, SECItem *wrappedKey)
+{
+    CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType);
+    return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey,
+                                           wrappedKey);
+}
+
+/* This function wraps a symmetric key with a public key, such as with the
+ * CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */
+SECStatus
+PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
+                                CK_MECHANISM_TYPE mechType, SECItem *param,
+                                PK11SymKey *symKey, SECItem *wrappedKey)
 {
     PK11SlotInfo *slot;
     CK_ULONG len = wrappedKey->len;
@@ -1271,7 +1281,7 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
     }
 
     /* if this slot doesn't support the mechanism, go to a slot that does */
-    newKey = pk11_ForceSlot(symKey, type, CKA_ENCRYPT);
+    newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT);
     if (newKey != NULL) {
         symKey = newKey;
     }
@@ -1282,9 +1292,15 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
     }
 
     slot = symKey->slot;
-    mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
-    mechanism.pParameter = NULL;
-    mechanism.ulParameterLen = 0;
+
+    mechanism.mechanism = mechType;
+    if (param == NULL) {
+        mechanism.pParameter = NULL;
+        mechanism.ulParameterLen = 0;
+    } else {
+        mechanism.pParameter = param->data;
+        mechanism.ulParameterLen = param->len;
+    }
 
     id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
     if (id == CK_INVALID_HANDLE) {
@@ -2856,20 +2872,33 @@ PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey,
                              wrappingKey->cx, keyTemplate, templateCount, isPerm);
 }
 
-/* unwrap a symetric key with a private key. */
+/* unwrap a symmetric key with a private key. Only supports CKM_RSA_PKCS. */
 PK11SymKey *
 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
                      CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
 {
     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
+
+    return PK11_PubUnwrapSymKeyWithMechanism(wrappingKey, wrapType, NULL,
+                                             wrappedKey, target, operation,
+                                             keySize);
+}
+
+/* unwrap a symmetric key with a private key with the given parameters. */
+PK11SymKey *
+PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey,
+                                  CK_MECHANISM_TYPE mechType, SECItem *param,
+                                  SECItem *wrappedKey, CK_MECHANISM_TYPE target,
+                                  CK_ATTRIBUTE_TYPE operation, int keySize)
+{
     PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
 
     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
         PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
     }
 
-    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
-                             wrapType, NULL, wrappedKey, target, operation, keySize,
+    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, mechType, param,
+                             wrappedKey, target, operation, keySize,
                              wrappingKey->wincx, NULL, 0, PR_FALSE);
 }
 
-- 
2.33.0