1178825Sdfr/*
2178825Sdfr * Copyright (c) 2004 - 2007 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825SdfrRCSID("$Id: ks_p12.c 21146 2007-06-18 21:37:25Z lha $");
36178825Sdfr
37178825Sdfrstruct ks_pkcs12 {
38178825Sdfr    hx509_certs certs;
39178825Sdfr    char *fn;
40178825Sdfr};
41178825Sdfr
42178825Sdfrtypedef int (*collector_func)(hx509_context,
43178825Sdfr			      struct hx509_collector *,
44178825Sdfr			      const void *, size_t,
45178825Sdfr			      const PKCS12_Attributes *);
46178825Sdfr
47178825Sdfrstruct type {
48178825Sdfr    const heim_oid * (*oid)(void);
49178825Sdfr    collector_func func;
50178825Sdfr};
51178825Sdfr
52178825Sdfrstatic void
53178825Sdfrparse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
54178825Sdfr		  const void *, size_t, const PKCS12_Attributes *);
55178825Sdfr
56178825Sdfr
57178825Sdfrstatic const PKCS12_Attribute *
58178825Sdfrfind_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
59178825Sdfr{
60178825Sdfr    int i;
61178825Sdfr    if (attrs == NULL)
62178825Sdfr	return NULL;
63178825Sdfr    for (i = 0; i < attrs->len; i++)
64178825Sdfr	if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
65178825Sdfr	    return &attrs->val[i];
66178825Sdfr    return NULL;
67178825Sdfr}
68178825Sdfr
69178825Sdfrstatic int
70178825SdfrkeyBag_parser(hx509_context context,
71178825Sdfr	      struct hx509_collector *c,
72178825Sdfr	      const void *data, size_t length,
73178825Sdfr	      const PKCS12_Attributes *attrs)
74178825Sdfr{
75178825Sdfr    const PKCS12_Attribute *attr;
76178825Sdfr    PKCS8PrivateKeyInfo ki;
77178825Sdfr    const heim_octet_string *os = NULL;
78178825Sdfr    int ret;
79178825Sdfr
80178825Sdfr    attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId());
81178825Sdfr    if (attr)
82178825Sdfr	os = &attr->attrValues;
83178825Sdfr
84178825Sdfr    ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
85178825Sdfr    if (ret)
86178825Sdfr	return ret;
87178825Sdfr
88178825Sdfr    _hx509_collector_private_key_add(context,
89178825Sdfr				     c,
90178825Sdfr				     &ki.privateKeyAlgorithm,
91178825Sdfr				     NULL,
92178825Sdfr				     &ki.privateKey,
93178825Sdfr				     os);
94178825Sdfr    free_PKCS8PrivateKeyInfo(&ki);
95178825Sdfr    return 0;
96178825Sdfr}
97178825Sdfr
98178825Sdfrstatic int
99178825SdfrShroudedKeyBag_parser(hx509_context context,
100178825Sdfr		      struct hx509_collector *c,
101178825Sdfr		      const void *data, size_t length,
102178825Sdfr		      const PKCS12_Attributes *attrs)
103178825Sdfr{
104178825Sdfr    PKCS8EncryptedPrivateKeyInfo pk;
105178825Sdfr    heim_octet_string content;
106178825Sdfr    int ret;
107178825Sdfr
108178825Sdfr    memset(&pk, 0, sizeof(pk));
109178825Sdfr
110178825Sdfr    ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
111178825Sdfr    if (ret)
112178825Sdfr	return ret;
113178825Sdfr
114178825Sdfr    ret = _hx509_pbe_decrypt(context,
115178825Sdfr			     _hx509_collector_get_lock(c),
116178825Sdfr			     &pk.encryptionAlgorithm,
117178825Sdfr			     &pk.encryptedData,
118178825Sdfr			     &content);
119178825Sdfr    free_PKCS8EncryptedPrivateKeyInfo(&pk);
120178825Sdfr    if (ret)
121178825Sdfr	return ret;
122178825Sdfr
123178825Sdfr    ret = keyBag_parser(context, c, content.data, content.length, attrs);
124178825Sdfr    der_free_octet_string(&content);
125178825Sdfr    return ret;
126178825Sdfr}
127178825Sdfr
128178825Sdfrstatic int
129178825SdfrcertBag_parser(hx509_context context,
130178825Sdfr	       struct hx509_collector *c,
131178825Sdfr	       const void *data, size_t length,
132178825Sdfr	       const PKCS12_Attributes *attrs)
133178825Sdfr{
134178825Sdfr    heim_octet_string os;
135178825Sdfr    hx509_cert cert;
136178825Sdfr    PKCS12_CertBag cb;
137178825Sdfr    int ret;
138178825Sdfr
139178825Sdfr    ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
140178825Sdfr    if (ret)
141178825Sdfr	return ret;
142178825Sdfr
143178825Sdfr    if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) {
144178825Sdfr	free_PKCS12_CertBag(&cb);
145178825Sdfr	return 0;
146178825Sdfr    }
147178825Sdfr
148178825Sdfr    ret = decode_PKCS12_OctetString(cb.certValue.data,
149178825Sdfr				    cb.certValue.length,
150178825Sdfr				    &os,
151178825Sdfr				    NULL);
152178825Sdfr    free_PKCS12_CertBag(&cb);
153178825Sdfr    if (ret)
154178825Sdfr	return ret;
155178825Sdfr
156178825Sdfr    ret = hx509_cert_init_data(context, os.data, os.length, &cert);
157178825Sdfr    der_free_octet_string(&os);
158178825Sdfr    if (ret)
159178825Sdfr	return ret;
160178825Sdfr
161178825Sdfr    ret = _hx509_collector_certs_add(context, c, cert);
162178825Sdfr    if (ret) {
163178825Sdfr	hx509_cert_free(cert);
164178825Sdfr	return ret;
165178825Sdfr    }
166178825Sdfr
167178825Sdfr    {
168178825Sdfr	const PKCS12_Attribute *attr;
169178825Sdfr	const heim_oid * (*oids[])(void) = {
170178825Sdfr	    oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName
171178825Sdfr	};
172178825Sdfr	int i;
173178825Sdfr
174178825Sdfr	for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
175178825Sdfr	    const heim_oid *oid = (*(oids[i]))();
176178825Sdfr	    attr = find_attribute(attrs, oid);
177178825Sdfr	    if (attr)
178178825Sdfr		_hx509_set_cert_attribute(context, cert, oid,
179178825Sdfr					  &attr->attrValues);
180178825Sdfr	}
181178825Sdfr    }
182178825Sdfr
183178825Sdfr    hx509_cert_free(cert);
184178825Sdfr
185178825Sdfr    return 0;
186178825Sdfr}
187178825Sdfr
188178825Sdfrstatic int
189178825Sdfrparse_safe_content(hx509_context context,
190178825Sdfr		   struct hx509_collector *c,
191178825Sdfr		   const unsigned char *p, size_t len)
192178825Sdfr{
193178825Sdfr    PKCS12_SafeContents sc;
194178825Sdfr    int ret, 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,
216178825Sdfr		   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;
240178825Sdfr
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
251178825Sdfr    if (der_heim_oid_cmp(&contentType, 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;
269178825Sdfr
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,
279178825Sdfr			       &contentType,
280178825Sdfr			       &content);
281178825Sdfr    if (ret) {
282178825Sdfr	hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
283178825Sdfr			       "PKCS12 failed to unenvelope");
284178825Sdfr	return ret;
285178825Sdfr    }
286178825Sdfr
287178825Sdfr    if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
288178825Sdfr	ret = parse_safe_content(context, c, content.data, content.length);
289178825Sdfr
290178825Sdfr    der_free_octet_string(&content);
291178825Sdfr    der_free_oid(&contentType);
292178825Sdfr
293178825Sdfr    return ret;
294178825Sdfr}
295178825Sdfr
296178825Sdfr
297178825Sdfrstruct type bagtypes[] = {
298178825Sdfr    { oid_id_pkcs12_keyBag, keyBag_parser },
299178825Sdfr    { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
300178825Sdfr    { oid_id_pkcs12_certBag, certBag_parser },
301178825Sdfr    { oid_id_pkcs7_data, safeContent_parser },
302178825Sdfr    { oid_id_pkcs7_encryptedData, encryptedData_parser },
303178825Sdfr    { oid_id_pkcs7_envelopedData, envelopedData_parser }
304178825Sdfr};
305178825Sdfr
306178825Sdfrstatic void
307178825Sdfrparse_pkcs12_type(hx509_context context,
308178825Sdfr		  struct hx509_collector *c,
309178825Sdfr		  const heim_oid *oid,
310178825Sdfr		  const void *data, size_t length,
311178825Sdfr		  const PKCS12_Attributes *attrs)
312178825Sdfr{
313178825Sdfr    int i;
314178825Sdfr
315178825Sdfr    for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
316178825Sdfr	if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0)
317178825Sdfr	    (*bagtypes[i].func)(context, c, data, length, attrs);
318178825Sdfr}
319178825Sdfr
320178825Sdfrstatic int
321178825Sdfrp12_init(hx509_context context,
322178825Sdfr	 hx509_certs certs, void **data, int flags,
323178825Sdfr	 const char *residue, hx509_lock lock)
324178825Sdfr{
325178825Sdfr    struct ks_pkcs12 *p12;
326178825Sdfr    size_t len;
327178825Sdfr    void *buf;
328178825Sdfr    PKCS12_PFX pfx;
329178825Sdfr    PKCS12_AuthenticatedSafe as;
330178825Sdfr    int ret, i;
331178825Sdfr    struct hx509_collector *c;
332178825Sdfr
333178825Sdfr    *data = NULL;
334178825Sdfr
335178825Sdfr    if (lock == NULL)
336178825Sdfr	lock = _hx509_empty_lock;
337178825Sdfr
338178825Sdfr    ret = _hx509_collector_alloc(context, lock, &c);
339178825Sdfr    if (ret)
340178825Sdfr	return ret;
341178825Sdfr
342178825Sdfr    p12 = calloc(1, sizeof(*p12));
343178825Sdfr    if (p12 == NULL) {
344178825Sdfr	ret = ENOMEM;
345178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
346178825Sdfr	goto out;
347178825Sdfr    }
348178825Sdfr
349178825Sdfr    p12->fn = strdup(residue);
350178825Sdfr    if (p12->fn == NULL) {
351178825Sdfr	ret = ENOMEM;
352178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
353178825Sdfr	goto out;
354178825Sdfr    }
355178825Sdfr
356178825Sdfr    if (flags & HX509_CERTS_CREATE) {
357178825Sdfr	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
358178825Sdfr			       0, lock, &p12->certs);
359178825Sdfr	if (ret == 0)
360178825Sdfr	    *data = p12;
361178825Sdfr	goto out;
362178825Sdfr    }
363178825Sdfr
364178825Sdfr    ret = _hx509_map_file(residue, &buf, &len, NULL);
365178825Sdfr    if (ret) {
366178825Sdfr	hx509_clear_error_string(context);
367178825Sdfr	goto out;
368178825Sdfr    }
369178825Sdfr
370178825Sdfr    ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
371178825Sdfr    _hx509_unmap_file(buf, len);
372178825Sdfr    if (ret) {
373178825Sdfr	hx509_set_error_string(context, 0, ret,
374178825Sdfr			       "Failed to decode the PFX in %s", residue);
375178825Sdfr	goto out;
376178825Sdfr    }
377178825Sdfr
378178825Sdfr    if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) {
379178825Sdfr	free_PKCS12_PFX(&pfx);
380178825Sdfr	ret = EINVAL;
381178825Sdfr	hx509_set_error_string(context, 0, ret,
382178825Sdfr			       "PKCS PFX isn't a pkcs7-data container");
383178825Sdfr	goto out;
384178825Sdfr    }
385178825Sdfr
386178825Sdfr    if (pfx.authSafe.content == NULL) {
387178825Sdfr	free_PKCS12_PFX(&pfx);
388178825Sdfr	ret = EINVAL;
389178825Sdfr	hx509_set_error_string(context, 0, ret,
390178825Sdfr			       "PKCS PFX missing data");
391178825Sdfr	goto out;
392178825Sdfr    }
393178825Sdfr
394178825Sdfr    {
395178825Sdfr	heim_octet_string asdata;
396178825Sdfr
397178825Sdfr	ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
398178825Sdfr					pfx.authSafe.content->length,
399178825Sdfr					&asdata,
400178825Sdfr					NULL);
401178825Sdfr	free_PKCS12_PFX(&pfx);
402178825Sdfr	if (ret) {
403178825Sdfr	    hx509_clear_error_string(context);
404178825Sdfr	    goto out;
405178825Sdfr	}
406178825Sdfr	ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
407178825Sdfr					      asdata.length,
408178825Sdfr					      &as,
409178825Sdfr					      NULL);
410178825Sdfr	der_free_octet_string(&asdata);
411178825Sdfr	if (ret) {
412178825Sdfr	    hx509_clear_error_string(context);
413178825Sdfr	    goto out;
414178825Sdfr	}
415178825Sdfr    }
416178825Sdfr
417178825Sdfr    for (i = 0; i < as.len; i++)
418178825Sdfr	parse_pkcs12_type(context,
419178825Sdfr			  c,
420178825Sdfr			  &as.val[i].contentType,
421178825Sdfr			  as.val[i].content->data,
422178825Sdfr			  as.val[i].content->length,
423178825Sdfr			  NULL);
424178825Sdfr
425178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
426178825Sdfr
427178825Sdfr    ret = _hx509_collector_collect_certs(context, c, &p12->certs);
428178825Sdfr    if (ret == 0)
429178825Sdfr	*data = p12;
430178825Sdfr
431178825Sdfrout:
432178825Sdfr    _hx509_collector_free(c);
433178825Sdfr
434178825Sdfr    if (ret && p12) {
435178825Sdfr	if (p12->fn)
436178825Sdfr	    free(p12->fn);
437178825Sdfr	if (p12->certs)
438178825Sdfr	    hx509_certs_free(&p12->certs);
439178825Sdfr	free(p12);
440178825Sdfr    }
441178825Sdfr
442178825Sdfr    return ret;
443178825Sdfr}
444178825Sdfr
445178825Sdfrstatic int
446178825SdfraddBag(hx509_context context,
447178825Sdfr       PKCS12_AuthenticatedSafe *as,
448178825Sdfr       const heim_oid *oid,
449178825Sdfr       void *data,
450178825Sdfr       size_t length)
451178825Sdfr{
452178825Sdfr    void *ptr;
453178825Sdfr    int ret;
454178825Sdfr
455178825Sdfr    ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
456178825Sdfr    if (ptr == NULL) {
457178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
458178825Sdfr	return ENOMEM;
459178825Sdfr    }
460178825Sdfr    as->val = ptr;
461178825Sdfr
462178825Sdfr    ret = der_copy_oid(oid, &as->val[as->len].contentType);
463178825Sdfr    if (ret) {
464178825Sdfr	hx509_set_error_string(context, 0, ret, "out of memory");
465178825Sdfr	return ret;
466178825Sdfr    }
467178825Sdfr
468178825Sdfr    as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
469178825Sdfr    if (as->val[as->len].content == NULL) {
470178825Sdfr	der_free_oid(&as->val[as->len].contentType);
471178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
472178825Sdfr	return ENOMEM;
473178825Sdfr    }
474178825Sdfr
475178825Sdfr    as->val[as->len].content->data = data;
476178825Sdfr    as->val[as->len].content->length = length;
477178825Sdfr
478178825Sdfr    as->len++;
479178825Sdfr
480178825Sdfr    return 0;
481178825Sdfr}
482178825Sdfr
483178825Sdfrstatic int
484178825Sdfrstore_func(hx509_context context, void *ctx, hx509_cert c)
485178825Sdfr{
486178825Sdfr    PKCS12_AuthenticatedSafe *as = ctx;
487178825Sdfr    PKCS12_OctetString os;
488178825Sdfr    PKCS12_CertBag cb;
489178825Sdfr    size_t size;
490178825Sdfr    int ret;
491178825Sdfr
492178825Sdfr    memset(&os, 0, sizeof(os));
493178825Sdfr    memset(&cb, 0, sizeof(cb));
494178825Sdfr
495178825Sdfr    os.data = NULL;
496178825Sdfr    os.length = 0;
497178825Sdfr
498178825Sdfr    ret = hx509_cert_binary(context, c, &os);
499178825Sdfr    if (ret)
500178825Sdfr	return ret;
501178825Sdfr
502178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
503178825Sdfr		       cb.certValue.data,cb.certValue.length,
504178825Sdfr		       &os, &size, ret);
505178825Sdfr    free(os.data);
506178825Sdfr    if (ret)
507178825Sdfr	goto out;
508178825Sdfr    ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType);
509178825Sdfr    if (ret) {
510178825Sdfr	free_PKCS12_CertBag(&cb);
511178825Sdfr	goto out;
512178825Sdfr    }
513178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
514178825Sdfr		       &cb, &size, ret);
515178825Sdfr    free_PKCS12_CertBag(&cb);
516178825Sdfr    if (ret)
517178825Sdfr	goto out;
518178825Sdfr
519178825Sdfr    ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length);
520178825Sdfr
521178825Sdfr    if (_hx509_cert_private_key_exportable(c)) {
522178825Sdfr	hx509_private_key key = _hx509_cert_private_key(c);
523178825Sdfr	PKCS8PrivateKeyInfo pki;
524178825Sdfr
525178825Sdfr	memset(&pki, 0, sizeof(pki));
526178825Sdfr
527178825Sdfr	ret = der_parse_hex_heim_integer("00", &pki.version);
528178825Sdfr	if (ret)
529178825Sdfr	    return ret;
530178825Sdfr	ret = _hx509_private_key_oid(context, key,
531178825Sdfr				     &pki.privateKeyAlgorithm.algorithm);
532178825Sdfr	if (ret) {
533178825Sdfr	    free_PKCS8PrivateKeyInfo(&pki);
534178825Sdfr	    return ret;
535178825Sdfr	}
536178825Sdfr	ret = _hx509_private_key_export(context,
537178825Sdfr					_hx509_cert_private_key(c),
538178825Sdfr					&pki.privateKey);
539178825Sdfr	if (ret) {
540178825Sdfr	    free_PKCS8PrivateKeyInfo(&pki);
541178825Sdfr	    return ret;
542178825Sdfr	}
543178825Sdfr	/* set attribute, oid_id_pkcs_9_at_localKeyId() */
544178825Sdfr
545178825Sdfr	ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
546178825Sdfr			   &pki, &size, ret);
547178825Sdfr	free_PKCS8PrivateKeyInfo(&pki);
548178825Sdfr	if (ret)
549178825Sdfr	    return ret;
550178825Sdfr
551178825Sdfr	ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length);
552178825Sdfr	if (ret)
553178825Sdfr	    return ret;
554178825Sdfr    }
555178825Sdfr
556178825Sdfrout:
557178825Sdfr    return ret;
558178825Sdfr}
559178825Sdfr
560178825Sdfrstatic int
561178825Sdfrp12_store(hx509_context context,
562178825Sdfr	  hx509_certs certs, void *data, int flags, hx509_lock lock)
563178825Sdfr{
564178825Sdfr    struct ks_pkcs12 *p12 = data;
565178825Sdfr    PKCS12_PFX pfx;
566178825Sdfr    PKCS12_AuthenticatedSafe as;
567178825Sdfr    PKCS12_OctetString asdata;
568178825Sdfr    size_t size;
569178825Sdfr    int ret;
570178825Sdfr
571178825Sdfr    memset(&as, 0, sizeof(as));
572178825Sdfr    memset(&pfx, 0, sizeof(pfx));
573178825Sdfr
574178825Sdfr    ret = hx509_certs_iter(context, p12->certs, store_func, &as);
575178825Sdfr    if (ret)
576178825Sdfr	goto out;
577178825Sdfr
578178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
579178825Sdfr		       &as, &size, ret);
580178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
581178825Sdfr    if (ret)
582178825Sdfr	return ret;
583178825Sdfr
584178825Sdfr    ret = der_parse_hex_heim_integer("03", &pfx.version);
585178825Sdfr    if (ret) {
586178825Sdfr	free(asdata.data);
587178825Sdfr	goto out;
588178825Sdfr    }
589178825Sdfr
590178825Sdfr    pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
591178825Sdfr
592178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_OctetString,
593178825Sdfr		       pfx.authSafe.content->data,
594178825Sdfr		       pfx.authSafe.content->length,
595178825Sdfr		       &asdata, &size, ret);
596178825Sdfr    free(asdata.data);
597178825Sdfr    if (ret)
598178825Sdfr	goto out;
599178825Sdfr
600178825Sdfr    ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType);
601178825Sdfr    if (ret)
602178825Sdfr	goto out;
603178825Sdfr
604178825Sdfr    ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
605178825Sdfr		       &pfx, &size, ret);
606178825Sdfr    if (ret)
607178825Sdfr	goto out;
608178825Sdfr
609178825Sdfr#if 0
610178825Sdfr    const struct _hx509_password *pw;
611178825Sdfr
612178825Sdfr    pw = _hx509_lock_get_passwords(lock);
613178825Sdfr    if (pw != NULL) {
614178825Sdfr	pfx.macData = calloc(1, sizeof(*pfx.macData));
615178825Sdfr	if (pfx.macData == NULL) {
616178825Sdfr	    ret = ENOMEM;
617178825Sdfr	    hx509_set_error_string(context, 0, ret, "malloc out of memory");
618178825Sdfr	    return ret;
619178825Sdfr	}
620178825Sdfr	if (pfx.macData == NULL) {
621178825Sdfr	    free(asdata.data);
622178825Sdfr	    goto out;
623178825Sdfr	}
624178825Sdfr    }
625178825Sdfr    ret = calculate_hash(&aspath, pw, pfx.macData);
626178825Sdfr#endif
627178825Sdfr
628178825Sdfr    rk_dumpdata(p12->fn, asdata.data, asdata.length);
629178825Sdfr    free(asdata.data);
630178825Sdfr
631178825Sdfrout:
632178825Sdfr    free_PKCS12_AuthenticatedSafe(&as);
633178825Sdfr    free_PKCS12_PFX(&pfx);
634178825Sdfr
635178825Sdfr    return ret;
636178825Sdfr}
637178825Sdfr
638178825Sdfr
639178825Sdfrstatic int
640178825Sdfrp12_free(hx509_certs certs, void *data)
641178825Sdfr{
642178825Sdfr    struct ks_pkcs12 *p12 = data;
643178825Sdfr    hx509_certs_free(&p12->certs);
644178825Sdfr    free(p12->fn);
645178825Sdfr    free(p12);
646178825Sdfr    return 0;
647178825Sdfr}
648178825Sdfr
649178825Sdfrstatic int
650178825Sdfrp12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
651178825Sdfr{
652178825Sdfr    struct ks_pkcs12 *p12 = data;
653178825Sdfr    return hx509_certs_add(context, p12->certs, c);
654178825Sdfr}
655178825Sdfr
656178825Sdfrstatic int
657178825Sdfrp12_iter_start(hx509_context context,
658178825Sdfr	       hx509_certs certs,
659178825Sdfr	       void *data,
660178825Sdfr	       void **cursor)
661178825Sdfr{
662178825Sdfr    struct ks_pkcs12 *p12 = data;
663178825Sdfr    return hx509_certs_start_seq(context, p12->certs, cursor);
664178825Sdfr}
665178825Sdfr
666178825Sdfrstatic int
667178825Sdfrp12_iter(hx509_context context,
668178825Sdfr	 hx509_certs certs,
669178825Sdfr	 void *data,
670178825Sdfr	 void *cursor,
671178825Sdfr	 hx509_cert *cert)
672178825Sdfr{
673178825Sdfr    struct ks_pkcs12 *p12 = data;
674178825Sdfr    return hx509_certs_next_cert(context, p12->certs, cursor, cert);
675178825Sdfr}
676178825Sdfr
677178825Sdfrstatic int
678178825Sdfrp12_iter_end(hx509_context context,
679178825Sdfr	     hx509_certs certs,
680178825Sdfr	     void *data,
681178825Sdfr	     void *cursor)
682178825Sdfr{
683178825Sdfr    struct ks_pkcs12 *p12 = data;
684178825Sdfr    return hx509_certs_end_seq(context, p12->certs, cursor);
685178825Sdfr}
686178825Sdfr
687178825Sdfrstatic struct hx509_keyset_ops keyset_pkcs12 = {
688178825Sdfr    "PKCS12",
689178825Sdfr    0,
690178825Sdfr    p12_init,
691178825Sdfr    p12_store,
692178825Sdfr    p12_free,
693178825Sdfr    p12_add,
694178825Sdfr    NULL,
695178825Sdfr    p12_iter_start,
696178825Sdfr    p12_iter,
697178825Sdfr    p12_iter_end
698178825Sdfr};
699178825Sdfr
700178825Sdfrvoid
701178825Sdfr_hx509_ks_pkcs12_register(hx509_context context)
702178825Sdfr{
703178825Sdfr    _hx509_ks_register(context, &keyset_pkcs12);
704178825Sdfr}
705