Cope with lack of gnutls_certificate_set_key() in GnuTLS 2.12
[platform/upstream/openconnect.git] / gnutls_pkcs12.c
1 /*
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
7  * explicit permission.
8  */
9
10 #define opaque unsigned char
11 #define gnutls_assert() do {} while(0)
12 #define gnutls_assert_val(x) (x)
13
14 /*
15  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
16  * Free Software Foundation, Inc.
17  *
18  * Author: Nikos Mavrogiannopoulos
19  *
20  * This file WAS part of GnuTLS.
21  *
22  * The GnuTLS is free software; you can redistribute it and/or
23  * modify it under the terms of the GNU Lesser General Public License
24  * as published by the Free Software Foundation; either version 2.1 of
25  * the License, or (at your option) any later version.
26  *
27  * This library is distributed in the hope that it will be useful, but
28  * WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30  * Lesser General Public License for more details.
31  *
32  * You should have received a copy of the GNU Lesser General Public
33  * License along with this library; if not, write to the Free Software
34  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
35  * USA
36  *
37  */
38
39
40 /* Checks if the extra_certs contain certificates that may form a chain
41  * with the first certificate in chain (it is expected that chain_len==1)
42  * and appends those in the chain.
43  */
44 static int make_chain(gnutls_x509_crt_t **chain, unsigned int *chain_len,
45                       gnutls_x509_crt_t **extra_certs, unsigned int *extra_certs_len)
46 {
47 unsigned int i;
48
49   if (*chain_len != 1)
50     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
51   
52   i = 0;
53   while(i<*extra_certs_len)
54     {
55       /* if it is an issuer but not a self-signed one */
56       if (gnutls_x509_crt_check_issuer((*chain)[*chain_len - 1], (*extra_certs)[i]) != 0 &&
57           gnutls_x509_crt_check_issuer((*extra_certs)[i], (*extra_certs)[i]) == 0)
58         {
59            *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) *
60                                                      ++(*chain_len));
61            if (*chain == NULL)
62              {
63                gnutls_assert();
64                return GNUTLS_E_MEMORY_ERROR;
65              }
66            (*chain)[*chain_len - 1] = (*extra_certs)[i];
67            
68            (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1];
69            (*extra_certs_len)--;
70
71            i=0;
72            continue;
73         }
74       i++;
75     }
76   return 0;
77 }
78
79 /**
80  * gnutls_pkcs12_simple_parse:
81  * @p12: the PKCS#12 blob.
82  * @password: optional password used to decrypt PKCS#12 blob, bags and keys.
83  * @key: a structure to store the parsed private key.
84  * @chain: the corresponding to key certificate chain
85  * @chain_len: will be updated with the number of additional
86  * @extra_certs: optional pointer to receive an array of additional
87  *                   certificates found in the PKCS#12 blob.
88  * @extra_certs_len: will be updated with the number of additional
89  *                       certs.
90  * @crl: an optional structure to store the parsed CRL.
91  * @flags: should be zero
92  *
93  * This function parses a PKCS#12 blob in @p12blob and extracts the
94  * private key, the corresponding certificate chain, and any additional
95  * certificates and a CRL.
96  *
97  * The @extra_certs_ret and @extra_certs_ret_len parameters are optional
98  * and both may be set to %NULL. If either is non-%NULL, then both must
99  * be.
100  * 
101  * MAC:ed PKCS#12 files are supported.  Encrypted PKCS#12 bags are
102  * supported.  Encrypted PKCS#8 private keys are supported.  However,
103  * only password based security, and the same password for all
104  * operations, are supported.
105  *
106  * The private keys may be RSA PKCS#1 or DSA private keys encoded in
107  * the OpenSSL way.
108  *
109  * PKCS#12 file may contain many keys and/or certificates, and there
110  * is no way to identify which key/certificate pair you want.  You
111  * should make sure the PKCS#12 file only contain one key/certificate
112  * pair and/or one CRL.
113  *
114  * It is believed that the limitations of this function is acceptable
115  * for most usage, and that any more flexibility would introduce
116  * complexity that would make it harder to use this functionality at
117  * all.
118  *
119  * If the provided structure has encrypted fields but no password
120  * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
121  *
122  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
123  *   negative error value.
124  *
125  * Since: 3.1
126  **/
127 static int
128 gnutls_pkcs12_simple_parse (gnutls_pkcs12_t p12,
129                      const char *password,
130                      gnutls_x509_privkey_t * key,
131                      gnutls_x509_crt_t ** chain,
132                      unsigned int * chain_len,
133                      gnutls_x509_crt_t ** extra_certs,
134                      unsigned int * extra_certs_len,
135                      gnutls_x509_crl_t * crl,
136                      unsigned int flags)
137 {
138   gnutls_pkcs12_bag_t bag = NULL;
139   gnutls_x509_crt_t *_extra_certs = NULL;
140   unsigned int _extra_certs_len = 0;
141   gnutls_x509_crt_t *_chain = NULL;
142   unsigned int _chain_len = 0;
143   int idx = 0;
144   int ret;
145   size_t cert_id_size = 0;
146   size_t key_id_size = 0;
147   opaque cert_id[20];
148   opaque key_id[20];
149   int privkey_ok = 0;
150
151   *key = NULL;
152   
153   if (crl)
154     *crl = NULL;
155
156   /* find the first private key */
157   for (;;)
158     {
159       int elements_in_bag;
160       int i;
161
162       ret = gnutls_pkcs12_bag_init (&bag);
163       if (ret < 0)
164         {
165           bag = NULL;
166           gnutls_assert ();
167           goto done;
168         }
169
170       ret = gnutls_pkcs12_get_bag (p12, idx, bag);
171       if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
172         break;
173       if (ret < 0)
174         {
175           gnutls_assert ();
176           goto done;
177         }
178
179       ret = gnutls_pkcs12_bag_get_type (bag, 0);
180       if (ret < 0)
181         {
182           gnutls_assert ();
183           goto done;
184         }
185
186       if (ret == GNUTLS_BAG_ENCRYPTED)
187         {
188           if (password == NULL)
189             {
190               ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
191               goto done;
192             }
193
194           ret = gnutls_pkcs12_bag_decrypt (bag, password);
195           if (ret < 0)
196             {
197               gnutls_assert ();
198               goto done;
199             }
200         }
201
202       elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
203       if (elements_in_bag < 0)
204         {
205           gnutls_assert ();
206           goto done;
207         }
208
209       for (i = 0; i < elements_in_bag; i++)
210         {
211           int type;
212           gnutls_datum_t data;
213
214           type = gnutls_pkcs12_bag_get_type (bag, i);
215           if (type < 0)
216             {
217               gnutls_assert ();
218               goto done;
219             }
220
221           ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
222           if (ret < 0)
223             {
224               gnutls_assert ();
225               goto done;
226             }
227
228           switch (type)
229             {
230             case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
231               if (password == NULL)
232                 {
233                   ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
234                   goto done;
235                 }
236
237             case GNUTLS_BAG_PKCS8_KEY:
238               if (*key != NULL) /* too simple to continue */
239                 {
240                   gnutls_assert ();
241                   break;
242                 }
243
244               ret = gnutls_x509_privkey_init (key);
245               if (ret < 0)
246                 {
247                   gnutls_assert ();
248                   goto done;
249                 }
250
251               ret = gnutls_x509_privkey_import_pkcs8
252                 (*key, &data, GNUTLS_X509_FMT_DER, password,
253                  type == GNUTLS_BAG_PKCS8_KEY ? GNUTLS_PKCS_PLAIN : 0);
254               if (ret < 0)
255                 {
256                   gnutls_assert ();
257                   gnutls_x509_privkey_deinit (*key);
258                   goto done;
259                 }
260
261               key_id_size = sizeof (key_id);
262               ret =
263                 gnutls_x509_privkey_get_key_id (*key, 0, key_id,
264                                                 &key_id_size);
265               if (ret < 0)
266                 {
267                   gnutls_assert ();
268                   gnutls_x509_privkey_deinit (*key);
269                   goto done;
270                 }
271
272               privkey_ok = 1;   /* break */
273               break;
274             default:
275               break;
276             }
277         }
278
279       idx++;
280       gnutls_pkcs12_bag_deinit (bag);
281
282       if (privkey_ok != 0)      /* private key was found */
283         break;
284     }
285
286   if (privkey_ok == 0)          /* no private key */
287     {
288       gnutls_assert ();
289       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
290     }
291
292   /* now find the corresponding certificate 
293    */
294   idx = 0;
295   bag = NULL;
296   for (;;)
297     {
298       int elements_in_bag;
299       int i;
300
301       ret = gnutls_pkcs12_bag_init (&bag);
302       if (ret < 0)
303         {
304           bag = NULL;
305           gnutls_assert ();
306           goto done;
307         }
308
309       ret = gnutls_pkcs12_get_bag (p12, idx, bag);
310       if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
311         break;
312       if (ret < 0)
313         {
314           gnutls_assert ();
315           goto done;
316         }
317
318       ret = gnutls_pkcs12_bag_get_type (bag, 0);
319       if (ret < 0)
320         {
321           gnutls_assert ();
322           goto done;
323         }
324
325       if (ret == GNUTLS_BAG_ENCRYPTED)
326         {
327           ret = gnutls_pkcs12_bag_decrypt (bag, password);
328           if (ret < 0)
329             {
330               gnutls_assert ();
331               goto done;
332             }
333         }
334
335       elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
336       if (elements_in_bag < 0)
337         {
338           gnutls_assert ();
339           goto done;
340         }
341
342       for (i = 0; i < elements_in_bag; i++)
343         {
344           int type;
345           gnutls_datum_t data;
346           gnutls_x509_crt_t this_cert;
347
348           type = gnutls_pkcs12_bag_get_type (bag, i);
349           if (type < 0)
350             {
351               gnutls_assert ();
352               goto done;
353             }
354
355           ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
356           if (ret < 0)
357             {
358               gnutls_assert ();
359               goto done;
360             }
361
362           switch (type)
363             {
364             case GNUTLS_BAG_CERTIFICATE:
365               ret = gnutls_x509_crt_init (&this_cert);
366               if (ret < 0)
367                 {
368                   gnutls_assert ();
369                   goto done;
370                 }
371
372               ret =
373                 gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER);
374               if (ret < 0)
375                 {
376                   gnutls_assert ();
377                   gnutls_x509_crt_deinit (this_cert);
378                   goto done;
379                 }
380
381               /* check if the key id match */
382               cert_id_size = sizeof (cert_id);
383               ret =
384                 gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size);
385               if (ret < 0)
386                 {
387                   gnutls_assert ();
388                   gnutls_x509_crt_deinit (this_cert);
389                   goto done;
390                 }
391
392               if (memcmp (cert_id, key_id, cert_id_size) != 0)
393                 { /* they don't match - skip the certificate */
394                   if (extra_certs)
395                     {
396                       _extra_certs = gnutls_realloc (_extra_certs,
397                                                      sizeof(_extra_certs[0]) *
398                                                      ++_extra_certs_len);
399                       if (!_extra_certs)
400                         {
401                           gnutls_assert ();
402                           ret = GNUTLS_E_MEMORY_ERROR;
403                           goto done;
404                         }
405                       _extra_certs[_extra_certs_len - 1] = this_cert;
406                       this_cert = NULL;
407                     }
408                   else
409                     {
410                        gnutls_x509_crt_deinit (this_cert);
411                     }
412                 }
413               else
414                 {
415                   if (_chain_len == 0)
416                     {
417                       _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len));
418                       if (!_chain)
419                         {
420                           gnutls_assert ();
421                           ret = GNUTLS_E_MEMORY_ERROR;
422                           goto done;
423                         }
424                       _chain[_chain_len - 1] = this_cert;
425                       this_cert = NULL;
426                     }
427                   else
428                     {
429                        gnutls_x509_crt_deinit (this_cert);
430                     }
431                 }
432               break;
433
434             case GNUTLS_BAG_CRL:
435               if (crl == NULL || *crl != NULL)
436                 {
437                   gnutls_assert ();
438                   break;
439                 }
440
441               ret = gnutls_x509_crl_init (crl);
442               if (ret < 0)
443                 {
444                   gnutls_assert ();
445                   goto done;
446                 }
447
448               ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER);
449               if (ret < 0)
450                 {
451                   gnutls_assert ();
452                   gnutls_x509_crl_deinit (*crl);
453                   goto done;
454                 }
455               break;
456
457             case GNUTLS_BAG_ENCRYPTED:
458               /* XXX Bother to recurse one level down?  Unlikely to
459                  use the same password anyway. */
460             case GNUTLS_BAG_EMPTY:
461             default:
462               break;
463             }
464         }
465
466       idx++;
467       gnutls_pkcs12_bag_deinit (bag);
468     }
469
470   if (_chain_len != 1)
471     {
472       ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
473       goto done;
474     }
475
476   ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len);
477   if (ret < 0)
478     {
479       gnutls_assert();
480       goto done;
481     }
482
483   ret = 0;
484
485 done:
486   if (bag)
487     gnutls_pkcs12_bag_deinit (bag);
488
489   if (ret < 0)
490     {
491       if (*key)
492         gnutls_x509_privkey_deinit(*key);
493       if (_extra_certs_len && _extra_certs != NULL)
494         {
495           unsigned int i;
496           for (i = 0; i < _extra_certs_len; i++)
497             gnutls_x509_crt_deinit(_extra_certs[i]);
498           gnutls_free(_extra_certs);
499         }
500       if (_chain_len && chain != NULL)
501         {
502           unsigned int i;
503           for (i = 0; i < _chain_len; i++)
504             gnutls_x509_crt_deinit(_chain[i]);
505           gnutls_free(_chain);
506         }
507     }
508   else 
509     {
510       if (extra_certs) 
511         {
512           *extra_certs = _extra_certs;
513           *extra_certs_len = _extra_certs_len;
514         }
515       
516       *chain = _chain;
517       *chain_len = _chain_len;
518     }
519
520   return ret;
521 }