/src/nss/lib/pk11wrap/pk11pk12.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | /* |
6 | | * This file PKCS #12 fuctions that should really be moved to the |
7 | | * PKCS #12 directory, however we can't do that in a point release |
8 | | * because that will break binary compatibility, so we keep them here for now. |
9 | | */ |
10 | | |
11 | | #include "seccomon.h" |
12 | | #include "secmod.h" |
13 | | #include "secmodi.h" |
14 | | #include "secmodti.h" |
15 | | #include "secmodt.h" |
16 | | #include "pkcs11.h" |
17 | | #include "pk11func.h" |
18 | | #include "secitem.h" |
19 | | #include "keyhi.h" |
20 | | #include "secoid.h" |
21 | | #include "secasn1.h" |
22 | | #include "secerr.h" |
23 | | #include "prerror.h" |
24 | | |
25 | | /* These data structures should move to a common .h file shared between the |
26 | | * wrappers and the pkcs 12 code. */ |
27 | | |
28 | | /* |
29 | | ** RSA Raw Private Key structures |
30 | | */ |
31 | | |
32 | | /* member names from PKCS#1, section 7.2 */ |
33 | | struct SECKEYRSAPrivateKeyStr { |
34 | | PLArenaPool *arena; |
35 | | SECItem version; |
36 | | SECItem modulus; |
37 | | SECItem publicExponent; |
38 | | SECItem privateExponent; |
39 | | SECItem prime1; |
40 | | SECItem prime2; |
41 | | SECItem exponent1; |
42 | | SECItem exponent2; |
43 | | SECItem coefficient; |
44 | | }; |
45 | | typedef struct SECKEYRSAPrivateKeyStr SECKEYRSAPrivateKey; |
46 | | |
47 | | /* |
48 | | ** DSA Raw Private Key structures |
49 | | */ |
50 | | |
51 | | struct SECKEYDSAPrivateKeyStr { |
52 | | SECKEYPQGParams params; |
53 | | SECItem privateValue; |
54 | | }; |
55 | | typedef struct SECKEYDSAPrivateKeyStr SECKEYDSAPrivateKey; |
56 | | |
57 | | /* |
58 | | ** Diffie-Hellman Raw Private Key structures |
59 | | ** Structure member names suggested by PKCS#3. |
60 | | */ |
61 | | struct SECKEYDHPrivateKeyStr { |
62 | | PLArenaPool *arena; |
63 | | SECItem prime; |
64 | | SECItem base; |
65 | | SECItem privateValue; |
66 | | }; |
67 | | typedef struct SECKEYDHPrivateKeyStr SECKEYDHPrivateKey; |
68 | | |
69 | | /* |
70 | | ** Elliptic Curve Private Key structures |
71 | | ** <https://tools.ietf.org/html/rfc5915#section-3> |
72 | | */ |
73 | | struct SECKEYECPrivateKeyStr { |
74 | | PLArenaPool *arena; |
75 | | SECItem version; |
76 | | SECItem curveOID; /* optional/ignored */ |
77 | | SECItem publicValue; /* required (for now) */ |
78 | | SECItem privateValue; |
79 | | }; |
80 | | typedef struct SECKEYECPrivateKeyStr SECKEYECPrivateKey; |
81 | | |
82 | | /* |
83 | | ** raw private key object |
84 | | */ |
85 | | struct SECKEYRawPrivateKeyStr { |
86 | | PLArenaPool *arena; |
87 | | KeyType keyType; |
88 | | union { |
89 | | SECKEYRSAPrivateKey rsa; |
90 | | SECKEYDSAPrivateKey dsa; |
91 | | SECKEYDHPrivateKey dh; |
92 | | SECKEYECPrivateKey ec; |
93 | | } u; |
94 | | }; |
95 | | typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey; |
96 | | |
97 | | SEC_ASN1_MKSUB(SEC_AnyTemplate) |
98 | | SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
99 | | |
100 | | /* ASN1 Templates for new decoder/encoder */ |
101 | | /* |
102 | | * Attribute value for PKCS8 entries (static?) |
103 | | */ |
104 | | const SEC_ASN1Template SECKEY_AttributeTemplate[] = { |
105 | | { SEC_ASN1_SEQUENCE, |
106 | | 0, NULL, sizeof(SECKEYAttribute) }, |
107 | | { SEC_ASN1_OBJECT_ID, offsetof(SECKEYAttribute, attrType) }, |
108 | | { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(SECKEYAttribute, attrValue), |
109 | | SEC_ASN1_SUB(SEC_AnyTemplate) }, |
110 | | { 0 } |
111 | | }; |
112 | | |
113 | | const SEC_ASN1Template SECKEY_SetOfAttributeTemplate[] = { |
114 | | { SEC_ASN1_SET_OF, 0, SECKEY_AttributeTemplate }, |
115 | | }; |
116 | | |
117 | | const SEC_ASN1Template SECKEY_PrivateKeyInfoTemplate[] = { |
118 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPrivateKeyInfo) }, |
119 | | { SEC_ASN1_INTEGER, offsetof(SECKEYPrivateKeyInfo, version) }, |
120 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
121 | | offsetof(SECKEYPrivateKeyInfo, algorithm), |
122 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
123 | | { SEC_ASN1_OCTET_STRING, offsetof(SECKEYPrivateKeyInfo, privateKey) }, |
124 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
125 | | offsetof(SECKEYPrivateKeyInfo, attributes), |
126 | | SECKEY_SetOfAttributeTemplate }, |
127 | | { 0 } |
128 | | }; |
129 | | |
130 | | const SEC_ASN1Template SECKEY_PointerToPrivateKeyInfoTemplate[] = { |
131 | | { SEC_ASN1_POINTER, 0, SECKEY_PrivateKeyInfoTemplate } |
132 | | }; |
133 | | |
134 | | const SEC_ASN1Template SECKEY_RSAPrivateKeyExportTemplate[] = { |
135 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) }, |
136 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.version) }, |
137 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.modulus) }, |
138 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.publicExponent) }, |
139 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.privateExponent) }, |
140 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime1) }, |
141 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.prime2) }, |
142 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent1) }, |
143 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.exponent2) }, |
144 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.rsa.coefficient) }, |
145 | | { 0 } |
146 | | }; |
147 | | |
148 | | const SEC_ASN1Template SECKEY_DSAPrivateKeyExportTemplate[] = { |
149 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dsa.privateValue) }, |
150 | | }; |
151 | | |
152 | | const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = { |
153 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.privateValue) }, |
154 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.base) }, |
155 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.prime) }, |
156 | | }; |
157 | | |
158 | | SEC_ASN1_MKSUB(SEC_BitStringTemplate) |
159 | | SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) |
160 | | |
161 | | const SEC_ASN1Template SECKEY_ECPrivateKeyExportTemplate[] = { |
162 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) }, |
163 | | { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.ec.version) }, |
164 | | { SEC_ASN1_OCTET_STRING, |
165 | | offsetof(SECKEYRawPrivateKey, u.ec.privateValue) }, |
166 | | /* This value will always be ignored. u.ec.curveOID will always be |
167 | | * overriden with the outer AlgorithmID.parameters. */ |
168 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
169 | | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
170 | | SEC_ASN1_XTRN | 0, |
171 | | offsetof(SECKEYRawPrivateKey, u.ec.curveOID), |
172 | | SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, |
173 | | /* The public value is optional per RFC, but required in NSS. We |
174 | | * can't do scalar mult on ECs to get a raw point with PK11 APIs. */ |
175 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
176 | | SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | |
177 | | SEC_ASN1_XTRN | 1, |
178 | | offsetof(SECKEYRawPrivateKey, u.ec.publicValue), |
179 | | SEC_ASN1_SUB(SEC_BitStringTemplate) }, |
180 | | { 0 } |
181 | | }; |
182 | | |
183 | | /* The template operates a private key consisting only of private key. */ |
184 | | const SEC_ASN1Template SECKEY_ECRawPrivateKeyTemplate[] = { |
185 | | { SEC_ASN1_OCTET_STRING, |
186 | | offsetof(SECKEYRawPrivateKey, u.ec.privateValue) }, |
187 | | { 0 } |
188 | | }; |
189 | | |
190 | | const SEC_ASN1Template SECKEY_EncryptedPrivateKeyInfoTemplate[] = { |
191 | | { SEC_ASN1_SEQUENCE, |
192 | | 0, NULL, sizeof(SECKEYEncryptedPrivateKeyInfo) }, |
193 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
194 | | offsetof(SECKEYEncryptedPrivateKeyInfo, algorithm), |
195 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
196 | | { SEC_ASN1_OCTET_STRING, |
197 | | offsetof(SECKEYEncryptedPrivateKeyInfo, encryptedData) }, |
198 | | { 0 } |
199 | | }; |
200 | | |
201 | | const SEC_ASN1Template SECKEY_PointerToEncryptedPrivateKeyInfoTemplate[] = { |
202 | | { SEC_ASN1_POINTER, 0, SECKEY_EncryptedPrivateKeyInfoTemplate } |
203 | | }; |
204 | | |
205 | | SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_EncryptedPrivateKeyInfoTemplate) |
206 | | SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate) |
207 | | SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PrivateKeyInfoTemplate) |
208 | | SEC_ASN1_CHOOSER_IMPLEMENT(SECKEY_PointerToPrivateKeyInfoTemplate) |
209 | | |
210 | | /* |
211 | | * See bugzilla bug 125359 |
212 | | * Since NSS (via PKCS#11) wants to handle big integers as unsigned ints, |
213 | | * all of the templates above that en/decode into integers must be converted |
214 | | * from ASN.1's signed integer type. This is done by marking either the |
215 | | * source or destination (encoding or decoding, respectively) type as |
216 | | * siUnsignedInteger. |
217 | | */ |
218 | | |
219 | | static void |
220 | | prepare_rsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) |
221 | 0 | { |
222 | 0 | key->u.rsa.modulus.type = siUnsignedInteger; |
223 | 0 | key->u.rsa.publicExponent.type = siUnsignedInteger; |
224 | 0 | key->u.rsa.privateExponent.type = siUnsignedInteger; |
225 | 0 | key->u.rsa.prime1.type = siUnsignedInteger; |
226 | 0 | key->u.rsa.prime2.type = siUnsignedInteger; |
227 | 0 | key->u.rsa.exponent1.type = siUnsignedInteger; |
228 | 0 | key->u.rsa.exponent2.type = siUnsignedInteger; |
229 | 0 | key->u.rsa.coefficient.type = siUnsignedInteger; |
230 | 0 | } |
231 | | |
232 | | static void |
233 | | prepare_dsa_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) |
234 | 0 | { |
235 | 0 | key->u.dsa.privateValue.type = siUnsignedInteger; |
236 | 0 | key->u.dsa.params.prime.type = siUnsignedInteger; |
237 | 0 | key->u.dsa.params.subPrime.type = siUnsignedInteger; |
238 | 0 | key->u.dsa.params.base.type = siUnsignedInteger; |
239 | 0 | } |
240 | | |
241 | | static void |
242 | | prepare_dh_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) |
243 | 0 | { |
244 | 0 | key->u.dh.privateValue.type = siUnsignedInteger; |
245 | 0 | key->u.dh.prime.type = siUnsignedInteger; |
246 | 0 | key->u.dh.base.type = siUnsignedInteger; |
247 | 0 | } |
248 | | |
249 | | static void |
250 | | prepare_ec_priv_key_export_for_asn1(SECKEYRawPrivateKey *key) |
251 | 0 | { |
252 | 0 | key->u.ec.version.type = siUnsignedInteger; |
253 | 0 | key->u.ec.curveOID.type = siUnsignedInteger; |
254 | 0 | key->u.ec.privateValue.type = siUnsignedInteger; |
255 | 0 | key->u.ec.publicValue.type = siUnsignedInteger; |
256 | 0 | } |
257 | | |
258 | | SECStatus |
259 | | PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, SECItem *derPKI, |
260 | | SECItem *nickname, SECItem *publicValue, PRBool isPerm, |
261 | | PRBool isPrivate, unsigned int keyUsage, void *wincx) |
262 | 0 | { |
263 | 0 | return PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, derPKI, |
264 | 0 | nickname, publicValue, |
265 | 0 | isPerm, isPrivate, keyUsage, |
266 | 0 | NULL, wincx); |
267 | 0 | } |
268 | | |
269 | | SECStatus |
270 | | PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, SECItem *derPKI, |
271 | | SECItem *nickname, SECItem *publicValue, |
272 | | PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, |
273 | | SECKEYPrivateKey **privk, void *wincx) |
274 | 0 | { |
275 | 0 | SECKEYPrivateKeyInfo *pki = NULL; |
276 | 0 | PLArenaPool *temparena = NULL; |
277 | 0 | SECStatus rv = SECFailure; |
278 | |
|
279 | 0 | temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
280 | 0 | if (!temparena) { |
281 | 0 | return rv; |
282 | 0 | } |
283 | | |
284 | 0 | pki = PORT_ArenaZNew(temparena, SECKEYPrivateKeyInfo); |
285 | 0 | if (!pki) { |
286 | 0 | PORT_FreeArena(temparena, PR_FALSE); |
287 | 0 | return rv; |
288 | 0 | } |
289 | 0 | pki->arena = temparena; |
290 | |
|
291 | 0 | rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate, |
292 | 0 | derPKI); |
293 | 0 | if (rv != SECSuccess) { |
294 | | /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the |
295 | | * validity of the data in pki. The best we can do is free the arena |
296 | | * and return. */ |
297 | 0 | PORT_FreeArena(temparena, PR_TRUE); |
298 | 0 | return rv; |
299 | 0 | } |
300 | 0 | if (pki->privateKey.data == NULL) { |
301 | | /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey |
302 | | * is a zero-length octet string, free the arena and return a failure |
303 | | * to avoid trying to zero the corresponding SECItem in |
304 | | * SECKEY_DestroyPrivateKeyInfo(). */ |
305 | 0 | PORT_FreeArena(temparena, PR_TRUE); |
306 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
307 | 0 | return SECFailure; |
308 | 0 | } |
309 | | |
310 | 0 | rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname, |
311 | 0 | publicValue, isPerm, isPrivate, |
312 | 0 | keyUsage, privk, wincx); |
313 | | |
314 | | /* this zeroes the key and frees the arena */ |
315 | 0 | SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE /*freeit*/); |
316 | 0 | return rv; |
317 | 0 | } |
318 | | |
319 | | SECStatus |
320 | | PK11_ImportAndReturnPrivateKey(PK11SlotInfo *slot, SECKEYRawPrivateKey *lpk, |
321 | | SECItem *nickname, SECItem *publicValue, PRBool isPerm, |
322 | | PRBool isPrivate, unsigned int keyUsage, SECKEYPrivateKey **privk, |
323 | | void *wincx) |
324 | 0 | { |
325 | 0 | CK_BBOOL cktrue = CK_TRUE; |
326 | 0 | CK_BBOOL ckfalse = CK_FALSE; |
327 | 0 | CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; |
328 | 0 | CK_KEY_TYPE keyType = CKK_RSA; |
329 | 0 | CK_OBJECT_HANDLE objectID; |
330 | 0 | CK_ATTRIBUTE theTemplate[20]; |
331 | 0 | int templateCount = 0; |
332 | 0 | SECStatus rv = SECFailure; |
333 | 0 | CK_ATTRIBUTE *attrs; |
334 | 0 | CK_ATTRIBUTE *signedattr = NULL; |
335 | 0 | int signedcount = 0; |
336 | 0 | CK_ATTRIBUTE *ap; |
337 | 0 | SECItem *ck_id = NULL; |
338 | |
|
339 | 0 | attrs = theTemplate; |
340 | |
|
341 | 0 | PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); |
342 | 0 | attrs++; |
343 | 0 | PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); |
344 | 0 | attrs++; |
345 | 0 | PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse, |
346 | 0 | sizeof(CK_BBOOL)); |
347 | 0 | attrs++; |
348 | 0 | PK11_SETATTRS(attrs, CKA_SENSITIVE, isPrivate ? &cktrue : &ckfalse, |
349 | 0 | sizeof(CK_BBOOL)); |
350 | 0 | attrs++; |
351 | 0 | PK11_SETATTRS(attrs, CKA_PRIVATE, isPrivate ? &cktrue : &ckfalse, |
352 | 0 | sizeof(CK_BBOOL)); |
353 | 0 | attrs++; |
354 | |
|
355 | 0 | switch (lpk->keyType) { |
356 | 0 | case rsaKey: |
357 | 0 | keyType = CKK_RSA; |
358 | 0 | PK11_SETATTRS(attrs, CKA_UNWRAP, (keyUsage & KU_KEY_ENCIPHERMENT) ? &cktrue : &ckfalse, |
359 | 0 | sizeof(CK_BBOOL)); |
360 | 0 | attrs++; |
361 | 0 | PK11_SETATTRS(attrs, CKA_DECRYPT, (keyUsage & KU_DATA_ENCIPHERMENT) ? &cktrue : &ckfalse, |
362 | 0 | sizeof(CK_BBOOL)); |
363 | 0 | attrs++; |
364 | 0 | PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, |
365 | 0 | sizeof(CK_BBOOL)); |
366 | 0 | attrs++; |
367 | 0 | PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, |
368 | 0 | (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue |
369 | 0 | : &ckfalse, |
370 | 0 | sizeof(CK_BBOOL)); |
371 | 0 | attrs++; |
372 | 0 | ck_id = PK11_MakeIDFromPubKey(&lpk->u.rsa.modulus); |
373 | 0 | if (ck_id == NULL) { |
374 | 0 | goto loser; |
375 | 0 | } |
376 | 0 | PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); |
377 | 0 | attrs++; |
378 | 0 | if (nickname) { |
379 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
380 | 0 | attrs++; |
381 | 0 | } |
382 | 0 | signedattr = attrs; |
383 | 0 | PK11_SETATTRS(attrs, CKA_MODULUS, lpk->u.rsa.modulus.data, |
384 | 0 | lpk->u.rsa.modulus.len); |
385 | 0 | attrs++; |
386 | 0 | PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, |
387 | 0 | lpk->u.rsa.publicExponent.data, |
388 | 0 | lpk->u.rsa.publicExponent.len); |
389 | 0 | attrs++; |
390 | 0 | PK11_SETATTRS(attrs, CKA_PRIVATE_EXPONENT, |
391 | 0 | lpk->u.rsa.privateExponent.data, |
392 | 0 | lpk->u.rsa.privateExponent.len); |
393 | 0 | attrs++; |
394 | 0 | PK11_SETATTRS(attrs, CKA_PRIME_1, |
395 | 0 | lpk->u.rsa.prime1.data, |
396 | 0 | lpk->u.rsa.prime1.len); |
397 | 0 | attrs++; |
398 | 0 | PK11_SETATTRS(attrs, CKA_PRIME_2, |
399 | 0 | lpk->u.rsa.prime2.data, |
400 | 0 | lpk->u.rsa.prime2.len); |
401 | 0 | attrs++; |
402 | 0 | PK11_SETATTRS(attrs, CKA_EXPONENT_1, |
403 | 0 | lpk->u.rsa.exponent1.data, |
404 | 0 | lpk->u.rsa.exponent1.len); |
405 | 0 | attrs++; |
406 | 0 | PK11_SETATTRS(attrs, CKA_EXPONENT_2, |
407 | 0 | lpk->u.rsa.exponent2.data, |
408 | 0 | lpk->u.rsa.exponent2.len); |
409 | 0 | attrs++; |
410 | 0 | PK11_SETATTRS(attrs, CKA_COEFFICIENT, |
411 | 0 | lpk->u.rsa.coefficient.data, |
412 | 0 | lpk->u.rsa.coefficient.len); |
413 | 0 | attrs++; |
414 | 0 | break; |
415 | 0 | case dsaKey: |
416 | 0 | keyType = CKK_DSA; |
417 | | /* To make our intenal PKCS #11 module work correctly with |
418 | | * our database, we need to pass in the public key value for |
419 | | * this dsa key. We have a netscape only CKA_ value to do this. |
420 | | * Only send it to internal slots */ |
421 | 0 | if (publicValue == NULL) { |
422 | 0 | goto loser; |
423 | 0 | } |
424 | 0 | if (PK11_IsInternal(slot)) { |
425 | 0 | PK11_SETATTRS(attrs, CKA_NSS_DB, |
426 | 0 | publicValue->data, publicValue->len); |
427 | 0 | attrs++; |
428 | 0 | } |
429 | 0 | PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); |
430 | 0 | attrs++; |
431 | 0 | PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL)); |
432 | 0 | attrs++; |
433 | 0 | if (nickname) { |
434 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
435 | 0 | attrs++; |
436 | 0 | } |
437 | 0 | ck_id = PK11_MakeIDFromPubKey(publicValue); |
438 | 0 | if (ck_id == NULL) { |
439 | 0 | goto loser; |
440 | 0 | } |
441 | 0 | PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); |
442 | 0 | attrs++; |
443 | 0 | signedattr = attrs; |
444 | 0 | PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dsa.params.prime.data, |
445 | 0 | lpk->u.dsa.params.prime.len); |
446 | 0 | attrs++; |
447 | 0 | PK11_SETATTRS(attrs, CKA_SUBPRIME, lpk->u.dsa.params.subPrime.data, |
448 | 0 | lpk->u.dsa.params.subPrime.len); |
449 | 0 | attrs++; |
450 | 0 | PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dsa.params.base.data, |
451 | 0 | lpk->u.dsa.params.base.len); |
452 | 0 | attrs++; |
453 | 0 | PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dsa.privateValue.data, |
454 | 0 | lpk->u.dsa.privateValue.len); |
455 | 0 | attrs++; |
456 | 0 | break; |
457 | 0 | case dhKey: |
458 | 0 | keyType = CKK_DH; |
459 | | /* To make our intenal PKCS #11 module work correctly with |
460 | | * our database, we need to pass in the public key value for |
461 | | * this dh key. We have a netscape only CKA_ value to do this. |
462 | | * Only send it to internal slots */ |
463 | 0 | if (PK11_IsInternal(slot)) { |
464 | 0 | PK11_SETATTRS(attrs, CKA_NSS_DB, |
465 | 0 | publicValue->data, publicValue->len); |
466 | 0 | attrs++; |
467 | 0 | } |
468 | 0 | PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); |
469 | 0 | attrs++; |
470 | 0 | if (nickname) { |
471 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
472 | 0 | attrs++; |
473 | 0 | } |
474 | 0 | ck_id = PK11_MakeIDFromPubKey(publicValue); |
475 | 0 | if (ck_id == NULL) { |
476 | 0 | goto loser; |
477 | 0 | } |
478 | 0 | PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); |
479 | 0 | attrs++; |
480 | 0 | signedattr = attrs; |
481 | 0 | PK11_SETATTRS(attrs, CKA_PRIME, lpk->u.dh.prime.data, |
482 | 0 | lpk->u.dh.prime.len); |
483 | 0 | attrs++; |
484 | 0 | PK11_SETATTRS(attrs, CKA_BASE, lpk->u.dh.base.data, |
485 | 0 | lpk->u.dh.base.len); |
486 | 0 | attrs++; |
487 | 0 | PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.dh.privateValue.data, |
488 | 0 | lpk->u.dh.privateValue.len); |
489 | 0 | attrs++; |
490 | 0 | break; |
491 | 0 | case ecKey: |
492 | 0 | keyType = CKK_EC; |
493 | 0 | if (lpk->u.ec.publicValue.len != 0) { |
494 | 0 | if (PK11_IsInternal(slot)) { |
495 | 0 | PK11_SETATTRS(attrs, CKA_NSS_DB, |
496 | 0 | lpk->u.ec.publicValue.data, |
497 | 0 | lpk->u.ec.publicValue.len); |
498 | 0 | attrs++; |
499 | 0 | } |
500 | 0 | } |
501 | |
|
502 | 0 | PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse, |
503 | 0 | sizeof(CK_BBOOL)); |
504 | 0 | attrs++; |
505 | 0 | PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, |
506 | 0 | (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue |
507 | 0 | : &ckfalse, |
508 | 0 | sizeof(CK_BBOOL)); |
509 | 0 | attrs++; |
510 | 0 | PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse, |
511 | 0 | sizeof(CK_BBOOL)); |
512 | 0 | attrs++; |
513 | 0 | if (nickname) { |
514 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
515 | 0 | attrs++; |
516 | 0 | } |
517 | 0 | ck_id = PK11_MakeIDFromPubKey(&lpk->u.ec.publicValue); |
518 | 0 | if (ck_id == NULL) { |
519 | 0 | goto loser; |
520 | 0 | } |
521 | 0 | PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); |
522 | 0 | attrs++; |
523 | | /* No signed attrs for EC */ |
524 | | /* curveOID always is a copy of AlgorithmID.parameters. */ |
525 | 0 | PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data, |
526 | 0 | lpk->u.ec.curveOID.len); |
527 | 0 | attrs++; |
528 | 0 | PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data, |
529 | 0 | lpk->u.ec.privateValue.len); |
530 | 0 | attrs++; |
531 | 0 | PK11_SETATTRS(attrs, CKA_EC_POINT, lpk->u.ec.publicValue.data, |
532 | 0 | lpk->u.ec.publicValue.len); |
533 | 0 | attrs++; |
534 | 0 | break; |
535 | 0 | case edKey: |
536 | 0 | keyType = CKK_EC_EDWARDS; |
537 | 0 | PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL)); |
538 | 0 | attrs++; |
539 | 0 | if (nickname) { |
540 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
541 | 0 | attrs++; |
542 | 0 | } |
543 | | |
544 | | /* No signed attrs for EC */ |
545 | | /* curveOID always is a copy of AlgorithmID.parameters. */ |
546 | 0 | PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data, |
547 | 0 | lpk->u.ec.curveOID.len); |
548 | 0 | attrs++; |
549 | 0 | PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data, |
550 | 0 | lpk->u.ec.privateValue.len); |
551 | 0 | attrs++; |
552 | 0 | break; |
553 | 0 | case ecMontKey: |
554 | 0 | keyType = CKK_EC_MONTGOMERY; |
555 | |
|
556 | 0 | PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); |
557 | 0 | attrs++; |
558 | |
|
559 | 0 | if (nickname) { |
560 | 0 | PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len); |
561 | 0 | attrs++; |
562 | 0 | } |
563 | | |
564 | | /* No signed attrs for EC */ |
565 | | /* curveOID always is a copy of AlgorithmID.parameters. */ |
566 | 0 | PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data, |
567 | 0 | lpk->u.ec.curveOID.len); |
568 | 0 | attrs++; |
569 | |
|
570 | 0 | PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data, |
571 | 0 | lpk->u.ec.privateValue.len); |
572 | 0 | attrs++; |
573 | 0 | break; |
574 | 0 | default: |
575 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
576 | 0 | goto loser; |
577 | 0 | } |
578 | 0 | templateCount = attrs - theTemplate; |
579 | 0 | PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE)); |
580 | 0 | if (lpk->keyType != ecKey && lpk->keyType != edKey && lpk->keyType != ecMontKey) { |
581 | 0 | PORT_Assert(signedattr); |
582 | 0 | signedcount = attrs - signedattr; |
583 | 0 | for (ap = signedattr; signedcount; ap++, signedcount--) { |
584 | 0 | pk11_SignedToUnsigned(ap); |
585 | 0 | } |
586 | 0 | } |
587 | |
|
588 | 0 | rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE, |
589 | 0 | theTemplate, templateCount, isPerm, &objectID); |
590 | | |
591 | | /* create and return a SECKEYPrivateKey */ |
592 | 0 | if (rv == SECSuccess && privk != NULL) { |
593 | 0 | *privk = PK11_MakePrivKey(slot, lpk->keyType, !isPerm, objectID, wincx); |
594 | 0 | if (*privk == NULL) { |
595 | 0 | rv = SECFailure; |
596 | 0 | } |
597 | 0 | } |
598 | 0 | loser: |
599 | 0 | if (ck_id) { |
600 | 0 | SECITEM_ZfreeItem(ck_id, PR_TRUE); |
601 | 0 | } |
602 | 0 | return rv; |
603 | 0 | } |
604 | | |
605 | | SECStatus |
606 | | PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, |
607 | | SECKEYPrivateKeyInfo *pki, SECItem *nickname, SECItem *publicValue, |
608 | | PRBool isPerm, PRBool isPrivate, unsigned int keyUsage, |
609 | | SECKEYPrivateKey **privk, void *wincx) |
610 | 0 | { |
611 | 0 | SECStatus rv = SECFailure; |
612 | 0 | SECKEYRawPrivateKey *lpk = NULL; |
613 | 0 | const SEC_ASN1Template *keyTemplate, *paramTemplate; |
614 | 0 | void *paramDest = NULL; |
615 | 0 | PLArenaPool *arena = NULL; |
616 | |
|
617 | 0 | arena = PORT_NewArena(2048); |
618 | 0 | if (!arena) { |
619 | 0 | return SECFailure; |
620 | 0 | } |
621 | | |
622 | | /* need to change this to use RSA/DSA keys */ |
623 | 0 | lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena, |
624 | 0 | sizeof(SECKEYRawPrivateKey)); |
625 | 0 | if (lpk == NULL) { |
626 | 0 | goto loser; |
627 | 0 | } |
628 | 0 | lpk->arena = arena; |
629 | |
|
630 | 0 | switch (SECOID_GetAlgorithmTag(&pki->algorithm)) { |
631 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
632 | 0 | prepare_rsa_priv_key_export_for_asn1(lpk); |
633 | 0 | keyTemplate = SECKEY_RSAPrivateKeyExportTemplate; |
634 | 0 | paramTemplate = NULL; |
635 | 0 | paramDest = NULL; |
636 | 0 | lpk->keyType = rsaKey; |
637 | 0 | break; |
638 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE: |
639 | 0 | prepare_dsa_priv_key_export_for_asn1(lpk); |
640 | 0 | keyTemplate = SECKEY_DSAPrivateKeyExportTemplate; |
641 | 0 | paramTemplate = SECKEY_PQGParamsTemplate; |
642 | 0 | paramDest = &(lpk->u.dsa.params); |
643 | 0 | lpk->keyType = dsaKey; |
644 | 0 | break; |
645 | 0 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: |
646 | 0 | if (!publicValue) { |
647 | 0 | goto loser; |
648 | 0 | } |
649 | 0 | prepare_dh_priv_key_export_for_asn1(lpk); |
650 | 0 | keyTemplate = SECKEY_DHPrivateKeyExportTemplate; |
651 | 0 | paramTemplate = NULL; |
652 | 0 | paramDest = NULL; |
653 | 0 | lpk->keyType = dhKey; |
654 | 0 | break; |
655 | 0 | case SEC_OID_ED25519_PUBLIC_KEY: |
656 | 0 | keyTemplate = SECKEY_ECRawPrivateKeyTemplate; |
657 | 0 | paramTemplate = NULL; |
658 | 0 | paramDest = NULL; |
659 | 0 | lpk->keyType = edKey; |
660 | 0 | break; |
661 | 0 | case SEC_OID_X25519: |
662 | 0 | keyTemplate = SECKEY_ECRawPrivateKeyTemplate; |
663 | 0 | paramTemplate = NULL; |
664 | 0 | paramDest = NULL; |
665 | 0 | lpk->keyType = ecMontKey; |
666 | 0 | break; |
667 | 0 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
668 | 0 | prepare_ec_priv_key_export_for_asn1(lpk); |
669 | 0 | keyTemplate = SECKEY_ECPrivateKeyExportTemplate; |
670 | 0 | paramTemplate = NULL; |
671 | 0 | paramDest = NULL; |
672 | 0 | lpk->keyType = ecKey; |
673 | 0 | break; |
674 | | |
675 | 0 | default: |
676 | 0 | keyTemplate = NULL; |
677 | 0 | paramTemplate = NULL; |
678 | 0 | paramDest = NULL; |
679 | 0 | break; |
680 | 0 | } |
681 | | |
682 | 0 | if (!keyTemplate) { |
683 | 0 | goto loser; |
684 | 0 | } |
685 | | |
686 | | /* decode the private key and any algorithm parameters */ |
687 | 0 | rv = SEC_QuickDERDecodeItem(arena, lpk, keyTemplate, &pki->privateKey); |
688 | 0 | if (rv != SECSuccess) { |
689 | 0 | goto loser; |
690 | 0 | } |
691 | | |
692 | 0 | if (lpk->keyType == ecKey) { |
693 | | /* Convert length in bits to length in bytes. */ |
694 | 0 | lpk->u.ec.publicValue.len >>= 3; |
695 | | |
696 | | /* Always override curveOID, we're ignoring any given value. */ |
697 | 0 | rv = SECITEM_CopyItem(arena, &lpk->u.ec.curveOID, |
698 | 0 | &pki->algorithm.parameters); |
699 | 0 | if (rv != SECSuccess) { |
700 | 0 | goto loser; |
701 | 0 | } |
702 | 0 | } |
703 | | |
704 | 0 | if (lpk->keyType == edKey || lpk->keyType == ecMontKey) { |
705 | | /* SECKEY_ECRawPrivateKeyTemplate (used for both key types) does not reference |
706 | | publicKey, curveOID, ec verion. */ |
707 | 0 | if (pki->algorithm.parameters.len != 0) { |
708 | | /* Currently supporting only (Pure)Ed25519/X25519 .*/ |
709 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
710 | 0 | goto loser; |
711 | 0 | } |
712 | | |
713 | 0 | SECOidData *oid25519 = SECOID_FindOIDByTag(SECOID_GetAlgorithmTag(&pki->algorithm)); |
714 | 0 | if (!oid25519) { |
715 | 0 | goto loser; |
716 | 0 | } |
717 | | |
718 | 0 | if (!SECITEM_AllocItem(arena, &lpk->u.ec.curveOID, oid25519->oid.len + 2)) { |
719 | 0 | goto loser; |
720 | 0 | } |
721 | 0 | lpk->u.ec.curveOID.data[0] = SEC_ASN1_OBJECT_ID; |
722 | 0 | lpk->u.ec.curveOID.data[1] = oid25519->oid.len; |
723 | 0 | PORT_Memcpy(lpk->u.ec.curveOID.data + 2, oid25519->oid.data, oid25519->oid.len); |
724 | 0 | } |
725 | | |
726 | 0 | if (paramDest && paramTemplate) { |
727 | 0 | rv = SEC_ASN1DecodeItem(arena, paramDest, paramTemplate, |
728 | 0 | &(pki->algorithm.parameters)); |
729 | 0 | if (rv != SECSuccess) { |
730 | 0 | goto loser; |
731 | 0 | } |
732 | 0 | } |
733 | | |
734 | 0 | rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm, |
735 | 0 | isPrivate, keyUsage, privk, wincx); |
736 | 0 | loser: |
737 | 0 | if (arena != NULL) { |
738 | 0 | PORT_FreeArena(arena, PR_TRUE); |
739 | 0 | } |
740 | |
|
741 | 0 | return rv; |
742 | 0 | } |
743 | | |
744 | | SECStatus |
745 | | PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, SECKEYPrivateKeyInfo *pki, |
746 | | SECItem *nickname, SECItem *publicValue, PRBool isPerm, |
747 | | PRBool isPrivate, unsigned int keyUsage, void *wincx) |
748 | 0 | { |
749 | 0 | return PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname, |
750 | 0 | publicValue, isPerm, isPrivate, keyUsage, NULL, wincx); |
751 | 0 | } |
752 | | |
753 | | SECItem * |
754 | | PK11_ExportDERPrivateKeyInfo(SECKEYPrivateKey *pk, void *wincx) |
755 | 0 | { |
756 | 0 | SECKEYPrivateKeyInfo *pki = PK11_ExportPrivKeyInfo(pk, wincx); |
757 | 0 | SECItem *derPKI; |
758 | |
|
759 | 0 | if (!pki) { |
760 | 0 | return NULL; |
761 | 0 | } |
762 | 0 | derPKI = SEC_ASN1EncodeItem(NULL, NULL, pki, |
763 | 0 | SECKEY_PrivateKeyInfoTemplate); |
764 | 0 | SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE); |
765 | 0 | return derPKI; |
766 | 0 | } |
767 | | |
768 | | static PRBool |
769 | | ReadAttribute(SECKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type, |
770 | | PLArenaPool *arena, SECItem *output) |
771 | 0 | { |
772 | 0 | SECStatus rv = PK11_ReadAttribute(key->pkcs11Slot, key->pkcs11ID, type, |
773 | 0 | arena, output); |
774 | 0 | return rv == SECSuccess; |
775 | 0 | } |
776 | | |
777 | | /* |
778 | | * The caller is responsible for freeing the return value by passing it to |
779 | | * SECKEY_DestroyPrivateKeyInfo(..., PR_TRUE). |
780 | | */ |
781 | | SECKEYPrivateKeyInfo * |
782 | | PK11_ExportPrivKeyInfo(SECKEYPrivateKey *pk, void *wincx) |
783 | 0 | { |
784 | | /* PrivateKeyInfo version (always zero) */ |
785 | 0 | const unsigned char pkiVersion = 0; |
786 | | /* RSAPrivateKey version (always zero) */ |
787 | 0 | const unsigned char rsaVersion = 0; |
788 | | /* ECPrivateKey version (always one) */ |
789 | 0 | const unsigned char ecVersion = 1; |
790 | 0 | PLArenaPool *arena = NULL; |
791 | 0 | SECKEYRawPrivateKey rawKey; |
792 | 0 | SECKEYPrivateKeyInfo *pki; |
793 | 0 | SECItem *encoded; |
794 | 0 | const SEC_ASN1Template *keyTemplate; |
795 | 0 | SECStatus rv; |
796 | |
|
797 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
798 | 0 | if (!arena) { |
799 | 0 | goto loser; |
800 | 0 | } |
801 | 0 | memset(&rawKey, 0, sizeof(rawKey)); |
802 | 0 | rawKey.keyType = pk->keyType; |
803 | 0 | pki = PORT_ArenaZNew(arena, SECKEYPrivateKeyInfo); |
804 | 0 | if (!pki) { |
805 | 0 | goto loser; |
806 | 0 | } |
807 | | |
808 | 0 | switch (pk->keyType) { |
809 | 0 | case rsaKey: { |
810 | 0 | rawKey.u.rsa.version.type = siUnsignedInteger; |
811 | 0 | rawKey.u.rsa.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); |
812 | 0 | if (!rawKey.u.rsa.version.data) { |
813 | 0 | goto loser; |
814 | 0 | } |
815 | | |
816 | 0 | rawKey.u.rsa.version.data[0] = rsaVersion; |
817 | 0 | rawKey.u.rsa.version.len = 1; |
818 | | |
819 | | /* Read the component attributes of the private key */ |
820 | 0 | prepare_rsa_priv_key_export_for_asn1(&rawKey); |
821 | 0 | if (!ReadAttribute(pk, CKA_MODULUS, arena, &rawKey.u.rsa.modulus) || |
822 | 0 | !ReadAttribute(pk, CKA_PUBLIC_EXPONENT, arena, |
823 | 0 | &rawKey.u.rsa.publicExponent) || |
824 | 0 | !ReadAttribute(pk, CKA_PRIVATE_EXPONENT, arena, |
825 | 0 | &rawKey.u.rsa.privateExponent) || |
826 | 0 | !ReadAttribute(pk, CKA_PRIME_1, arena, &rawKey.u.rsa.prime1) || |
827 | 0 | !ReadAttribute(pk, CKA_PRIME_2, arena, &rawKey.u.rsa.prime2) || |
828 | 0 | !ReadAttribute(pk, CKA_EXPONENT_1, arena, |
829 | 0 | &rawKey.u.rsa.exponent1) || |
830 | 0 | !ReadAttribute(pk, CKA_EXPONENT_2, arena, |
831 | 0 | &rawKey.u.rsa.exponent2) || |
832 | 0 | !ReadAttribute(pk, CKA_COEFFICIENT, arena, |
833 | 0 | &rawKey.u.rsa.coefficient)) { |
834 | 0 | goto loser; |
835 | 0 | } |
836 | | |
837 | 0 | keyTemplate = SECKEY_RSAPrivateKeyExportTemplate; |
838 | |
|
839 | 0 | rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); |
840 | 0 | if (rv != SECSuccess) { |
841 | 0 | goto loser; |
842 | 0 | } |
843 | |
|
844 | 0 | } break; |
845 | 0 | case ecKey: { |
846 | 0 | rawKey.u.ec.version.type = siUnsignedInteger; |
847 | 0 | rawKey.u.ec.version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); |
848 | 0 | if (!rawKey.u.ec.version.data) { |
849 | 0 | goto loser; |
850 | 0 | } |
851 | 0 | rawKey.u.ec.version.data[0] = ecVersion; |
852 | 0 | rawKey.u.ec.version.len = 1; |
853 | |
|
854 | 0 | SECItem curveOID; |
855 | | /* Read the component attributes of the private key */ |
856 | 0 | prepare_ec_priv_key_export_for_asn1(&rawKey); |
857 | 0 | if (!ReadAttribute(pk, CKA_VALUE, arena, |
858 | 0 | &rawKey.u.ec.privateValue) || |
859 | 0 | !ReadAttribute(pk, CKA_EC_PARAMS, arena, &curveOID)) { |
860 | 0 | goto loser; |
861 | 0 | } |
862 | 0 | if (!ReadAttribute(pk, CKA_EC_POINT, arena, |
863 | 0 | &rawKey.u.ec.publicValue)) { |
864 | 0 | SECKEYPublicKey *pubk = SECKEY_ConvertToPublicKey(pk); |
865 | 0 | if (pubk == NULL) |
866 | 0 | goto loser; |
867 | 0 | rv = SECITEM_CopyItem(arena, &rawKey.u.ec.publicValue, &pubk->u.ec.publicValue); |
868 | 0 | SECKEY_DestroyPublicKey(pubk); |
869 | 0 | if (rv != SECSuccess) { |
870 | 0 | goto loser; |
871 | 0 | } |
872 | 0 | } |
873 | | |
874 | 0 | keyTemplate = SECKEY_ECPrivateKeyExportTemplate; |
875 | | /* Convert length in bytes to length in bits. */ |
876 | 0 | rawKey.u.ec.publicValue.len <<= 3; |
877 | |
|
878 | 0 | rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ANSIX962_EC_PUBLIC_KEY, &curveOID); |
879 | 0 | if (rv != SECSuccess) { |
880 | 0 | goto loser; |
881 | 0 | } |
882 | |
|
883 | 0 | } break; |
884 | 0 | case edKey: { |
885 | 0 | if (!ReadAttribute(pk, CKA_VALUE, arena, |
886 | 0 | &rawKey.u.ec.privateValue)) { |
887 | 0 | goto loser; |
888 | 0 | } |
889 | | |
890 | 0 | keyTemplate = SECKEY_ECRawPrivateKeyTemplate; |
891 | | /* Currently, Ed25519 does not support any parameter. */ |
892 | 0 | rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_ED25519_PUBLIC_KEY, NULL); |
893 | 0 | if (rv != SECSuccess) { |
894 | 0 | goto loser; |
895 | 0 | } |
896 | 0 | } break; |
897 | 0 | case ecMontKey: { |
898 | 0 | if (!ReadAttribute(pk, CKA_VALUE, arena, |
899 | 0 | &rawKey.u.ec.privateValue)) { |
900 | 0 | goto loser; |
901 | 0 | } |
902 | | |
903 | 0 | keyTemplate = SECKEY_ECRawPrivateKeyTemplate; |
904 | | /* Currently, X25519 does not support any parameter. */ |
905 | 0 | rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, SEC_OID_X25519, NULL); |
906 | 0 | if (rv != SECSuccess) { |
907 | 0 | goto loser; |
908 | 0 | } |
909 | 0 | } break; |
910 | 0 | default: { |
911 | 0 | PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
912 | 0 | goto loser; |
913 | 0 | } |
914 | 0 | } |
915 | | |
916 | 0 | encoded = SEC_ASN1EncodeItem(arena, &pki->privateKey, &rawKey, keyTemplate); |
917 | 0 | if (!encoded) { |
918 | 0 | goto loser; |
919 | 0 | } |
920 | 0 | pki->version.type = siUnsignedInteger; |
921 | 0 | pki->version.data = (unsigned char *)PORT_ArenaAlloc(arena, 1); |
922 | 0 | if (!pki->version.data) { |
923 | 0 | goto loser; |
924 | 0 | } |
925 | 0 | pki->version.data[0] = pkiVersion; |
926 | 0 | pki->version.len = 1; |
927 | 0 | pki->arena = arena; |
928 | |
|
929 | 0 | return pki; |
930 | | |
931 | 0 | loser: |
932 | 0 | if (arena) { |
933 | 0 | PORT_FreeArena(arena, PR_TRUE); |
934 | 0 | } |
935 | 0 | return NULL; |
936 | 0 | } |