Update translations from Transifex
[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 #ifndef HAVE_GNUTLS_PKCS12_SIMPLE_PARSE
11
12 #include <string.h>
13 #include "gnutls.h"
14
15 #define opaque unsigned char
16 #define gnutls_assert() do {} while(0)
17 #define gnutls_assert_val(x) (x)
18
19 /*
20  * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
21  * Free Software Foundation, Inc.
22  *
23  * Author: Nikos Mavrogiannopoulos
24  *
25  * This file WAS part of GnuTLS.
26  *
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.
31  *
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.
36  *
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,
40  * USA
41  *
42  */
43
44
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.
48  */
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)
51 {
52 unsigned int i;
53
54   if (*chain_len != 1)
55     return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
56   
57   i = 0;
58   while(i<*extra_certs_len)
59     {
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)
63         {
64            *chain = gnutls_realloc (*chain, sizeof((*chain)[0]) *
65                                                      ++(*chain_len));
66            if (*chain == NULL)
67              {
68                gnutls_assert();
69                return GNUTLS_E_MEMORY_ERROR;
70              }
71            (*chain)[*chain_len - 1] = (*extra_certs)[i];
72            
73            (*extra_certs)[i] = (*extra_certs)[*extra_certs_len-1];
74            (*extra_certs_len)--;
75
76            i=0;
77            continue;
78         }
79       i++;
80     }
81   return 0;
82 }
83
84 /**
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
94  *                       certs.
95  * @crl: an optional structure to store the parsed CRL.
96  * @flags: should be zero
97  *
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.
101  *
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
104  * be.
105  * 
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.
110  *
111  * The private keys may be RSA PKCS#1 or DSA private keys encoded in
112  * the OpenSSL way.
113  *
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.
118  *
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
122  * all.
123  *
124  * If the provided structure has encrypted fields but no password
125  * is provided then this function returns %GNUTLS_E_DECRYPTION_FAILED.
126  *
127  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
128  *   negative error value.
129  *
130  * Since: 3.1
131  **/
132 int
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,
141                      unsigned int flags)
142 {
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;
148   int idx = 0;
149   int ret;
150   size_t cert_id_size = 0;
151   size_t key_id_size = 0;
152   opaque cert_id[20];
153   opaque key_id[20];
154   int privkey_ok = 0;
155
156   *key = NULL;
157   
158   if (crl)
159     *crl = NULL;
160
161   /* find the first private key */
162   for (;;)
163     {
164       int elements_in_bag;
165       int i;
166
167       ret = gnutls_pkcs12_bag_init (&bag);
168       if (ret < 0)
169         {
170           bag = NULL;
171           gnutls_assert ();
172           goto done;
173         }
174
175       ret = gnutls_pkcs12_get_bag (p12, idx, bag);
176       if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
177         break;
178       if (ret < 0)
179         {
180           gnutls_assert ();
181           goto done;
182         }
183
184       ret = gnutls_pkcs12_bag_get_type (bag, 0);
185       if (ret < 0)
186         {
187           gnutls_assert ();
188           goto done;
189         }
190
191       if (ret == GNUTLS_BAG_ENCRYPTED)
192         {
193           if (password == NULL)
194             {
195               ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
196               goto done;
197             }
198
199           ret = gnutls_pkcs12_bag_decrypt (bag, password);
200           if (ret < 0)
201             {
202               gnutls_assert ();
203               goto done;
204             }
205         }
206
207       elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
208       if (elements_in_bag < 0)
209         {
210           gnutls_assert ();
211           goto done;
212         }
213
214       for (i = 0; i < elements_in_bag; i++)
215         {
216           int type;
217           gnutls_datum_t data;
218
219           type = gnutls_pkcs12_bag_get_type (bag, i);
220           if (type < 0)
221             {
222               gnutls_assert ();
223               goto done;
224             }
225
226           ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
227           if (ret < 0)
228             {
229               gnutls_assert ();
230               goto done;
231             }
232
233           switch (type)
234             {
235             case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
236               if (password == NULL)
237                 {
238                   ret = gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
239                   goto done;
240                 }
241
242             case GNUTLS_BAG_PKCS8_KEY:
243               if (*key != NULL) /* too simple to continue */
244                 {
245                   gnutls_assert ();
246                   break;
247                 }
248
249               ret = gnutls_x509_privkey_init (key);
250               if (ret < 0)
251                 {
252                   gnutls_assert ();
253                   goto done;
254                 }
255
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);
259               if (ret < 0)
260                 {
261                   gnutls_assert ();
262                   gnutls_x509_privkey_deinit (*key);
263                   goto done;
264                 }
265
266               key_id_size = sizeof (key_id);
267               ret =
268                 gnutls_x509_privkey_get_key_id (*key, 0, key_id,
269                                                 &key_id_size);
270               if (ret < 0)
271                 {
272                   gnutls_assert ();
273                   gnutls_x509_privkey_deinit (*key);
274                   goto done;
275                 }
276
277               privkey_ok = 1;   /* break */
278               break;
279             default:
280               break;
281             }
282         }
283
284       idx++;
285       gnutls_pkcs12_bag_deinit (bag);
286
287       if (privkey_ok != 0)      /* private key was found */
288         break;
289     }
290
291   if (privkey_ok == 0)          /* no private key */
292     {
293       gnutls_assert ();
294       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
295     }
296
297   /* now find the corresponding certificate 
298    */
299   idx = 0;
300   bag = NULL;
301   for (;;)
302     {
303       int elements_in_bag;
304       int i;
305
306       ret = gnutls_pkcs12_bag_init (&bag);
307       if (ret < 0)
308         {
309           bag = NULL;
310           gnutls_assert ();
311           goto done;
312         }
313
314       ret = gnutls_pkcs12_get_bag (p12, idx, bag);
315       if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
316         break;
317       if (ret < 0)
318         {
319           gnutls_assert ();
320           goto done;
321         }
322
323       ret = gnutls_pkcs12_bag_get_type (bag, 0);
324       if (ret < 0)
325         {
326           gnutls_assert ();
327           goto done;
328         }
329
330       if (ret == GNUTLS_BAG_ENCRYPTED)
331         {
332           ret = gnutls_pkcs12_bag_decrypt (bag, password);
333           if (ret < 0)
334             {
335               gnutls_assert ();
336               goto done;
337             }
338         }
339
340       elements_in_bag = gnutls_pkcs12_bag_get_count (bag);
341       if (elements_in_bag < 0)
342         {
343           gnutls_assert ();
344           goto done;
345         }
346
347       for (i = 0; i < elements_in_bag; i++)
348         {
349           int type;
350           gnutls_datum_t data;
351           gnutls_x509_crt_t this_cert;
352
353           type = gnutls_pkcs12_bag_get_type (bag, i);
354           if (type < 0)
355             {
356               gnutls_assert ();
357               goto done;
358             }
359
360           ret = gnutls_pkcs12_bag_get_data (bag, i, &data);
361           if (ret < 0)
362             {
363               gnutls_assert ();
364               goto done;
365             }
366
367           switch (type)
368             {
369             case GNUTLS_BAG_CERTIFICATE:
370               ret = gnutls_x509_crt_init (&this_cert);
371               if (ret < 0)
372                 {
373                   gnutls_assert ();
374                   goto done;
375                 }
376
377               ret =
378                 gnutls_x509_crt_import (this_cert, &data, GNUTLS_X509_FMT_DER);
379               if (ret < 0)
380                 {
381                   gnutls_assert ();
382                   gnutls_x509_crt_deinit (this_cert);
383                   goto done;
384                 }
385
386               /* check if the key id match */
387               cert_id_size = sizeof (cert_id);
388               ret =
389                 gnutls_x509_crt_get_key_id (this_cert, 0, cert_id, &cert_id_size);
390               if (ret < 0)
391                 {
392                   gnutls_assert ();
393                   gnutls_x509_crt_deinit (this_cert);
394                   goto done;
395                 }
396
397               if (memcmp (cert_id, key_id, cert_id_size) != 0)
398                 { /* they don't match - skip the certificate */
399                   if (extra_certs)
400                     {
401                       _extra_certs = gnutls_realloc (_extra_certs,
402                                                      sizeof(_extra_certs[0]) *
403                                                      ++_extra_certs_len);
404                       if (!_extra_certs)
405                         {
406                           gnutls_assert ();
407                           ret = GNUTLS_E_MEMORY_ERROR;
408                           goto done;
409                         }
410                       _extra_certs[_extra_certs_len - 1] = this_cert;
411                       this_cert = NULL;
412                     }
413                   else
414                     {
415                        gnutls_x509_crt_deinit (this_cert);
416                     }
417                 }
418               else
419                 {
420                   if (_chain_len == 0)
421                     {
422                       _chain = gnutls_malloc (sizeof(_chain[0]) * (++_chain_len));
423                       if (!_chain)
424                         {
425                           gnutls_assert ();
426                           ret = GNUTLS_E_MEMORY_ERROR;
427                           goto done;
428                         }
429                       _chain[_chain_len - 1] = this_cert;
430                       this_cert = NULL;
431                     }
432                   else
433                     {
434                        gnutls_x509_crt_deinit (this_cert);
435                     }
436                 }
437               break;
438
439             case GNUTLS_BAG_CRL:
440               if (crl == NULL || *crl != NULL)
441                 {
442                   gnutls_assert ();
443                   break;
444                 }
445
446               ret = gnutls_x509_crl_init (crl);
447               if (ret < 0)
448                 {
449                   gnutls_assert ();
450                   goto done;
451                 }
452
453               ret = gnutls_x509_crl_import (*crl, &data, GNUTLS_X509_FMT_DER);
454               if (ret < 0)
455                 {
456                   gnutls_assert ();
457                   gnutls_x509_crl_deinit (*crl);
458                   goto done;
459                 }
460               break;
461
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:
466             default:
467               break;
468             }
469         }
470
471       idx++;
472       gnutls_pkcs12_bag_deinit (bag);
473     }
474
475   if (_chain_len != 1)
476     {
477       ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
478       goto done;
479     }
480
481   ret = make_chain(&_chain, &_chain_len, &_extra_certs, &_extra_certs_len);
482   if (ret < 0)
483     {
484       gnutls_assert();
485       goto done;
486     }
487
488   ret = 0;
489
490 done:
491   if (bag)
492     gnutls_pkcs12_bag_deinit (bag);
493
494   if (ret < 0)
495     {
496       if (*key)
497         gnutls_x509_privkey_deinit(*key);
498       if (_extra_certs_len && _extra_certs != NULL)
499         {
500           unsigned int i;
501           for (i = 0; i < _extra_certs_len; i++)
502             gnutls_x509_crt_deinit(_extra_certs[i]);
503           gnutls_free(_extra_certs);
504         }
505       if (_chain_len && chain != NULL)
506         {
507           unsigned int i;
508           for (i = 0; i < _chain_len; i++)
509             gnutls_x509_crt_deinit(_chain[i]);
510           gnutls_free(_chain);
511         }
512     }
513   else 
514     {
515       if (extra_certs) 
516         {
517           *extra_certs = _extra_certs;
518           *extra_certs_len = _extra_certs_len;
519         }
520       
521       *chain = _chain;
522       *chain_len = _chain_len;
523     }
524
525   return ret;
526 }
527
528 #endif /* HAVE_GNUTLS_PKCS12_SIMPLE_PARSE */