/src/nss/lib/softoken/lowkey.c
Line | Count | Source |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | #include "lowkeyi.h" |
5 | | #include "secoid.h" |
6 | | #include "secitem.h" |
7 | | #include "secder.h" |
8 | | #include "base64.h" |
9 | | #include "secasn1.h" |
10 | | #include "secerr.h" |
11 | | #include "softoken.h" |
12 | | #include "ec.h" |
13 | | #include "kem.h" |
14 | | |
15 | | SEC_ASN1_MKSUB(SEC_AnyTemplate) |
16 | | SEC_ASN1_MKSUB(SEC_BitStringTemplate) |
17 | | SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) |
18 | | SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
19 | | SEC_ASN1_MKSUB(SEC_OctetStringTemplate) |
20 | | |
21 | | const SEC_ASN1Template nsslowkey_AttributeTemplate[] = { |
22 | | { SEC_ASN1_SEQUENCE, |
23 | | 0, NULL, sizeof(NSSLOWKEYAttribute) }, |
24 | | { SEC_ASN1_OBJECT_ID, offsetof(NSSLOWKEYAttribute, attrType) }, |
25 | | { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, |
26 | | offsetof(NSSLOWKEYAttribute, attrValue), |
27 | | SEC_ASN1_SUB(SEC_AnyTemplate) }, |
28 | | { 0 } |
29 | | }; |
30 | | |
31 | | const SEC_ASN1Template nsslowkey_SetOfAttributeTemplate[] = { |
32 | | { SEC_ASN1_SET_OF, 0, nsslowkey_AttributeTemplate }, |
33 | | }; |
34 | | /* ASN1 Templates for new decoder/encoder */ |
35 | | const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[] = { |
36 | | { SEC_ASN1_SEQUENCE, |
37 | | 0, NULL, sizeof(NSSLOWKEYPrivateKeyInfo) }, |
38 | | { SEC_ASN1_INTEGER, |
39 | | offsetof(NSSLOWKEYPrivateKeyInfo, version) }, |
40 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
41 | | offsetof(NSSLOWKEYPrivateKeyInfo, algorithm), |
42 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
43 | | { SEC_ASN1_OCTET_STRING, |
44 | | offsetof(NSSLOWKEYPrivateKeyInfo, privateKey) }, |
45 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
46 | | offsetof(NSSLOWKEYPrivateKeyInfo, attributes), |
47 | | nsslowkey_SetOfAttributeTemplate }, |
48 | | { 0 } |
49 | | }; |
50 | | |
51 | | const SEC_ASN1Template nsslowkey_SubjectPublicKeyInfoTemplate[] = { |
52 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYSubjectPublicKeyInfo) }, |
53 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
54 | | offsetof(NSSLOWKEYSubjectPublicKeyInfo, algorithm), |
55 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
56 | | { SEC_ASN1_BIT_STRING, |
57 | | offsetof(NSSLOWKEYSubjectPublicKeyInfo, subjectPublicKey) }, |
58 | | { 0 } |
59 | | }; |
60 | | |
61 | | const SEC_ASN1Template nsslowkey_RSAPublicKeyTemplate[] = { |
62 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPublicKey) }, |
63 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.modulus) }, |
64 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPublicKey, u.rsa.publicExponent) }, |
65 | | { 0 } |
66 | | }; |
67 | | |
68 | | const SEC_ASN1Template nsslowkey_PQGParamsTemplate[] = { |
69 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PQGParams) }, |
70 | | { SEC_ASN1_INTEGER, offsetof(PQGParams, prime) }, |
71 | | { SEC_ASN1_INTEGER, offsetof(PQGParams, subPrime) }, |
72 | | { SEC_ASN1_INTEGER, offsetof(PQGParams, base) }, |
73 | | { 0 } |
74 | | }; |
75 | | |
76 | | const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[] = { |
77 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
78 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.version) }, |
79 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.modulus) }, |
80 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.publicExponent) }, |
81 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.privateExponent) }, |
82 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.prime1) }, |
83 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.prime2) }, |
84 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.exponent1) }, |
85 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.exponent2) }, |
86 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.rsa.coefficient) }, |
87 | | { 0 } |
88 | | }; |
89 | | |
90 | | const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = { |
91 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
92 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.publicValue) }, |
93 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) }, |
94 | | { 0 } |
95 | | }; |
96 | | |
97 | | const SEC_ASN1Template nsslowkey_PQBothSeedAndPrivateKeyTemplate[] = { |
98 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
99 | | { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.seedItem) }, |
100 | | { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.keyItem) }, |
101 | | { 0 } |
102 | | }; |
103 | | |
104 | | const SEC_ASN1Template nsslowkey_PQSeedTemplate[] = { |
105 | | /* the explicit | 0 here is source code doumentation, tell |
106 | | * clang warnings to let it ride */ |
107 | | { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, // NOLINT(misc-redundant-expression) |
108 | | offsetof(NSSLOWKEYPrivateKey, u.genpq.seedItem), |
109 | | SEC_ASN1_SUB(SEC_OctetStringTemplate) }, |
110 | | { 0 } |
111 | | }; |
112 | | const SEC_ASN1Template nsslowkey_PQPrivateKeyTemplate[] = { |
113 | | { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.keyItem) }, |
114 | | { 0 } |
115 | | }; |
116 | | |
117 | | const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = { |
118 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) }, |
119 | | }; |
120 | | |
121 | | const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = { |
122 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
123 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.publicValue) }, |
124 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.privateValue) }, |
125 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.base) }, |
126 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.prime) }, |
127 | | { 0 } |
128 | | }; |
129 | | |
130 | | /* NOTE: The SECG specification allows the private key structure |
131 | | * to contain curve parameters but recommends that they be stored |
132 | | * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo |
133 | | * instead. |
134 | | */ |
135 | | const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = { |
136 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) }, |
137 | | { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.ec.version) }, |
138 | | { SEC_ASN1_OCTET_STRING, |
139 | | offsetof(NSSLOWKEYPrivateKey, u.ec.privateValue) }, |
140 | | /* We only support named curves for which the parameters are |
141 | | * encoded as an object ID. |
142 | | */ |
143 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
144 | | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
145 | | SEC_ASN1_XTRN | 0, |
146 | | offsetof(NSSLOWKEYPrivateKey, u.ec.ecParams.curveOID), |
147 | | SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, |
148 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
149 | | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
150 | | SEC_ASN1_XTRN | 1, |
151 | | offsetof(NSSLOWKEYPrivateKey, u.ec.publicValue), |
152 | | SEC_ASN1_SUB(SEC_BitStringTemplate) }, |
153 | | { 0 } |
154 | | }; |
155 | | /* |
156 | | * See bugzilla bug 125359 |
157 | | * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, |
158 | | * all of the templates above that en/decode into integers must be converted |
159 | | * from ASN.1's signed integer type. This is done by marking either the |
160 | | * source or destination (encoding or decoding, respectively) type as |
161 | | * siUnsignedInteger. |
162 | | */ |
163 | | |
164 | | void |
165 | | prepare_low_rsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
166 | 0 | { |
167 | 0 | key->u.rsa.modulus.type = siUnsignedInteger; |
168 | 0 | key->u.rsa.publicExponent.type = siUnsignedInteger; |
169 | 0 | key->u.rsa.privateExponent.type = siUnsignedInteger; |
170 | 0 | key->u.rsa.prime1.type = siUnsignedInteger; |
171 | 0 | key->u.rsa.prime2.type = siUnsignedInteger; |
172 | 0 | key->u.rsa.exponent1.type = siUnsignedInteger; |
173 | 0 | key->u.rsa.exponent2.type = siUnsignedInteger; |
174 | 0 | key->u.rsa.coefficient.type = siUnsignedInteger; |
175 | 0 | } |
176 | | |
177 | | void |
178 | | prepare_low_rsa_pub_key_for_asn1(NSSLOWKEYPublicKey *key) |
179 | 0 | { |
180 | 0 | key->u.rsa.modulus.type = siUnsignedInteger; |
181 | 0 | key->u.rsa.publicExponent.type = siUnsignedInteger; |
182 | 0 | } |
183 | | |
184 | | void |
185 | | prepare_low_pqg_params_for_asn1(PQGParams *params) |
186 | 0 | { |
187 | 0 | params->prime.type = siUnsignedInteger; |
188 | 0 | params->subPrime.type = siUnsignedInteger; |
189 | 0 | params->base.type = siUnsignedInteger; |
190 | 0 | } |
191 | | |
192 | | void |
193 | | prepare_low_dsa_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
194 | 0 | { |
195 | 0 | key->u.dsa.publicValue.type = siUnsignedInteger; |
196 | 0 | key->u.dsa.privateValue.type = siUnsignedInteger; |
197 | 0 | key->u.dsa.params.prime.type = siUnsignedInteger; |
198 | 0 | key->u.dsa.params.subPrime.type = siUnsignedInteger; |
199 | 0 | key->u.dsa.params.base.type = siUnsignedInteger; |
200 | 0 | } |
201 | | |
202 | | void |
203 | | prepare_low_dsa_priv_key_export_for_asn1(NSSLOWKEYPrivateKey *key) |
204 | 0 | { |
205 | 0 | key->u.dsa.privateValue.type = siUnsignedInteger; |
206 | 0 | } |
207 | | |
208 | | void |
209 | | prepare_low_dh_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
210 | 0 | { |
211 | 0 | key->u.dh.prime.type = siUnsignedInteger; |
212 | 0 | key->u.dh.base.type = siUnsignedInteger; |
213 | 0 | key->u.dh.publicValue.type = siUnsignedInteger; |
214 | 0 | key->u.dh.privateValue.type = siUnsignedInteger; |
215 | 0 | } |
216 | | |
217 | | void |
218 | | prepare_low_ecparams_for_asn1(ECParams *params) |
219 | 0 | { |
220 | 0 | params->DEREncoding.type = siUnsignedInteger; |
221 | 0 | params->curveOID.type = siUnsignedInteger; |
222 | 0 | } |
223 | | |
224 | | void |
225 | | prepare_low_ec_priv_key_for_asn1(NSSLOWKEYPrivateKey *key) |
226 | 0 | { |
227 | 0 | key->u.ec.version.type = siUnsignedInteger; |
228 | 0 | key->u.ec.ecParams.DEREncoding.type = siUnsignedInteger; |
229 | 0 | key->u.ec.ecParams.curveOID.type = siUnsignedInteger; |
230 | 0 | key->u.ec.privateValue.type = siUnsignedInteger; |
231 | 0 | key->u.ec.publicValue.type = siUnsignedInteger; |
232 | 0 | } |
233 | | |
234 | | void |
235 | | nsslowkey_DestroyPrivateKey(NSSLOWKEYPrivateKey *privk) |
236 | 105k | { |
237 | 105k | if (privk && privk->arena) { |
238 | 105k | PORT_FreeArena(privk->arena, PR_TRUE); |
239 | 105k | } |
240 | 105k | } |
241 | | |
242 | | void |
243 | | nsslowkey_DestroyPublicKey(NSSLOWKEYPublicKey *pubk) |
244 | 148k | { |
245 | 148k | if (pubk && pubk->arena) { |
246 | 148k | PORT_FreeArena(pubk->arena, PR_TRUE); |
247 | 148k | } |
248 | 148k | } |
249 | | unsigned |
250 | | nsslowkey_PublicModulusLen(NSSLOWKEYPublicKey *pubk) |
251 | 15.1k | { |
252 | | /* interpret modulus length as key strength... in |
253 | | * fortezza that's the public key length */ |
254 | | |
255 | 15.1k | switch (pubk->keyType) { |
256 | 15.1k | case NSSLOWKEYRSAKey: |
257 | 15.1k | if (pubk->u.rsa.modulus.len == 0) { |
258 | 0 | return 0; |
259 | 0 | } |
260 | 15.1k | if (pubk->u.rsa.modulus.data[0] == 0) { |
261 | 0 | return pubk->u.rsa.modulus.len - 1; |
262 | 0 | } |
263 | 15.1k | return pubk->u.rsa.modulus.len; |
264 | 0 | default: |
265 | 0 | break; |
266 | 15.1k | } |
267 | 0 | return 0; |
268 | 15.1k | } |
269 | | |
270 | | unsigned |
271 | | nsslowkey_PrivateModulusLen(NSSLOWKEYPrivateKey *privk) |
272 | 113k | { |
273 | 113k | switch (privk->keyType) { |
274 | 113k | case NSSLOWKEYRSAKey: |
275 | 113k | if (privk->u.rsa.modulus.len == 0) { |
276 | 0 | return 0; |
277 | 0 | } |
278 | 113k | if (privk->u.rsa.modulus.data[0] == 0) { |
279 | 0 | return privk->u.rsa.modulus.len - 1; |
280 | 0 | } |
281 | 113k | return privk->u.rsa.modulus.len; |
282 | 0 | default: |
283 | 0 | break; |
284 | 113k | } |
285 | 0 | return 0; |
286 | 113k | } |
287 | | |
288 | | NSSLOWKEYPublicKey * |
289 | | nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) |
290 | 0 | { |
291 | 0 | NSSLOWKEYPublicKey *pubk; |
292 | 0 | SECItem publicValue; |
293 | 0 | PLArenaPool *arena; |
294 | |
|
295 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
296 | 0 | if (arena == NULL) { |
297 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
298 | 0 | return NULL; |
299 | 0 | } |
300 | | |
301 | 0 | switch (privk->keyType) { |
302 | 0 | case NSSLOWKEYRSAKey: |
303 | 0 | case NSSLOWKEYNullKey: |
304 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
305 | 0 | sizeof(NSSLOWKEYPublicKey)); |
306 | 0 | if (pubk != NULL) { |
307 | 0 | SECStatus rv; |
308 | |
|
309 | 0 | pubk->arena = arena; |
310 | 0 | pubk->keyType = privk->keyType; |
311 | 0 | if (privk->keyType == NSSLOWKEYNullKey) |
312 | 0 | return pubk; |
313 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus, |
314 | 0 | &privk->u.rsa.modulus); |
315 | 0 | if (rv == SECSuccess) { |
316 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.rsa.publicExponent, |
317 | 0 | &privk->u.rsa.publicExponent); |
318 | 0 | if (rv == SECSuccess) { |
319 | | /* this key was already verified fully as |
320 | | * a private key */ |
321 | 0 | pubk->u.rsa.needVerify = PR_FALSE; |
322 | 0 | return pubk; |
323 | 0 | } |
324 | 0 | } |
325 | 0 | } else { |
326 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
327 | 0 | } |
328 | 0 | break; |
329 | 0 | case NSSLOWKEYDSAKey: |
330 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
331 | 0 | sizeof(NSSLOWKEYPublicKey)); |
332 | 0 | if (pubk != NULL) { |
333 | 0 | SECStatus rv; |
334 | |
|
335 | 0 | pubk->arena = arena; |
336 | 0 | pubk->keyType = privk->keyType; |
337 | | /* if the public key value doesn't exist, calculate it */ |
338 | 0 | if (privk->u.dsa.publicValue.len == 0) { |
339 | 0 | rv = DH_Derive(&privk->u.dsa.params.base, &privk->u.dsa.params.prime, |
340 | 0 | &privk->u.dsa.privateValue, &publicValue, 0); |
341 | 0 | if (rv != SECSuccess) { |
342 | 0 | break; |
343 | 0 | } |
344 | 0 | rv = SECITEM_CopyItem(privk->arena, &privk->u.dsa.publicValue, &publicValue); |
345 | 0 | SECITEM_ZfreeItem(&publicValue, PR_FALSE); |
346 | 0 | if (rv != SECSuccess) { |
347 | 0 | break; |
348 | 0 | } |
349 | 0 | } |
350 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, |
351 | 0 | &privk->u.dsa.publicValue); |
352 | 0 | if (rv != SECSuccess) |
353 | 0 | break; |
354 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.prime, |
355 | 0 | &privk->u.dsa.params.prime); |
356 | 0 | if (rv != SECSuccess) |
357 | 0 | break; |
358 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.subPrime, |
359 | 0 | &privk->u.dsa.params.subPrime); |
360 | 0 | if (rv != SECSuccess) |
361 | 0 | break; |
362 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dsa.params.base, |
363 | 0 | &privk->u.dsa.params.base); |
364 | 0 | if (rv == SECSuccess) |
365 | 0 | return pubk; |
366 | 0 | } |
367 | 0 | break; |
368 | 0 | case NSSLOWKEYDHKey: |
369 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
370 | 0 | sizeof(NSSLOWKEYPublicKey)); |
371 | 0 | if (pubk != NULL) { |
372 | 0 | SECStatus rv; |
373 | |
|
374 | 0 | pubk->arena = arena; |
375 | 0 | pubk->keyType = privk->keyType; |
376 | | /* if the public key value doesn't exist, calculate it */ |
377 | 0 | if (privk->u.dh.publicValue.len == 0) { |
378 | 0 | rv = DH_Derive(&privk->u.dh.base, &privk->u.dh.prime, |
379 | 0 | &privk->u.dh.privateValue, &publicValue, 0); |
380 | 0 | if (rv != SECSuccess) { |
381 | 0 | break; |
382 | 0 | } |
383 | 0 | rv = SECITEM_CopyItem(privk->arena, &privk->u.dh.publicValue, &publicValue); |
384 | 0 | SECITEM_ZfreeItem(&publicValue, PR_FALSE); |
385 | 0 | if (rv != SECSuccess) { |
386 | 0 | break; |
387 | 0 | } |
388 | 0 | } |
389 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, |
390 | 0 | &privk->u.dh.publicValue); |
391 | 0 | if (rv != SECSuccess) |
392 | 0 | break; |
393 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dh.prime, |
394 | 0 | &privk->u.dh.prime); |
395 | 0 | if (rv != SECSuccess) |
396 | 0 | break; |
397 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.dh.base, |
398 | 0 | &privk->u.dh.base); |
399 | 0 | if (rv == SECSuccess) |
400 | 0 | return pubk; |
401 | 0 | } |
402 | 0 | break; |
403 | 0 | case NSSLOWKEYECKey: |
404 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
405 | 0 | sizeof(NSSLOWKEYPublicKey)); |
406 | 0 | if (pubk != NULL) { |
407 | 0 | SECStatus rv; |
408 | |
|
409 | 0 | pubk->arena = arena; |
410 | 0 | pubk->keyType = privk->keyType; |
411 | | |
412 | | /* if the public key value doesn't exist, calculate it */ |
413 | 0 | if (privk->u.ec.publicValue.len == 0) { |
414 | | /* Checking if it's an ed25519 or x25519 key. |
415 | | If it's the case, we derive the public key using the private key. */ |
416 | 0 | SECOidTag privKeyOIDTag = SECOID_FindOIDTag(&privk->u.ec.ecParams.curveOID); |
417 | 0 | if (privKeyOIDTag == SEC_OID_ED25519_PUBLIC_KEY) { |
418 | 0 | PORT_Memset(&privk->u.ec.publicValue, 0, sizeof(privk->u.ec.publicValue)); |
419 | 0 | if (SECITEM_AllocItem(privk->arena, &privk->u.ec.publicValue, Ed25519_PUBLIC_KEYLEN) == NULL) { |
420 | 0 | break; |
421 | 0 | } |
422 | | |
423 | 0 | rv = ED_DerivePublicKey(&privk->u.ec.privateValue, &privk->u.ec.publicValue); |
424 | 0 | if (rv != CKR_OK) { |
425 | 0 | break; |
426 | 0 | } |
427 | 0 | } else if (privKeyOIDTag == SEC_OID_X25519) { |
428 | 0 | PORT_Memset(&privk->u.ec.publicValue, 0, sizeof(privk->u.ec.publicValue)); |
429 | 0 | if (SECITEM_AllocItem(privk->arena, &privk->u.ec.publicValue, X25519_PUBLIC_KEYLEN) == NULL) { |
430 | 0 | break; |
431 | 0 | } |
432 | | |
433 | 0 | rv = X25519_DerivePublicKey(&privk->u.ec.privateValue, &privk->u.ec.publicValue); |
434 | 0 | if (rv != CKR_OK) { |
435 | 0 | break; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | } |
439 | | |
440 | 0 | rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, |
441 | 0 | &privk->u.ec.publicValue); |
442 | 0 | if (rv != SECSuccess) |
443 | 0 | break; |
444 | 0 | pubk->u.ec.ecParams.arena = arena; |
445 | | /* Copy the rest of the params */ |
446 | 0 | rv = EC_CopyParams(arena, &(pubk->u.ec.ecParams), |
447 | 0 | &(privk->u.ec.ecParams)); |
448 | 0 | if (rv == SECSuccess) |
449 | 0 | return pubk; |
450 | 0 | } |
451 | 0 | break; |
452 | 0 | case NSSLOWKEYMLDSAKey: |
453 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
454 | 0 | sizeof(NSSLOWKEYPublicKey)); |
455 | 0 | if (pubk != NULL) { |
456 | 0 | SECStatus rv; |
457 | 0 | SECItem seed = { siBuffer, NULL, 0 }; |
458 | 0 | MLDSAPrivateKey newPrivKey; |
459 | |
|
460 | 0 | pubk->arena = arena; |
461 | 0 | pubk->keyType = privk->keyType; |
462 | | |
463 | | /* privatekey value is encoded (rho, K, tr, s1, s2, t0) */ |
464 | | /* publickey value is encoded (rho, t1) */ |
465 | | /* Future, we can calculate public key directly from |
466 | | * privatekey value as follows : |
467 | | * A^ = ExpandA(rho); |
468 | | * t = NTT-1(A^ o NSS(s1)) + s2 |
469 | | * (t1, t0) = Power2Round(t) |
470 | | * we now have rho and t1 so we can encode public key. |
471 | | * these functions are all specified in FIPS-204. For now |
472 | | * we just use the seed if it's a available and regenerate |
473 | | * both keys, and discard the private key. */ |
474 | 0 | if (privk->u.mldsa.seedLen == 0) { |
475 | 0 | PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED); |
476 | 0 | rv = SECFailure; |
477 | 0 | break; |
478 | 0 | } |
479 | 0 | seed.data = privk->u.mldsa.seed; |
480 | 0 | seed.len = privk->u.mldsa.seedLen; |
481 | 0 | rv = MLDSA_NewKey(privk->u.mldsa.paramSet, &seed, |
482 | 0 | &newPrivKey, &pubk->u.mldsa); |
483 | 0 | if (rv != SECSuccess) { |
484 | 0 | break; |
485 | 0 | } |
486 | 0 | PORT_SafeZero(&newPrivKey, sizeof(newPrivKey)); |
487 | 0 | return pubk; |
488 | 0 | } |
489 | 0 | break; |
490 | 0 | case NSSLOWKEYMLKEMKey: |
491 | 0 | pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena, |
492 | 0 | sizeof(NSSLOWKEYPublicKey)); |
493 | 0 | if (pubk != NULL) { |
494 | 0 | size_t pubKeyLen; |
495 | 0 | SECItem *item = NULL; |
496 | |
|
497 | 0 | pubk->arena = arena; |
498 | 0 | pubk->keyType = privk->keyType; |
499 | 0 | pubk->u.mlkem.mlkemParams = privk->u.mlkem.mlkemParams; |
500 | | /* privatekey value is encoded (dPKE||ePKE||H(ePKE)||z) */ |
501 | | /* publickey value is encoded (ePKE) */ |
502 | | /* size(dPKE) = 384k and size(ePKE)=384k+32, |
503 | | * so size(dPKE) = size(ePKE)-32 */ |
504 | 0 | pubKeyLen = sftk_kyber_pubKeyLen(pubk->u.mlkem.mlkemParams); |
505 | 0 | if (privk->u.mlkem.key.len < 2 * pubKeyLen) { |
506 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
507 | 0 | break; |
508 | 0 | } |
509 | 0 | item = SECITEM_AllocItem(arena, &pubk->u.mlkem.key, (int)pubKeyLen); |
510 | 0 | if (item == NULL) { |
511 | 0 | break; |
512 | 0 | } |
513 | 0 | PORT_Memcpy(pubk->u.mlkem.key.data, |
514 | 0 | privk->u.mlkem.key.data + pubKeyLen - 32, |
515 | 0 | pubKeyLen); |
516 | 0 | return pubk; |
517 | 0 | } |
518 | 0 | break; |
519 | | /* No Fortezza in Low Key implementations (Fortezza keys aren't |
520 | | * stored in our data base */ |
521 | 0 | default: |
522 | 0 | break; |
523 | 0 | } |
524 | | |
525 | 0 | PORT_FreeArena(arena, PR_TRUE); |
526 | 0 | return NULL; |
527 | 0 | } |
528 | | |
529 | | NSSLOWKEYPrivateKey * |
530 | | nsslowkey_CopyPrivateKey(NSSLOWKEYPrivateKey *privKey) |
531 | 0 | { |
532 | 0 | NSSLOWKEYPrivateKey *returnKey = NULL; |
533 | 0 | SECStatus rv = SECFailure; |
534 | 0 | PLArenaPool *poolp; |
535 | |
|
536 | 0 | if (!privKey) { |
537 | 0 | return NULL; |
538 | 0 | } |
539 | | |
540 | 0 | poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
541 | 0 | if (!poolp) { |
542 | 0 | return NULL; |
543 | 0 | } |
544 | | |
545 | 0 | returnKey = (NSSLOWKEYPrivateKey *)PORT_ArenaZAlloc(poolp, sizeof(NSSLOWKEYPrivateKey)); |
546 | 0 | if (!returnKey) { |
547 | 0 | rv = SECFailure; |
548 | 0 | goto loser; |
549 | 0 | } |
550 | | |
551 | 0 | returnKey->keyType = privKey->keyType; |
552 | 0 | returnKey->arena = poolp; |
553 | |
|
554 | 0 | switch (privKey->keyType) { |
555 | 0 | case NSSLOWKEYRSAKey: |
556 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.modulus), |
557 | 0 | &(privKey->u.rsa.modulus)); |
558 | 0 | if (rv != SECSuccess) |
559 | 0 | break; |
560 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.version), |
561 | 0 | &(privKey->u.rsa.version)); |
562 | 0 | if (rv != SECSuccess) |
563 | 0 | break; |
564 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.publicExponent), |
565 | 0 | &(privKey->u.rsa.publicExponent)); |
566 | 0 | if (rv != SECSuccess) |
567 | 0 | break; |
568 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.privateExponent), |
569 | 0 | &(privKey->u.rsa.privateExponent)); |
570 | 0 | if (rv != SECSuccess) |
571 | 0 | break; |
572 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime1), |
573 | 0 | &(privKey->u.rsa.prime1)); |
574 | 0 | if (rv != SECSuccess) |
575 | 0 | break; |
576 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.prime2), |
577 | 0 | &(privKey->u.rsa.prime2)); |
578 | 0 | if (rv != SECSuccess) |
579 | 0 | break; |
580 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent1), |
581 | 0 | &(privKey->u.rsa.exponent1)); |
582 | 0 | if (rv != SECSuccess) |
583 | 0 | break; |
584 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.exponent2), |
585 | 0 | &(privKey->u.rsa.exponent2)); |
586 | 0 | if (rv != SECSuccess) |
587 | 0 | break; |
588 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.rsa.coefficient), |
589 | 0 | &(privKey->u.rsa.coefficient)); |
590 | 0 | if (rv != SECSuccess) |
591 | 0 | break; |
592 | 0 | break; |
593 | 0 | case NSSLOWKEYDSAKey: |
594 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.publicValue), |
595 | 0 | &(privKey->u.dsa.publicValue)); |
596 | 0 | if (rv != SECSuccess) |
597 | 0 | break; |
598 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.privateValue), |
599 | 0 | &(privKey->u.dsa.privateValue)); |
600 | 0 | if (rv != SECSuccess) |
601 | 0 | break; |
602 | 0 | returnKey->u.dsa.params.arena = poolp; |
603 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.prime), |
604 | 0 | &(privKey->u.dsa.params.prime)); |
605 | 0 | if (rv != SECSuccess) |
606 | 0 | break; |
607 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.subPrime), |
608 | 0 | &(privKey->u.dsa.params.subPrime)); |
609 | 0 | if (rv != SECSuccess) |
610 | 0 | break; |
611 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dsa.params.base), |
612 | 0 | &(privKey->u.dsa.params.base)); |
613 | 0 | if (rv != SECSuccess) |
614 | 0 | break; |
615 | 0 | break; |
616 | 0 | case NSSLOWKEYDHKey: |
617 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.publicValue), |
618 | 0 | &(privKey->u.dh.publicValue)); |
619 | 0 | if (rv != SECSuccess) |
620 | 0 | break; |
621 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.privateValue), |
622 | 0 | &(privKey->u.dh.privateValue)); |
623 | 0 | if (rv != SECSuccess) |
624 | 0 | break; |
625 | 0 | returnKey->u.dsa.params.arena = poolp; |
626 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.prime), |
627 | 0 | &(privKey->u.dh.prime)); |
628 | 0 | if (rv != SECSuccess) |
629 | 0 | break; |
630 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.dh.base), |
631 | 0 | &(privKey->u.dh.base)); |
632 | 0 | if (rv != SECSuccess) |
633 | 0 | break; |
634 | 0 | break; |
635 | 0 | case NSSLOWKEYECKey: |
636 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.version), |
637 | 0 | &(privKey->u.ec.version)); |
638 | 0 | if (rv != SECSuccess) |
639 | 0 | break; |
640 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.publicValue), |
641 | 0 | &(privKey->u.ec.publicValue)); |
642 | 0 | if (rv != SECSuccess) |
643 | 0 | break; |
644 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.ec.privateValue), |
645 | 0 | &(privKey->u.ec.privateValue)); |
646 | 0 | if (rv != SECSuccess) |
647 | 0 | break; |
648 | 0 | returnKey->u.ec.ecParams.arena = poolp; |
649 | | /* Copy the rest of the params */ |
650 | 0 | rv = EC_CopyParams(poolp, &(returnKey->u.ec.ecParams), |
651 | 0 | &(privKey->u.ec.ecParams)); |
652 | 0 | if (rv != SECSuccess) |
653 | 0 | break; |
654 | 0 | break; |
655 | 0 | case NSSLOWKEYMLDSAKey: |
656 | 0 | returnKey->u.mldsa = privKey->u.mldsa; |
657 | 0 | rv = SECSuccess; |
658 | 0 | break; |
659 | 0 | case NSSLOWKEYMLKEMKey: |
660 | 0 | returnKey->u.mlkem.mlkemParams = privKey->u.mlkem.mlkemParams; |
661 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.mlkem.key), |
662 | 0 | &(privKey->u.mlkem.key)); |
663 | 0 | if (rv != SECSuccess) |
664 | 0 | break; |
665 | 0 | rv = SECITEM_CopyItem(poolp, &(returnKey->u.mlkem.seed), |
666 | 0 | &(privKey->u.mlkem.seed)); |
667 | 0 | if (rv != SECSuccess) |
668 | 0 | break; |
669 | 0 | break; |
670 | 0 | default: |
671 | 0 | rv = SECFailure; |
672 | 0 | } |
673 | | |
674 | 0 | loser: |
675 | |
|
676 | 0 | if (rv != SECSuccess) { |
677 | 0 | PORT_FreeArena(poolp, PR_TRUE); |
678 | 0 | returnKey = NULL; |
679 | 0 | } |
680 | |
|
681 | 0 | return returnKey; |
682 | 0 | } |