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