1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfrstruct ks_pkcs12 {
37178825Sdfr    hx509_certs certs;
38178825Sdfr    char *fn;
39178825Sdfr};
40178825Sdfr
41178825Sdfrtypedef int (*collector_func)(hx509_context,
42178825Sdfr			      struct hx509_collector *,
43178825Sdfr			      const void *, size_t,
44178825Sdfr			      const PKCS12_Attributes *);
45178825Sdfr
46178825Sdfrstruct type {
47233294Sstas    const heim_oid *oid;
48178825Sdfr    collector_func func;
49178825Sdfr};
50178825Sdfr
51178825Sdfrstatic void
52233294Sstasparse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
53178825Sdfr		  const void *, size_t, const PKCS12_Attributes *);
54178825Sdfr
55178825Sdfr
56178825Sdfrstatic const PKCS12_Attribute *
57178825Sdfrfind_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
58178825Sdfr{
59233294Sstas    size_t i;
60178825Sdfr    if (attrs == NULL)
61178825Sdfr	return NULL;
62178825Sdfr    for (i = 0; i < attrs->len; i++)
63178825Sdfr	if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
64178825Sdfr	    return &attrs->val[i];
65178825Sdfr    return NULL;
66178825Sdfr}
67178825Sdfr
68178825Sdfrstatic int
69178825SdfrkeyBag_parser(hx509_context context,
70233294Sstas	      struct hx509_collector *c,
71178825Sdfr	      const void *data, size_t length,
72178825Sdfr	      const PKCS12_Attributes *attrs)
73178825Sdfr{
74178825Sdfr    const PKCS12_Attribute *attr;
75178825Sdfr    PKCS8PrivateKeyInfo ki;
76178825Sdfr    const heim_octet_string *os = NULL;
77178825Sdfr    int ret;
78178825Sdfr
79233294Sstas    attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);
80178825Sdfr    if (attr)
81178825Sdfr	os = &attr->attrValues;
82178825Sdfr
83178825Sdfr    ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
84178825Sdfr    if (ret)
85178825Sdfr	return ret;
86233294Sstas
87178825Sdfr    _hx509_collector_private_key_add(context,
88178825Sdfr				     c,
89178825Sdfr				     &ki.privateKeyAlgorithm,
90178825Sdfr				     NULL,
91178825Sdfr				     &ki.privateKey,
92178825Sdfr				     os);
93178825Sdfr    free_PKCS8PrivateKeyInfo(&ki);
94178825Sdfr    return 0;
95178825Sdfr}
96178825Sdfr
97178825Sdfrstatic int
98178825SdfrShroudedKeyBag_parser(hx509_context context,
99233294Sstas		      struct hx509_collector *c,
100178825Sdfr		      const void *data, size_t length,
101178825Sdfr		      const PKCS12_Attributes *attrs)
102178825Sdfr{
103178825Sdfr    PKCS8EncryptedPrivateKeyInfo pk;
104178825Sdfr    heim_octet_string content;
105178825Sdfr    int ret;
106233294Sstas
107178825Sdfr    memset(&pk, 0, sizeof(pk));
108233294Sstas
109178825Sdfr    ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
110178825Sdfr    if (ret)
111178825Sdfr	return ret;
112178825Sdfr
113178825Sdfr    ret = _hx509_pbe_decrypt(context,
114178825Sdfr			     _hx509_collector_get_lock(c),
115178825Sdfr			     &pk.encryptionAlgorithm,
116178825Sdfr			     &pk.encryptedData,
117178825Sdfr			     &content);
118178825Sdfr    free_PKCS8EncryptedPrivateKeyInfo(&pk);
119178825Sdfr    if (ret)
120178825Sdfr	return ret;
121178825Sdfr
122178825Sdfr    ret = keyBag_parser(context, c, content.data, content.length, attrs);
123178825Sdfr    der_free_octet_string(&content);
124178825Sdfr    return ret;
125178825Sdfr}
126178825Sdfr
127178825Sdfrstatic int
128178825SdfrcertBag_parser(hx509_context context,
129233294Sstas	       struct hx509_collector *c,
130178825Sdfr	       const void *data, size_t length,
131178825Sdfr	       const PKCS12_Attributes *attrs)
132178825Sdfr{
133178825Sdfr    heim_octet_string os;
134178825Sdfr    hx509_cert cert;
135178825Sdfr    PKCS12_CertBag cb;
136178825Sdfr    int ret;
137178825Sdfr
138178825Sdfr    ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
139178825Sdfr    if (ret)
140178825Sdfr	return ret;
141178825Sdfr
142233294Sstas    if (der_heim_oid_cmp(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType)) {
143178825Sdfr	free_PKCS12_CertBag(&cb);
144178825Sdfr	return 0;
145178825Sdfr    }
146178825Sdfr
147233294Sstas    ret = decode_PKCS12_OctetString(cb.certValue.data,
148178825Sdfr				    cb.certValue.length,
149178825Sdfr				    &os,
150178825Sdfr				    NULL);
151178825Sdfr    free_PKCS12_CertBag(&cb);
152178825Sdfr    if (ret)
153178825Sdfr	return ret;
154178825Sdfr
155178825Sdfr    ret = hx509_cert_init_data(context, os.data, os.length, &cert);
156178825Sdfr    der_free_octet_string(&os);
157178825Sdfr    if (ret)
158178825Sdfr	return ret;
159178825Sdfr
160178825Sdfr    ret = _hx509_collector_certs_add(context, c, cert);
161178825Sdfr    if (ret) {
162178825Sdfr	hx509_cert_free(cert);
163178825Sdfr	return ret;
164178825Sdfr    }
165178825Sdfr
166178825Sdfr    {
167178825Sdfr	const PKCS12_Attribute *attr;
168233294Sstas	const heim_oid *oids[] = {
169233294Sstas	    &asn1_oid_id_pkcs_9_at_localKeyId, &asn1_oid_id_pkcs_9_at_friendlyName
170178825Sdfr	};
171233294Sstas	size_t i;
172178825Sdfr
173233294Sstas	for  (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
174233294Sstas	    const heim_oid *oid = oids[i];
175178825Sdfr	    attr = find_attribute(attrs, oid);
176178825Sdfr	    if (attr)
177178825Sdfr		_hx509_set_cert_attribute(context, cert, oid,
178178825Sdfr					  &attr->attrValues);
179233294Sstas	}
180178825Sdfr    }
181178825Sdfr
182178825Sdfr    hx509_cert_free(cert);
183178825Sdfr
184178825Sdfr    return 0;
185178825Sdfr}
186178825Sdfr
187178825Sdfrstatic int
188178825Sdfrparse_safe_content(hx509_context context,
189233294Sstas		   struct hx509_collector *c,
190178825Sdfr		   const unsigned char *p, size_t len)
191178825Sdfr{
192178825Sdfr    PKCS12_SafeContents sc;
193233294Sstas    int ret;
194233294Sstas    size_t i;
195178825Sdfr
196178825Sdfr    memset(&sc, 0, sizeof(sc));
197178825Sdfr
198178825Sdfr    ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
199178825Sdfr    if (ret)
200178825Sdfr	return ret;
201178825Sdfr
202178825Sdfr    for (i = 0; i < sc.len ; i++)
203178825Sdfr	parse_pkcs12_type(context,
204178825Sdfr			  c,
205178825Sdfr			  &sc.val[i].bagId,
206178825Sdfr			  sc.val[i].bagValue.data,
207178825Sdfr			  sc.val[i].bagValue.length,
208178825Sdfr			  sc.val[i].bagAttributes);
209178825Sdfr
210178825Sdfr    free_PKCS12_SafeContents(&sc);
211178825Sdfr    return 0;
212178825Sdfr}
213178825Sdfr
214178825Sdfrstatic int
215178825SdfrsafeContent_parser(hx509_context context,
216233294Sstas		   struct hx509_collector *c,
217178825Sdfr		   const void *data, size_t length,
218178825Sdfr		   const PKCS12_Attributes *attrs)
219178825Sdfr{
220178825Sdfr    heim_octet_string os;
221178825Sdfr    int ret;
222178825Sdfr
223178825Sdfr    ret = decode_PKCS12_OctetString(data, length, &os, NULL);
224178825Sdfr    if (ret)
225178825Sdfr	return ret;
226178825Sdfr    ret = parse_safe_content(context, c, os.data, os.length);
227178825Sdfr    der_free_octet_string(&os);
228178825Sdfr    return ret;
229178825Sdfr}
230178825Sdfr
231178825Sdfrstatic int
232178825SdfrencryptedData_parser(hx509_context context,
233178825Sdfr		     struct hx509_collector *c,
234178825Sdfr		     const void *data, size_t length,
235178825Sdfr		     const PKCS12_Attributes *attrs)
236178825Sdfr{
237178825Sdfr    heim_octet_string content;
238178825Sdfr    heim_oid contentType;
239178825Sdfr    int ret;
240233294Sstas
241178825Sdfr    memset(&contentType, 0, sizeof(contentType));
242178825Sdfr
243178825Sdfr    ret = hx509_cms_decrypt_encrypted(context,
244178825Sdfr				      _hx509_collector_get_lock(c),
245178825Sdfr				      data, length,
246178825Sdfr				      &contentType,
247178825Sdfr				      &content);
248178825Sdfr    if (ret)
249178825Sdfr	return ret;
250178825Sdfr
251233294Sstas    if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
252178825Sdfr	ret = parse_safe_content(context, c, content.data, content.length);
253178825Sdfr
254178825Sdfr    der_free_octet_string(&content);
255178825Sdfr    der_free_oid(&contentType);
256178825Sdfr    return ret;
257178825Sdfr}
258178825Sdfr
259178825Sdfrstatic int
260178825SdfrenvelopedData_parser(hx509_context context,
261178825Sdfr		     struct hx509_collector *c,
262178825Sdfr		     const void *data, size_t length,
263178825Sdfr		     const PKCS12_Attributes *attrs)
264178825Sdfr{
265178825Sdfr    heim_octet_string content;
266178825Sdfr    heim_oid contentType;
267178825Sdfr    hx509_lock lock;
268178825Sdfr    int ret;
269233294Sstas
270178825Sdfr    memset(&contentType, 0, sizeof(contentType));
271178825Sdfr
272178825Sdfr    lock = _hx509_collector_get_lock(c);
273178825Sdfr
274178825Sdfr    ret = hx509_cms_unenvelope(context,
275178825Sdfr			       _hx509_lock_unlock_certs(lock),
276178825Sdfr			       0,
277178825Sdfr			       data, length,
278178825Sdfr			       NULL,
279233294Sstas			       0,
280178825Sdfr			       &contentType,
281178825Sdfr			       &content);
282178825Sdfr    if (ret) {
283233294Sstas	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
284178825Sdfr			       "PKCS12 failed to unenvelope");
285178825Sdfr	return ret;
286178825Sdfr    }
287178825Sdfr
288233294Sstas    if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
289178825Sdfr	ret = parse_safe_content(context, c, content.data, content.length);
290178825Sdfr
291178825Sdfr    der_free_octet_string(&content);
292178825Sdfr    der_free_oid(&contentType);
293178825Sdfr
294178825Sdfr    return ret;
295178825Sdfr}
296178825Sdfr
297178825Sdfr
298178825Sdfrstruct type bagtypes[] = {
299233294Sstas    { &asn1_oid_id_pkcs12_keyBag, keyBag_parser },
300233294Sstas    { &asn1_oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
301233294Sstas    { &asn1_oid_id_pkcs12_certBag, certBag_parser },
302233294Sstas    { &asn1_oid_id_pkcs7_data, safeContent_parser },
303233294Sstas    { &asn1_oid_id_pkcs7_encryptedData, encryptedData_parser },
304233294Sstas    { &asn1_oid_id_pkcs7_envelopedData, envelopedData_parser }
305178825Sdfr};
306178825Sdfr
307178825Sdfrstatic void
308178825Sdfrparse_pkcs12_type(hx509_context context,
309178825Sdfr		  struct hx509_collector *c,
310233294Sstas		  const heim_oid *oid,
311178825Sdfr		  const void *data, size_t length,
312178825Sdfr		  const PKCS12_Attributes *attrs)
313178825Sdfr{
314233294Sstas    size_t i;
315178825Sdfr
316178825Sdfr    for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
317233294Sstas	if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)
318178825Sdfr	    (*bagtypes[i].func)(context, c, data, length, attrs);
319178825Sdfr}
320178825Sdfr
321178825Sdfrstatic int
322178825Sdfrp12_init(hx509_context context,
323233294Sstas	 hx509_certs certs, void **data, int flags,
324178825Sdfr	 const char *residue, hx509_lock lock)
325178825Sdfr{
326178825Sdfr    struct ks_pkcs12 *p12;
327178825Sdfr    size_t len;
328178825Sdfr    void *buf;
329178825Sdfr    PKCS12_PFX pfx;
330178825Sdfr    PKCS12_AuthenticatedSafe as;
331233294Sstas    int ret;
332233294Sstas    size_t i;
333178825Sdfr    struct hx509_collector *c;
334178825Sdfr
335178825Sdfr    *data = NULL;
336178825Sdfr
337178825Sdfr    if (lock == NULL)
338178825Sdfr	lock = _hx509_empty_lock;
339178825Sdfr
340178825Sdfr    ret = _hx509_collector_alloc(context, lock, &c);
341178825Sdfr    if (ret)
342178825Sdfr	return ret;
343178825Sdfr
344178825Sdfr    p12 = calloc(1, sizeof(*p12));
345178825Sdfr    if (p12 == NULL) {
346178825Sdfr	ret = ENOMEM;
347178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
348178825Sdfr	goto out;
349178825Sdfr    }
350178825Sdfr
351178825Sdfr    p12->fn = strdup(residue);
352178825Sdfr    if (p12->fn == NULL) {
353178825Sdfr	ret = ENOMEM;
354178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
355178825Sdfr	goto out;
356178825Sdfr    }
357178825Sdfr
358178825Sdfr    if (flags & HX509_CERTS_CREATE) {
359178825Sdfr	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
360178825Sdfr			       0, lock, &p12->certs);
361178825Sdfr	if (ret == 0)
362178825Sdfr	    *data = p12;
363178825Sdfr	goto out;
364178825Sdfr    }
365178825Sdfr
366233294Sstas    ret = rk_undumpdata(residue, &buf, &len);
367178825Sdfr    if (ret) {
368178825Sdfr	hx509_clear_error_string(context);
369178825Sdfr	goto out;
370178825Sdfr    }
371178825Sdfr
372178825Sdfr    ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
373233294Sstas    rk_xfree(buf);
374178825Sdfr    if (ret) {
375178825Sdfr	hx509_set_error_string(context, 0, ret,
376178825Sdfr			       "Failed to decode the PFX in %s", residue);
377178825Sdfr	goto out;
378178825Sdfr    }
379178825Sdfr
380233294Sstas    if (der_heim_oid_cmp(&pfx.authSafe.contentType, &asn1_oid_id_pkcs7_data) != 0) {
381178825Sdfr	free_PKCS12_PFX(&pfx);
382178825Sdfr	ret = EINVAL;
383178825Sdfr	hx509_set_error_string(context, 0, ret,
384178825Sdfr			       "PKCS PFX isn't a pkcs7-data container");
385178825Sdfr	goto out;
386178825Sdfr    }
387178825Sdfr
388178825Sdfr    if (pfx.authSafe.content == NULL) {
389178825Sdfr	free_PKCS12_PFX(&pfx);
390178825Sdfr	ret = EINVAL;
391178825Sdfr	hx509_set_error_string(context, 0, ret,
392178825Sdfr			       "PKCS PFX missing data");
393178825Sdfr	goto out;
394178825Sdfr    }
395178825Sdfr
396178825Sdfr    {
397178825Sdfr	heim_octet_string asdata;
398178825Sdfr
399178825Sdfr	ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
400178825Sdfr					pfx.authSafe.content->length,
401178825Sdfr					&asdata,
402178825Sdfr					NULL);
403178825Sdfr	free_PKCS12_PFX(&pfx);
404178825Sdfr	if (ret) {
405178825Sdfr	    hx509_clear_error_string(context);
406178825Sdfr	    goto out;
407178825Sdfr	}
408233294Sstas	ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
409178825Sdfr					      asdata.length,
410178825Sdfr					      &as,
411178825Sdfr					      NULL);
412178825Sdfr	der_free_octet_string(&asdata);
413178825Sdfr	if (ret) {
414178825Sdfr	    hx509_clear_error_string(context);
415178825Sdfr	    goto out;
416178825Sdfr	}
417178825Sdfr    }
418178825Sdfr
419178825Sdfr    for (i = 0; i < as.len; i++)
420178825Sdfr	parse_pkcs12_type(context,
421178825Sdfr			  c,
422178825Sdfr			  &as.val[i].contentType,
423178825Sdfr			  as.val[i].content->data,
424178825Sdfr			  as.val[i].content->length,
425178825Sdfr			  NULL);
426178825Sdfr
427178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
428178825Sdfr
429178825Sdfr    ret = _hx509_collector_collect_certs(context, c, &p12->certs);
430178825Sdfr    if (ret == 0)
431178825Sdfr	*data = p12;
432178825Sdfr
433178825Sdfrout:
434178825Sdfr    _hx509_collector_free(c);
435178825Sdfr
436178825Sdfr    if (ret && p12) {
437178825Sdfr	if (p12->fn)
438178825Sdfr	    free(p12->fn);
439178825Sdfr	if (p12->certs)
440178825Sdfr	    hx509_certs_free(&p12->certs);
441178825Sdfr	free(p12);
442178825Sdfr    }
443178825Sdfr
444178825Sdfr    return ret;
445178825Sdfr}
446178825Sdfr
447178825Sdfrstatic int
448178825SdfraddBag(hx509_context context,
449178825Sdfr       PKCS12_AuthenticatedSafe *as,
450178825Sdfr       const heim_oid *oid,
451178825Sdfr       void *data,
452178825Sdfr       size_t length)
453178825Sdfr{
454178825Sdfr    void *ptr;
455178825Sdfr    int ret;
456178825Sdfr
457178825Sdfr    ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
458178825Sdfr    if (ptr == NULL) {
459178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
460178825Sdfr	return ENOMEM;
461178825Sdfr    }
462178825Sdfr    as->val = ptr;
463178825Sdfr
464178825Sdfr    ret = der_copy_oid(oid, &as->val[as->len].contentType);
465178825Sdfr    if (ret) {
466178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
467178825Sdfr	return ret;
468178825Sdfr    }
469233294Sstas
470178825Sdfr    as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
471178825Sdfr    if (as->val[as->len].content == NULL) {
472178825Sdfr	der_free_oid(&as->val[as->len].contentType);
473178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
474178825Sdfr	return ENOMEM;
475178825Sdfr    }
476178825Sdfr
477178825Sdfr    as->val[as->len].content->data = data;
478178825Sdfr    as->val[as->len].content->length = length;
479178825Sdfr
480178825Sdfr    as->len++;
481178825Sdfr
482178825Sdfr    return 0;
483178825Sdfr}
484178825Sdfr
485178825Sdfrstatic int
486178825Sdfrstore_func(hx509_context context, void *ctx, hx509_cert c)
487178825Sdfr{
488178825Sdfr    PKCS12_AuthenticatedSafe *as = ctx;
489178825Sdfr    PKCS12_OctetString os;
490178825Sdfr    PKCS12_CertBag cb;
491178825Sdfr    size_t size;
492178825Sdfr    int ret;
493178825Sdfr
494178825Sdfr    memset(&os, 0, sizeof(os));
495178825Sdfr    memset(&cb, 0, sizeof(cb));
496178825Sdfr
497178825Sdfr    os.data = NULL;
498178825Sdfr    os.length = 0;
499178825Sdfr
500178825Sdfr    ret = hx509_cert_binary(context, c, &os);
501178825Sdfr    if (ret)
502178825Sdfr	return ret;
503178825Sdfr
504178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
505178825Sdfr		       cb.certValue.data,cb.certValue.length,
506178825Sdfr		       &os, &size, ret);
507178825Sdfr    free(os.data);
508178825Sdfr    if (ret)
509178825Sdfr	goto out;
510233294Sstas    ret = der_copy_oid(&asn1_oid_id_pkcs_9_at_certTypes_x509, &cb.certType);
511178825Sdfr    if (ret) {
512178825Sdfr	free_PKCS12_CertBag(&cb);
513178825Sdfr	goto out;
514178825Sdfr    }
515178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
516178825Sdfr		       &cb, &size, ret);
517178825Sdfr    free_PKCS12_CertBag(&cb);
518178825Sdfr    if (ret)
519178825Sdfr	goto out;
520178825Sdfr
521233294Sstas    ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length);
522178825Sdfr
523178825Sdfr    if (_hx509_cert_private_key_exportable(c)) {
524178825Sdfr	hx509_private_key key = _hx509_cert_private_key(c);
525178825Sdfr	PKCS8PrivateKeyInfo pki;
526178825Sdfr
527178825Sdfr	memset(&pki, 0, sizeof(pki));
528178825Sdfr
529178825Sdfr	ret = der_parse_hex_heim_integer("00", &pki.version);
530178825Sdfr	if (ret)
531178825Sdfr	    return ret;
532233294Sstas	ret = _hx509_private_key_oid(context, key,
533178825Sdfr				     &pki.privateKeyAlgorithm.algorithm);
534178825Sdfr	if (ret) {
535178825Sdfr	    free_PKCS8PrivateKeyInfo(&pki);
536178825Sdfr	    return ret;
537178825Sdfr	}
538178825Sdfr	ret = _hx509_private_key_export(context,
539178825Sdfr					_hx509_cert_private_key(c),
540233294Sstas					HX509_KEY_FORMAT_DER,
541178825Sdfr					&pki.privateKey);
542178825Sdfr	if (ret) {
543178825Sdfr	    free_PKCS8PrivateKeyInfo(&pki);
544178825Sdfr	    return ret;
545178825Sdfr	}
546233294Sstas	/* set attribute, asn1_oid_id_pkcs_9_at_localKeyId */
547178825Sdfr
548178825Sdfr	ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
549178825Sdfr			   &pki, &size, ret);
550178825Sdfr	free_PKCS8PrivateKeyInfo(&pki);
551178825Sdfr	if (ret)
552178825Sdfr	    return ret;
553178825Sdfr
554233294Sstas	ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length);
555178825Sdfr	if (ret)
556178825Sdfr	    return ret;
557178825Sdfr    }
558178825Sdfr
559178825Sdfrout:
560178825Sdfr    return ret;
561178825Sdfr}
562178825Sdfr
563178825Sdfrstatic int
564233294Sstasp12_store(hx509_context context,
565178825Sdfr	  hx509_certs certs, void *data, int flags, hx509_lock lock)
566178825Sdfr{
567178825Sdfr    struct ks_pkcs12 *p12 = data;
568178825Sdfr    PKCS12_PFX pfx;
569178825Sdfr    PKCS12_AuthenticatedSafe as;
570178825Sdfr    PKCS12_OctetString asdata;
571178825Sdfr    size_t size;
572178825Sdfr    int ret;
573178825Sdfr
574178825Sdfr    memset(&as, 0, sizeof(as));
575178825Sdfr    memset(&pfx, 0, sizeof(pfx));
576178825Sdfr
577233294Sstas    ret = hx509_certs_iter_f(context, p12->certs, store_func, &as);
578178825Sdfr    if (ret)
579178825Sdfr	goto out;
580178825Sdfr
581178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
582178825Sdfr		       &as, &size, ret);
583178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
584178825Sdfr    if (ret)
585178825Sdfr	return ret;
586233294Sstas
587178825Sdfr    ret = der_parse_hex_heim_integer("03", &pfx.version);
588178825Sdfr    if (ret) {
589178825Sdfr	free(asdata.data);
590178825Sdfr	goto out;
591178825Sdfr    }
592178825Sdfr
593178825Sdfr    pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
594178825Sdfr
595233294Sstas    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
596178825Sdfr		       pfx.authSafe.content->data,
597178825Sdfr		       pfx.authSafe.content->length,
598178825Sdfr		       &asdata, &size, ret);
599178825Sdfr    free(asdata.data);
600178825Sdfr    if (ret)
601178825Sdfr	goto out;
602178825Sdfr
603233294Sstas    ret = der_copy_oid(&asn1_oid_id_pkcs7_data, &pfx.authSafe.contentType);
604178825Sdfr    if (ret)
605178825Sdfr	goto out;
606178825Sdfr
607178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
608178825Sdfr		       &pfx, &size, ret);
609178825Sdfr    if (ret)
610178825Sdfr	goto out;
611178825Sdfr
612178825Sdfr#if 0
613178825Sdfr    const struct _hx509_password *pw;
614178825Sdfr
615178825Sdfr    pw = _hx509_lock_get_passwords(lock);
616178825Sdfr    if (pw != NULL) {
617178825Sdfr	pfx.macData = calloc(1, sizeof(*pfx.macData));
618178825Sdfr	if (pfx.macData == NULL) {
619178825Sdfr	    ret = ENOMEM;
620178825Sdfr	    hx509_set_error_string(context, 0, ret, "malloc out of memory");
621178825Sdfr	    return ret;
622178825Sdfr	}
623178825Sdfr	if (pfx.macData == NULL) {
624178825Sdfr	    free(asdata.data);
625178825Sdfr	    goto out;
626178825Sdfr	}
627178825Sdfr    }
628178825Sdfr    ret = calculate_hash(&aspath, pw, pfx.macData);
629178825Sdfr#endif
630178825Sdfr
631178825Sdfr    rk_dumpdata(p12->fn, asdata.data, asdata.length);
632178825Sdfr    free(asdata.data);
633178825Sdfr
634178825Sdfrout:
635178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
636178825Sdfr    free_PKCS12_PFX(&pfx);
637178825Sdfr
638178825Sdfr    return ret;
639178825Sdfr}
640178825Sdfr
641178825Sdfr
642178825Sdfrstatic int
643178825Sdfrp12_free(hx509_certs certs, void *data)
644178825Sdfr{
645178825Sdfr    struct ks_pkcs12 *p12 = data;
646178825Sdfr    hx509_certs_free(&p12->certs);
647178825Sdfr    free(p12->fn);
648178825Sdfr    free(p12);
649178825Sdfr    return 0;
650178825Sdfr}
651178825Sdfr
652233294Sstasstatic int
653178825Sdfrp12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
654178825Sdfr{
655178825Sdfr    struct ks_pkcs12 *p12 = data;
656178825Sdfr    return hx509_certs_add(context, p12->certs, c);
657178825Sdfr}
658178825Sdfr
659233294Sstasstatic int
660178825Sdfrp12_iter_start(hx509_context context,
661178825Sdfr	       hx509_certs certs,
662178825Sdfr	       void *data,
663178825Sdfr	       void **cursor)
664178825Sdfr{
665178825Sdfr    struct ks_pkcs12 *p12 = data;
666178825Sdfr    return hx509_certs_start_seq(context, p12->certs, cursor);
667178825Sdfr}
668178825Sdfr
669178825Sdfrstatic int
670178825Sdfrp12_iter(hx509_context context,
671178825Sdfr	 hx509_certs certs,
672178825Sdfr	 void *data,
673178825Sdfr	 void *cursor,
674178825Sdfr	 hx509_cert *cert)
675178825Sdfr{
676178825Sdfr    struct ks_pkcs12 *p12 = data;
677178825Sdfr    return hx509_certs_next_cert(context, p12->certs, cursor, cert);
678178825Sdfr}
679178825Sdfr
680178825Sdfrstatic int
681178825Sdfrp12_iter_end(hx509_context context,
682178825Sdfr	     hx509_certs certs,
683178825Sdfr	     void *data,
684178825Sdfr	     void *cursor)
685178825Sdfr{
686178825Sdfr    struct ks_pkcs12 *p12 = data;
687178825Sdfr    return hx509_certs_end_seq(context, p12->certs, cursor);
688178825Sdfr}
689178825Sdfr
690178825Sdfrstatic struct hx509_keyset_ops keyset_pkcs12 = {
691178825Sdfr    "PKCS12",
692178825Sdfr    0,
693178825Sdfr    p12_init,
694178825Sdfr    p12_store,
695178825Sdfr    p12_free,
696178825Sdfr    p12_add,
697178825Sdfr    NULL,
698178825Sdfr    p12_iter_start,
699178825Sdfr    p12_iter,
700178825Sdfr    p12_iter_end
701178825Sdfr};
702178825Sdfr
703178825Sdfrvoid
704178825Sdfr_hx509_ks_pkcs12_register(hx509_context context)
705178825Sdfr{
706178825Sdfr    _hx509_ks_register(context, &keyset_pkcs12);
707178825Sdfr}
708