2 * This is (now) gnutls_pkcs12_simple_parse() from GnuTLS 3.1, although
3 * it was actually taken from parse_pkcs12() in GnuTLS 2.12.x (where it
4 * was under LGPLv2.1) and modified locally. The modifications were
5 * accepted back into GnuTLS in commit 9a43e8fa. Further modifications
6 * by Nikos Mavrogiannopoulos are included here under LGPLv2.1 with his
10 #ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
15 #define opaque unsigned char
16 #define gnutls_assert() do {} while(0)
17 #define gnutls_assert_val(x) (x)
20 * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
21 * Free Software Foundation, Inc.
23 * Author: Nikos Mavrogiannopoulos
25 * This file WAS part of GnuTLS.
27 * The GnuTLS is free software; you can redistribute it and/or
28 * modify it under the terms of the GNU Lesser General Public License
29 * as published by the Free Software Foundation; either version 2.1 of
30 * the License, or (at your option) any later version.
32 * This library is distributed in the hope that it will be useful, but
33 * WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35 * Lesser General Public License for more details.
37 * You should have received a copy of the GNU Lesser General Public
38 * License along with this library; if not, write to the Free Software
39 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
45 /* Checks if the extra_certs contain certificates that may form a chain
46 * with the first certificate in chain (it is expected that chain_len==1)
47 * and appends those in the chain.
49 static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len,
50 gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len)
55 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
58 while(i<*extra_certs_len)
60 /* if it is an issuer but not a self-signed one */
61 if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0 &&
62 gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) == 0)
64 *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) *
69 return GNUTLS_E_MEMORY_ERROR;
71 (*chain)[*chain_len - 1] = (*extra_certs)[i];
73 (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1];
85 * gnutls_pkcs12_simple_parse:
86 * @p12: the PKCS#12 blob.
87 * @password: optional password used to decrypt PKCS#12 blob, bags and keys.
88 * @key: a structure to store the parsed private key.
89 * @chain: the corresponding to key certificate chain
90 * @chain_len: will be updated with the number of additional
91 * @extra_certs: optional pointer to receive an array of additional
92 * certificates found in the PKCS#12 blob.
93 * @extra_certs_len: will be updated with the number of additional
95 * @crl: an optional structure to store the parsed CRL.
96 * @flags: should be zero
98 * This function parses a PKCS#12 blob in @p12blob and extracts the
99 * private key, the corresponding certificate chain, and any additional
100 * certificates and a CRL.
102 * The @extra_certs_ret and @extra_certs_ret_len parameters are optional
103 * and both may be set to %NULL. If either is non-%NULL, then both must
106 * MAC:ed PKCS#12 files are supported. Encrypted PKCS#12 bags are
107 * supported. Encrypted PKCS#8 private keys are supported. However,
108 * only password based security, and the same password for all
109 * operations, are supported.
111 * The private keys may be RSA PKCS#1 or DSA private keys encoded in
114 * PKCS#12 file may contain many keys and/or certificates, and there
115 * is no way to identify which key/certificate pair you want. You
116 * should make sure the PKCS#12 file only contain one key/certificate
117 * pair and/or one CRL.
119 * It is believed that the limitations of this function is acceptable
120 * for most usage, and that any more flexibility would introduce
121 * complexity that would make it harder to use this functionality at
124 * If the provided structure has encrypted fields but no password
125 * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
127 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
128 * negative error value.
133 gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12,
134 const char *password,
135 gnutls_x509_privkey_t * key,
136 gnutls_x509_crt_t ** chain,
137 unsigned int * chain_len,
138 gnutls_x509_crt_t ** extra_certs,
139 unsigned int * extra_certs_len,
140 gnutls_x509_crl_t * crl,
143 gnutls_pkcs12_bag_t bag = NULL;
144 gnutls_x509_crt_t *_extra_certs = NULL;
145 unsigned int _extra_certs_len = 0;
146 gnutls_x509_crt_t *_chain = NULL;
147 unsigned int _chain_len = 0;
150 size_t cert_id_size = 0;
151 size_t key_id_size = 0;
161 /* find the first private key */
167 ret = gnutls_pkcs12_bag_init (&bag);
175 ret = gnutls_pkcs12_get_bag (p12, idx, bag);
176 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
184 ret = gnutls_pkcs12_bag_get_type (bag, 0);
191 if (ret == GNUTLS_BAG_ENCRYPTED)
193 if (password == NULL)
195 ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
199 ret = gnutls_pkcs12_bag_decrypt (bag, password);
207 elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
208 if (elements_in_bag < 0)
214 for (i = 0; i < elements_in_bag; i++)
219 type = gnutls_pkcs12_bag_get_type (bag, i);
226 ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
235 case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
236 if (password == NULL)
238 ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
242 case GNUTLS_BAG_PKCS8_KEY:
243 if (*key != NULL) /* too simple to continue */
249 ret = gnutls_x509_privkey_init (key);
256 ret = gnutls_x509_privkey_import_pkcs8
257 (*key, &data, GNUTLS_X509_FMT_DER, password,
258 type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0);
262 gnutls_x509_privkey_deinit (*key);
266 key_id_size = sizeof (key_id);
268 gnutls_x509_privkey_get_key_id (*key, 0, key_id,
273 gnutls_x509_privkey_deinit (*key);
277 privkey_ok = 1; /* break */
285 gnutls_pkcs12_bag_deinit (bag);
287 if (privkey_ok != 0) /* private key was found */
291 if (privkey_ok == 0) /* no private key */
294 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
297 /* now find the corresponding certificate
306 ret = gnutls_pkcs12_bag_init (&bag);
314 ret = gnutls_pkcs12_get_bag (p12, idx, bag);
315 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
323 ret = gnutls_pkcs12_bag_get_type (bag, 0);
330 if (ret == GNUTLS_BAG_ENCRYPTED)
332 ret = gnutls_pkcs12_bag_decrypt (bag, password);
340 elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
341 if (elements_in_bag < 0)
347 for (i = 0; i < elements_in_bag; i++)
351 gnutls_x509_crt_t this_cert;
353 type = gnutls_pkcs12_bag_get_type (bag, i);
360 ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
369 case GNUTLS_BAG_CERTIFICATE:
370 ret = gnutls_x509_crt_init (&this_cert);
378 gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER);
382 gnutls_x509_crt_deinit (this_cert);
386 /* check if the key id match */
387 cert_id_size = sizeof (cert_id);
389 gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size);
393 gnutls_x509_crt_deinit (this_cert);
397 if (memcmp (cert_id, key_id, cert_id_size) != 0)
398 { /* they don't match - skip the certificate */
401 _extra_certs = gnutls_realloc (_extra_certs,
402 sizeof(_extra_certs[0]) *
407 ret = GNUTLS_E_MEMORY_ERROR;
410 _extra_certs[_extra_certs_len - 1] = this_cert;
415 gnutls_x509_crt_deinit (this_cert);
422 _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len));
426 ret = GNUTLS_E_MEMORY_ERROR;
429 _chain[_chain_len - 1] = this_cert;
434 gnutls_x509_crt_deinit (this_cert);
440 if (crl == NULL || *crl != NULL)
446 ret = gnutls_x509_crl_init (crl);
453 ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER);
457 gnutls_x509_crl_deinit (*crl);
462 case GNUTLS_BAG_ENCRYPTED:
463 /* XXX Bother to recurse one level down? Unlikely to
464 use the same password anyway. */
465 case GNUTLS_BAG_EMPTY:
472 gnutls_pkcs12_bag_deinit (bag);
477 ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
481 ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len);
492 gnutls_pkcs12_bag_deinit (bag);
497 gnutls_x509_privkey_deinit(*key);
498 if (_extra_certs_len && _extra_certs != NULL)
501 for (i = 0; i < _extra_certs_len; i++)
502 gnutls_x509_crt_deinit(_extra_certs[i]);
503 gnutls_free(_extra_certs);
505 if (_chain_len && _chain != NULL)
508 for (i = 0; i < _chain_len; i++)
509 gnutls_x509_crt_deinit(_chain[i]);
517 *extra_certs = _extra_certs;
518 *extra_certs_len = _extra_certs_len;
522 *chain_len = _chain_len;
528 #endif /* HAVE_GNUTLS_PKCS12_SIMPLE_PARSE */