1 /* $NetBSD: ks_p12.c,v 1.2 2017/01/28 21:31:48 christos Exp $ */
2
3 /*
4 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "hx_locl.h"
37
38 struct ks_pkcs12 {
39 hx509_certs certs;
40 char *fn;
41 };
42
43 typedef int (*collector_func)(hx509_context,
44 struct hx509_collector *,
45 const void *, size_t,
46 const PKCS12_Attributes *);
47
48 struct type {
49 const heim_oid *oid;
50 collector_func func;
51 };
52
53 static void
54 parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
55 const void *, size_t, const PKCS12_Attributes *);
56
57
58 static const PKCS12_Attribute *
find_attribute(const PKCS12_Attributes * attrs,const heim_oid * oid)59 find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
60 {
61 size_t i;
62 if (attrs == NULL)
63 return NULL;
64 for (i = 0; i < attrs->len; i++)
65 if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
66 return &attrs->val[i];
67 return NULL;
68 }
69
70 static int
keyBag_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)71 keyBag_parser(hx509_context context,
72 struct hx509_collector *c,
73 const void *data, size_t length,
74 const PKCS12_Attributes *attrs)
75 {
76 const PKCS12_Attribute *attr;
77 PKCS8PrivateKeyInfo ki;
78 const heim_octet_string *os = NULL;
79 int ret;
80
81 attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);
82 if (attr)
83 os = &attr->attrValues;
84
85 ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
86 if (ret)
87 return ret;
88
89 _hx509_collector_private_key_add(context,
90 c,
91 &ki.privateKeyAlgorithm,
92 NULL,
93 &ki.privateKey,
94 os);
95 free_PKCS8PrivateKeyInfo(&ki);
96 return 0;
97 }
98
99 static int
ShroudedKeyBag_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)100 ShroudedKeyBag_parser(hx509_context context,
101 struct hx509_collector *c,
102 const void *data, size_t length,
103 const PKCS12_Attributes *attrs)
104 {
105 PKCS8EncryptedPrivateKeyInfo pk;
106 heim_octet_string content;
107 int ret;
108
109 memset(&pk, 0, sizeof(pk));
110
111 ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
112 if (ret)
113 return ret;
114
115 ret = _hx509_pbe_decrypt(context,
116 _hx509_collector_get_lock(c),
117 &pk.encryptionAlgorithm,
118 &pk.encryptedData,
119 &content);
120 free_PKCS8EncryptedPrivateKeyInfo(&pk);
121 if (ret)
122 return ret;
123
124 ret = keyBag_parser(context, c, content.data, content.length, attrs);
125 der_free_octet_string(&content);
126 return ret;
127 }
128
129 static int
certBag_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)130 certBag_parser(hx509_context context,
131 struct hx509_collector *c,
132 const void *data, size_t length,
133 const PKCS12_Attributes *attrs)
134 {
135 heim_error_t error = NULL;
136 heim_octet_string os;
137 hx509_cert cert;
138 PKCS12_CertBag cb;
139 int ret;
140
141 ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
142 if (ret)
143 return ret;
144
145 if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) {
146 free_PKCS12_CertBag(&cb);
147 return 0;
148 }
149
150 ret = decode_PKCS12_OctetString(cb.certValue.data,
151 cb.certValue.length,
152 &os,
153 NULL);
154 free_PKCS12_CertBag(&cb);
155 if (ret)
156 return ret;
157
158 cert = hx509_cert_init_data(context, os.data, os.length, &error);
159 der_free_octet_string(&os);
160 if (cert == NULL) {
161 ret = heim_error_get_code(error);
162 heim_release(error);
163 return ret;
164 }
165
166 ret = _hx509_collector_certs_add(context, c, cert);
167 if (ret) {
168 hx509_cert_free(cert);
169 return ret;
170 }
171
172 {
173 const PKCS12_Attribute *attr;
174 const heim_oid *oids[] = {
175 &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName
176 };
177 size_t i;
178
179 for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
180 const heim_oid *oid = oids[i];
181 attr = find_attribute(attrs, oid);
182 if (attr)
183 _hx509_set_cert_attribute(context, cert, oid,
184 &attr->attrValues);
185 }
186 }
187
188 hx509_cert_free(cert);
189
190 return 0;
191 }
192
193 static int
parse_safe_content(hx509_context context,struct hx509_collector * c,const unsigned char * p,size_t len)194 parse_safe_content(hx509_context context,
195 struct hx509_collector *c,
196 const unsigned char *p, size_t len)
197 {
198 PKCS12_SafeContents sc;
199 int ret;
200 size_t i;
201
202 memset(&sc, 0, sizeof(sc));
203
204 ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
205 if (ret)
206 return ret;
207
208 for (i = 0; i < sc.len ; i++)
209 parse_pkcs12_type(context,
210 c,
211 &sc.val[i].bagId,
212 sc.val[i].bagValue.data,
213 sc.val[i].bagValue.length,
214 sc.val[i].bagAttributes);
215
216 free_PKCS12_SafeContents(&sc);
217 return 0;
218 }
219
220 static int
safeContent_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)221 safeContent_parser(hx509_context context,
222 struct hx509_collector *c,
223 const void *data, size_t length,
224 const PKCS12_Attributes *attrs)
225 {
226 heim_octet_string os;
227 int ret;
228
229 ret = decode_PKCS12_OctetString(data, length, &os, NULL);
230 if (ret)
231 return ret;
232 ret = parse_safe_content(context, c, os.data, os.length);
233 der_free_octet_string(&os);
234 return ret;
235 }
236
237 static int
encryptedData_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)238 encryptedData_parser(hx509_context context,
239 struct hx509_collector *c,
240 const void *data, size_t length,
241 const PKCS12_Attributes *attrs)
242 {
243 heim_octet_string content;
244 heim_oid contentType;
245 int ret;
246
247 memset(&contentType, 0, sizeof(contentType));
248
249 ret = hx509_cms_decrypt_encrypted(context,
250 _hx509_collector_get_lock(c),
251 data, length,
252 &contentType,
253 &content);
254 if (ret)
255 return ret;
256
257 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
258 ret = parse_safe_content(context, c, content.data, content.length);
259
260 der_free_octet_string(&content);
261 der_free_oid(&contentType);
262 return ret;
263 }
264
265 static int
envelopedData_parser(hx509_context context,struct hx509_collector * c,const void * data,size_t length,const PKCS12_Attributes * attrs)266 envelopedData_parser(hx509_context context,
267 struct hx509_collector *c,
268 const void *data, size_t length,
269 const PKCS12_Attributes *attrs)
270 {
271 heim_octet_string content;
272 heim_oid contentType;
273 hx509_lock lock;
274 int ret;
275
276 memset(&contentType, 0, sizeof(contentType));
277
278 lock = _hx509_collector_get_lock(c);
279
280 ret = hx509_cms_unenvelope(context,
281 _hx509_lock_unlock_certs(lock),
282 0,
283 data, length,
284 NULL,
285 0,
286 &contentType,
287 &content);
288 if (ret) {
289 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
290 "PKCS12 failed to unenvelope");
291 return ret;
292 }
293
294 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
295 ret = parse_safe_content(context, c, content.data, content.length);
296
297 der_free_octet_string(&content);
298 der_free_oid(&contentType);
299
300 return ret;
301 }
302
303
304 struct type bagtypes[] = {
305 { &asn1_oid_id_pkcs12_keyBag, keyBag_parser },
306 { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
307 { &asn1_oid_id_pkcs12_certBag, certBag_parser },
308 { &asn1_oid_id_pkcs7_data, safeContent_parser },
309 { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser },
310 { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser }
311 };
312
313 static void
parse_pkcs12_type(hx509_context context,struct hx509_collector * c,const heim_oid * oid,const void * data,size_t length,const PKCS12_Attributes * attrs)314 parse_pkcs12_type(hx509_context context,
315 struct hx509_collector *c,
316 const heim_oid *oid,
317 const void *data, size_t length,
318 const PKCS12_Attributes *attrs)
319 {
320 size_t i;
321
322 for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
323 if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)
324 (*bagtypes[i].func)(context, c, data, length, attrs);
325 }
326
327 static int
p12_init(hx509_context context,hx509_certs certs,void ** data,int flags,const char * residue,hx509_lock lock)328 p12_init(hx509_context context,
329 hx509_certs certs, void **data, int flags,
330 const char *residue, hx509_lock lock)
331 {
332 struct ks_pkcs12 *p12;
333 size_t len;
334 void *buf;
335 PKCS12_PFX pfx;
336 PKCS12_AuthenticatedSafe as;
337 int ret;
338 size_t i;
339 struct hx509_collector *c;
340
341 *data = NULL;
342
343 if (lock == NULL)
344 lock = _hx509_empty_lock;
345
346 ret = _hx509_collector_alloc(context, lock, &c);
347 if (ret)
348 return ret;
349
350 p12 = calloc(1, sizeof(*p12));
351 if (p12 == NULL) {
352 ret = ENOMEM;
353 hx509_set_error_string(context, 0, ret, "out of memory");
354 goto out;
355 }
356
357 p12->fn = strdup(residue);
358 if (p12->fn == NULL) {
359 ret = ENOMEM;
360 hx509_set_error_string(context, 0, ret, "out of memory");
361 goto out;
362 }
363
364 if (flags & HX509_CERTS_CREATE) {
365 ret = hx509_certs_init(context, "MEMORY:ks-file-create",
366 0, lock, &p12->certs);
367 if (ret == 0)
368 *data = p12;
369 goto out;
370 }
371
372 ret = rk_undumpdata(residue, &buf, &len);
373 if (ret) {
374 hx509_clear_error_string(context);
375 goto out;
376 }
377
378 ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
379 rk_xfree(buf);
380 if (ret) {
381 hx509_set_error_string(context, 0, ret,
382 "Failed to decode the PFX in %s", residue);
383 goto out;
384 }
385
386 if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) {
387 free_PKCS12_PFX(&pfx);
388 ret = EINVAL;
389 hx509_set_error_string(context, 0, ret,
390 "PKCS PFX isn't a pkcs7-data container");
391 goto out;
392 }
393
394 if (pfx.authSafe.content == NULL) {
395 free_PKCS12_PFX(&pfx);
396 ret = EINVAL;
397 hx509_set_error_string(context, 0, ret,
398 "PKCS PFX missing data");
399 goto out;
400 }
401
402 {
403 heim_octet_string asdata;
404
405 ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
406 pfx.authSafe.content->length,
407 &asdata,
408 NULL);
409 free_PKCS12_PFX(&pfx);
410 if (ret) {
411 hx509_clear_error_string(context);
412 goto out;
413 }
414 ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
415 asdata.length,
416 &as,
417 NULL);
418 der_free_octet_string(&asdata);
419 if (ret) {
420 hx509_clear_error_string(context);
421 goto out;
422 }
423 }
424
425 for (i = 0; i < as.len; i++)
426 parse_pkcs12_type(context,
427 c,
428 &as.val[i].contentType,
429 as.val[i].content->data,
430 as.val[i].content->length,
431 NULL);
432
433 free_PKCS12_AuthenticatedSafe(&as);
434
435 ret = _hx509_collector_collect_certs(context, c, &p12->certs);
436 if (ret == 0)
437 *data = p12;
438
439 out:
440 _hx509_collector_free(c);
441
442 if (ret && p12) {
443 if (p12->fn)
444 free(p12->fn);
445 if (p12->certs)
446 hx509_certs_free(&p12->certs);
447 free(p12);
448 }
449
450 return ret;
451 }
452
453 static int
addBag(hx509_context context,PKCS12_AuthenticatedSafe * as,const heim_oid * oid,void * data,size_t length)454 addBag(hx509_context context,
455 PKCS12_AuthenticatedSafe *as,
456 const heim_oid *oid,
457 void *data,
458 size_t length)
459 {
460 void *ptr;
461 int ret;
462
463 ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
464 if (ptr == NULL) {
465 hx509_set_error_string(context, 0, ENOMEM, "out of memory");
466 return ENOMEM;
467 }
468 as->val = ptr;
469
470 ret = der_copy_oid(oid, &as->val[as->len].contentType);
471 if (ret) {
472 hx509_set_error_string(context, 0, ret, "out of memory");
473 return ret;
474 }
475
476 as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
477 if (as->val[as->len].content == NULL) {
478 der_free_oid(&as->val[as->len].contentType);
479 hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
480 return ENOMEM;
481 }
482
483 as->val[as->len].content->data = data;
484 as->val[as->len].content->length = length;
485
486 as->len++;
487
488 return 0;
489 }
490
491 static int
store_func(hx509_context context,void * ctx,hx509_cert c)492 store_func(hx509_context context, void *ctx, hx509_cert c)
493 {
494 PKCS12_AuthenticatedSafe *as = ctx;
495 PKCS12_OctetString os;
496 PKCS12_CertBag cb;
497 size_t size;
498 int ret;
499
500 memset(&os, 0, sizeof(os));
501 memset(&cb, 0, sizeof(cb));
502
503 os.data = NULL;
504 os.length = 0;
505
506 ret = hx509_cert_binary(context, c, &os);
507 if (ret)
508 return ret;
509
510 ASN1_MALLOC_ENCODE(PKCS12_OctetString,
511 cb.certValue.data,cb.certValue.length,
512 &os, &size, ret);
513 free(os.data);
514 if (ret)
515 goto out;
516 ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType);
517 if (ret) {
518 free_PKCS12_CertBag(&cb);
519 goto out;
520 }
521 ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
522 &cb, &size, ret);
523 free_PKCS12_CertBag(&cb);
524 if (ret)
525 goto out;
526
527 ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length);
528
529 if (_hx509_cert_private_key_exportable(c)) {
530 hx509_private_key key = _hx509_cert_private_key(c);
531 PKCS8PrivateKeyInfo pki;
532
533 memset(&pki, 0, sizeof(pki));
534
535 ret = der_parse_hex_heim_integer("00", &pki.version);
536 if (ret)
537 return ret;
538 ret = _hx509_private_key_oid(context, key,
539 &pki.privateKeyAlgorithm.algorithm);
540 if (ret) {
541 free_PKCS8PrivateKeyInfo(&pki);
542 return ret;
543 }
544 ret = _hx509_private_key_export(context,
545 _hx509_cert_private_key(c),
546 HX509_KEY_FORMAT_DER,
547 &pki.privateKey);
548 if (ret) {
549 free_PKCS8PrivateKeyInfo(&pki);
550 return ret;
551 }
552 /* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */
553
554 ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
555 &pki, &size, ret);
556 free_PKCS8PrivateKeyInfo(&pki);
557 if (ret)
558 return ret;
559
560 ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length);
561 if (ret)
562 return ret;
563 }
564
565 out:
566 return ret;
567 }
568
569 static int
p12_store(hx509_context context,hx509_certs certs,void * data,int flags,hx509_lock lock)570 p12_store(hx509_context context,
571 hx509_certs certs, void *data, int flags, hx509_lock lock)
572 {
573 struct ks_pkcs12 *p12 = data;
574 PKCS12_PFX pfx;
575 PKCS12_AuthenticatedSafe as;
576 PKCS12_OctetString asdata;
577 size_t size;
578 int ret;
579
580 memset(&as, 0, sizeof(as));
581 memset(&pfx, 0, sizeof(pfx));
582
583 ret = hx509_certs_iter_f(context, p12->certs, store_func, &as);
584 if (ret)
585 goto out;
586
587 ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
588 &as, &size, ret);
589 free_PKCS12_AuthenticatedSafe(&as);
590 if (ret)
591 return ret;
592
593 ret = der_parse_hex_heim_integer("03", &pfx.version);
594 if (ret) {
595 free(asdata.data);
596 goto out;
597 }
598
599 pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
600
601 ASN1_MALLOC_ENCODE(PKCS12_OctetString,
602 pfx.authSafe.content->data,
603 pfx.authSafe.content->length,
604 &asdata, &size, ret);
605 free(asdata.data);
606 if (ret)
607 goto out;
608
609 ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType);
610 if (ret)
611 goto out;
612
613 ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
614 &pfx, &size, ret);
615 if (ret)
616 goto out;
617
618 #if 0
619 const struct _hx509_password *pw;
620
621 pw = _hx509_lock_get_passwords(lock);
622 if (pw != NULL) {
623 pfx.macData = calloc(1, sizeof(*pfx.macData));
624 if (pfx.macData == NULL) {
625 ret = ENOMEM;
626 hx509_set_error_string(context, 0, ret, "malloc out of memory");
627 return ret;
628 }
629 if (pfx.macData == NULL) {
630 free(asdata.data);
631 goto out;
632 }
633 }
634 ret = calculate_hash(&aspath, pw, pfx.macData);
635 #endif
636
637 rk_dumpdata(p12->fn, asdata.data, asdata.length);
638 free(asdata.data);
639
640 out:
641 free_PKCS12_AuthenticatedSafe(&as);
642 free_PKCS12_PFX(&pfx);
643
644 return ret;
645 }
646
647
648 static int
p12_free(hx509_certs certs,void * data)649 p12_free(hx509_certs certs, void *data)
650 {
651 struct ks_pkcs12 *p12 = data;
652 hx509_certs_free(&p12->certs);
653 free(p12->fn);
654 free(p12);
655 return 0;
656 }
657
658 static int
p12_add(hx509_context context,hx509_certs certs,void * data,hx509_cert c)659 p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
660 {
661 struct ks_pkcs12 *p12 = data;
662 return hx509_certs_add(context, p12->certs, c);
663 }
664
665 static int
p12_iter_start(hx509_context context,hx509_certs certs,void * data,void ** cursor)666 p12_iter_start(hx509_context context,
667 hx509_certs certs,
668 void *data,
669 void **cursor)
670 {
671 struct ks_pkcs12 *p12 = data;
672 return hx509_certs_start_seq(context, p12->certs, cursor);
673 }
674
675 static int
p12_iter(hx509_context context,hx509_certs certs,void * data,void * cursor,hx509_cert * cert)676 p12_iter(hx509_context context,
677 hx509_certs certs,
678 void *data,
679 void *cursor,
680 hx509_cert *cert)
681 {
682 struct ks_pkcs12 *p12 = data;
683 return hx509_certs_next_cert(context, p12->certs, cursor, cert);
684 }
685
686 static int
p12_iter_end(hx509_context context,hx509_certs certs,void * data,void * cursor)687 p12_iter_end(hx509_context context,
688 hx509_certs certs,
689 void *data,
690 void *cursor)
691 {
692 struct ks_pkcs12 *p12 = data;
693 return hx509_certs_end_seq(context, p12->certs, cursor);
694 }
695
696 static struct hx509_keyset_ops keyset_pkcs12 = {
697 "PKCS12",
698 0,
699 p12_init,
700 p12_store,
701 p12_free,
702 p12_add,
703 NULL,
704 p12_iter_start,
705 p12_iter,
706 p12_iter_end,
707 NULL,
708 NULL,
709 NULL
710 };
711
712 void
_hx509_ks_pkcs12_register(hx509_context context)713 _hx509_ks_pkcs12_register(hx509_context context)
714 {
715 _hx509_ks_register(context, &keyset_pkcs12);
716 }
717