2 * Ick. This is (or at least started off as) a straight copy of
3 * parse_pkcs12() from GnuTLS lib/gnutls_x509.c, as of commit ID
4 * 77670476814c078bbad56ce8772b192a3b5736b6 on the gnutls_2_12_x
7 * We need to *see* the cert so that we can check its expiry, and
8 * we'll also want to get all the other certs in the PKCS#12 file
9 * rather than only the leaf node. Hopefully these changes can be
10 * merged back into GnuTLS as soon as possible, it can be made a
11 * public function, and this copy can die.
13 #define opaque unsigned char
14 #define gnutls_assert() do {} while(0)
17 * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
18 * Free Software Foundation, Inc.
20 * Author: Nikos Mavrogiannopoulos
22 * This file WAS part of GnuTLS.
24 * The GnuTLS is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU Lesser General Public License
26 * as published by the Free Software Foundation; either version 2.1 of
27 * the License, or (at your option) any later version.
29 * This library is distributed in the hope that it will be useful, but
30 * WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32 * Lesser General Public License for more details.
34 * You should have received a copy of the GNU Lesser General Public
35 * License along with this library; if not, write to the Free Software
36 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
43 parse_pkcs12 (gnutls_certificate_credentials_t res,
46 gnutls_x509_privkey_t * key,
47 gnutls_x509_crt_t * cert,
48 gnutls_x509_crt_t ** extra_certs_ret,
49 unsigned int * extra_certs_ret_len,
50 gnutls_x509_crl_t * crl)
52 gnutls_pkcs12_bag_t bag = NULL;
53 gnutls_x509_crt_t *extra_certs = NULL;
54 int extra_certs_len = 0;
57 size_t cert_id_size = 0;
58 size_t key_id_size = 0;
67 /* find the first private key */
73 ret = gnutls_pkcs12_bag_init (&bag);
81 ret = gnutls_pkcs12_get_bag (p12, idx, bag);
82 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
90 ret = gnutls_pkcs12_bag_get_type (bag, 0);
97 if (ret == GNUTLS_BAG_ENCRYPTED)
99 ret = gnutls_pkcs12_bag_decrypt (bag, password);
107 elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
108 if (elements_in_bag < 0)
114 for (i = 0; i < elements_in_bag; i++)
119 type = gnutls_pkcs12_bag_get_type (bag, i);
126 ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
135 case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
136 case GNUTLS_BAG_PKCS8_KEY:
137 if (*key != NULL) /* too simple to continue */
143 ret = gnutls_x509_privkey_init (key);
150 ret = gnutls_x509_privkey_import_pkcs8
151 (*key, &data, GNUTLS_X509_FMT_DER, password,
152 type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0);
156 gnutls_x509_privkey_deinit (*key);
160 key_id_size = sizeof (key_id);
162 gnutls_x509_privkey_get_key_id (*key, 0, key_id,
167 gnutls_x509_privkey_deinit (*key);
171 privkey_ok = 1; /* break */
179 gnutls_pkcs12_bag_deinit (bag);
181 if (privkey_ok != 0) /* private key was found */
185 if (privkey_ok == 0) /* no private key */
188 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
191 /* now find the corresponding certificate
200 ret = gnutls_pkcs12_bag_init (&bag);
208 ret = gnutls_pkcs12_get_bag (p12, idx, bag);
209 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
217 ret = gnutls_pkcs12_bag_get_type (bag, 0);
224 if (ret == GNUTLS_BAG_ENCRYPTED)
226 ret = gnutls_pkcs12_bag_decrypt (bag, password);
234 elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
235 if (elements_in_bag < 0)
241 for (i = 0; i < elements_in_bag; i++)
245 gnutls_x509_crt_t this_cert;
247 type = gnutls_pkcs12_bag_get_type (bag, i);
254 ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
263 case GNUTLS_BAG_CERTIFICATE:
264 ret = gnutls_x509_crt_init (&this_cert);
272 gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER);
276 gnutls_x509_crt_deinit (this_cert);
280 /* check if the key id match */
281 cert_id_size = sizeof (cert_id);
283 gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size);
287 gnutls_x509_crt_deinit (this_cert);
291 if (memcmp (cert_id, key_id, cert_id_size) != 0)
292 { /* they don't match - skip the certificate */
295 extra_certs = gnutls_realloc (extra_certs,
296 sizeof(extra_certs[0]) *
301 ret = GNUTLS_E_MEMORY_ERROR;
304 extra_certs[extra_certs_len - 1] = this_cert;
309 gnutls_x509_crt_deinit (this_cert);
315 if (*cert != NULL) /* no need to set it again */
332 ret = gnutls_x509_crl_init (crl);
339 ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER);
343 gnutls_x509_crl_deinit (*crl);
348 case GNUTLS_BAG_ENCRYPTED:
349 /* XXX Bother to recurse one level down? Unlikely to
350 use the same password anyway. */
351 case GNUTLS_BAG_EMPTY:
358 gnutls_pkcs12_bag_deinit (bag);
365 gnutls_pkcs12_bag_deinit (bag);
370 gnutls_x509_privkey_deinit(*key);
372 gnutls_x509_crt_deinit(*cert);
376 for (i = 0; i < extra_certs_len; i++)
377 gnutls_x509_crt_deinit(extra_certs[i]);
378 gnutls_free(extra_certs);
381 else if (extra_certs_ret)
383 *extra_certs_ret = extra_certs;
384 *extra_certs_ret_len = extra_certs_len;