Tizen 2.0 Release
[external/libgnutls26.git] / src / certtool-common.c
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
3  *   2011 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuTLS.
6  *
7  * GnuTLS is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuTLS is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21
22 #include <config.h>
23
24 #include <gnutls/gnutls.h>
25 #include <gnutls/extra.h>
26 #include <gnutls/x509.h>
27 #include <gnutls/openpgp.h>
28 #include <gnutls/pkcs12.h>
29 #include <gnutls/pkcs11.h>
30 #include <gnutls/abstract.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <error.h>
43 #include "certtool-common.h"
44 #include "certtool-cfg.h"
45
46 /* Gnulib portability files. */
47 #include <read-file.h>
48
49 unsigned char buffer[64 * 1024];
50 const int buffer_size = sizeof (buffer);
51
52
53 FILE *
54 safe_open_rw (const char *file, int privkey_op)
55 {
56   mode_t omask = 0;
57   FILE *fh;
58
59   if (privkey_op != 0)
60     {
61       omask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
62     }
63
64   fh = fopen (file, "wb");
65
66   if (privkey_op != 0)
67     {
68       umask (omask);
69     }
70
71   return fh;
72 }
73
74 gnutls_datum_t *
75 load_secret_key (int mand, common_info_st * info)
76 {
77   unsigned char raw_key[64];
78   size_t raw_key_size = sizeof (raw_key);
79   static gnutls_datum_t key;
80   gnutls_datum_t hex_key;
81   int ret;
82
83   fprintf (stderr, "Loading secret key...\n");
84
85   if (info->secret_key == NULL)
86     {
87       if (mand)
88         error (EXIT_FAILURE, 0, "missing --secret-key");
89       else
90         return NULL;
91     }
92
93   hex_key.data = (char *) info->secret_key;
94   hex_key.size = strlen (info->secret_key);
95
96   ret = gnutls_hex_decode (&hex_key, raw_key, &raw_key_size);
97   if (ret < 0)
98     error (EXIT_FAILURE, 0, "hex_decode: %s", gnutls_strerror (ret));
99
100   key.data = raw_key;
101   key.size = raw_key_size;
102
103   return &key;
104 }
105
106 static gnutls_privkey_t _load_privkey(gnutls_datum_t *dat, common_info_st * info)
107 {
108 int ret;
109 gnutls_privkey_t key;
110 gnutls_x509_privkey_t xkey;
111
112   ret = gnutls_x509_privkey_init (&xkey);
113   if (ret < 0)
114     error (EXIT_FAILURE, 0, "x509_privkey_init: %s", gnutls_strerror (ret));
115
116   ret = gnutls_privkey_init (&key);
117   if (ret < 0)
118     error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
119
120   if (info->pkcs8)
121     {
122       const char *pass = get_pass ();
123       ret =
124         gnutls_x509_privkey_import_pkcs8 (xkey, dat, info->incert_format,
125                                           pass, 0);
126     }
127   else
128     ret = gnutls_x509_privkey_import (xkey, dat, info->incert_format);
129
130   if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
131     {
132       error (EXIT_FAILURE, 0,
133              "import error: could not find a valid PEM header; "
134              "check if your key is PKCS #8 or PKCS #12 encoded");
135     }
136
137   if (ret < 0)
138     error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
139            info->privkey, gnutls_strerror (ret));
140
141   ret = gnutls_privkey_import_x509(key, xkey, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
142   if (ret < 0)
143     error (EXIT_FAILURE, 0, "gnutls_privkey_import_x509: %s",
144            gnutls_strerror (ret));
145   
146   return key;
147 }
148
149 #ifdef ENABLE_PKCS11
150
151 static gnutls_privkey_t _load_pkcs11_privkey(const char* url)
152 {
153 int ret;
154 gnutls_pkcs11_privkey_t p11key;
155 gnutls_privkey_t key;
156
157   ret = gnutls_privkey_init (&key);
158   if (ret < 0)
159     error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
160
161   ret = gnutls_pkcs11_privkey_init (&p11key);
162   if (ret < 0)
163     error (EXIT_FAILURE, 0, "pkcs11_privkey_init: %s", gnutls_strerror (ret));
164
165   ret = gnutls_pkcs11_privkey_import_url(p11key, url, 0);
166   if (ret < 0)
167     error (EXIT_FAILURE, 0, "importing PKCS #11 key: %s: %s",
168            url, gnutls_strerror (ret));
169
170   ret = gnutls_privkey_import_pkcs11(key, p11key, GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
171   if (ret < 0)
172     error (EXIT_FAILURE, 0, "gnutls_privkey_import_pkcs11: %s",
173            gnutls_strerror (ret));
174   
175   return key;
176 }
177
178 static gnutls_pubkey_t _load_pkcs11_pubkey(const char* url)
179 {
180 int ret;
181 gnutls_pkcs11_obj_t obj;
182 gnutls_x509_crt_t xcrt;
183 gnutls_pubkey_t pubkey;
184 unsigned int obj_flags = 0;
185
186   ret = gnutls_pubkey_init (&pubkey);
187   if (ret < 0)
188     {
189       fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
190                gnutls_strerror (ret));
191       exit (1);
192     }
193
194   ret = gnutls_pkcs11_obj_init (&obj);
195   if (ret < 0)
196     {
197       fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
198                gnutls_strerror (ret));
199       exit (1);
200     }
201
202   ret = gnutls_pkcs11_obj_import_url (obj, url, obj_flags);
203   if (ret < 0)
204     {
205       fprintf (stderr, "Error in %s:%d: %s: %s\n", __func__, __LINE__,
206                gnutls_strerror (ret), url);
207       exit (1);
208     }
209
210   switch (gnutls_pkcs11_obj_get_type (obj))
211     {
212     case GNUTLS_PKCS11_OBJ_X509_CRT:
213       ret = gnutls_x509_crt_init (&xcrt);
214       if (ret < 0)
215         {
216           fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
217                    gnutls_strerror (ret));
218           exit (1);
219         }
220
221       ret = gnutls_x509_crt_import_pkcs11 (xcrt, obj);
222       if (ret < 0)
223         {
224           fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
225                    gnutls_strerror (ret));
226           exit (1);
227         }
228
229       ret = gnutls_pubkey_import_x509 (pubkey, xcrt, 0);
230       if (ret < 0)
231         {
232           fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
233                    gnutls_strerror (ret));
234           exit (1);
235         }
236
237       gnutls_x509_crt_deinit (xcrt);
238       break;
239     case GNUTLS_PKCS11_OBJ_PUBKEY:
240
241       ret = gnutls_pubkey_import_pkcs11 (pubkey, obj, 0);
242       if (ret < 0)
243         {
244           fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
245                    gnutls_strerror (ret));
246           exit (1);
247         }
248
249       break;
250     default:
251       {
252         fprintf(stderr, "Unsupported PKCS #11 object\n");
253         exit (1);
254         break;
255       }
256     }
257   
258   gnutls_pkcs11_obj_deinit (obj);
259   return pubkey;
260 }
261
262 #endif /* ENABLE_PKCS11 */
263
264 /* Load the private key.
265  * @mand should be non zero if it is required to read a private key.
266  */
267 gnutls_privkey_t
268 load_private_key (int mand, common_info_st * info)
269 {
270   gnutls_privkey_t key;
271   gnutls_datum_t dat;
272   size_t size;
273
274   if (!info->privkey && !mand)
275     return NULL;
276
277   if (info->privkey == NULL)
278     error (EXIT_FAILURE, 0, "missing --load-privkey");
279
280 #ifdef ENABLE_PKCS11
281   if (strncmp(info->privkey, "pkcs11:", 7) == 0)
282     return _load_pkcs11_privkey(info->privkey);
283 #endif
284
285   dat.data = read_binary_file (info->privkey, &size);
286   dat.size = size;
287
288   if (!dat.data)
289     error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
290
291   key = _load_privkey(&dat, info);
292
293   free (dat.data);
294
295   return key;
296 }
297
298 /* Load the private key.
299  * @mand should be non zero if it is required to read a private key.
300  */
301 gnutls_x509_privkey_t
302 load_x509_private_key (int mand, common_info_st * info)
303 {
304   gnutls_x509_privkey_t key;
305   int ret;
306   gnutls_datum_t dat;
307   size_t size;
308
309   if (!info->privkey && !mand)
310     return NULL;
311
312   if (info->privkey == NULL)
313     error (EXIT_FAILURE, 0, "missing --load-privkey");
314
315   ret = gnutls_x509_privkey_init (&key);
316   if (ret < 0)
317     error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
318
319   dat.data = read_binary_file (info->privkey, &size);
320   dat.size = size;
321
322   if (!dat.data)
323     error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
324
325   if (info->pkcs8)
326     {
327       const char *pass = get_pass ();
328       ret =
329         gnutls_x509_privkey_import_pkcs8 (key, &dat, info->incert_format,
330                                           pass, 0);
331     }
332   else
333     ret = gnutls_x509_privkey_import (key, &dat, info->incert_format);
334
335   free (dat.data);
336
337   if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
338     {
339       error (EXIT_FAILURE, 0,
340              "import error: could not find a valid PEM header; "
341              "check if your key is PKCS #8 or PKCS #12 encoded");
342     }
343
344   if (ret < 0)
345     error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
346            info->privkey, gnutls_strerror (ret));
347
348   return key;
349 }
350
351 /* Loads the certificate
352  * If mand is non zero then a certificate is mandatory. Otherwise
353  * null will be returned if the certificate loading fails.
354  */
355 gnutls_x509_crt_t
356 load_cert (int mand, common_info_st * info)
357 {
358   gnutls_x509_crt_t *crt;
359   size_t size;
360
361   crt = load_cert_list (mand, &size, info);
362
363   return crt ? crt[0] : NULL;
364 }
365
366 #define MAX_CERTS 256
367
368 /* Loads a certificate list
369  */
370 gnutls_x509_crt_t *
371 load_cert_list (int mand, size_t * crt_size, common_info_st * info)
372 {
373   FILE *fd;
374   static gnutls_x509_crt_t crt[MAX_CERTS];
375   char *ptr;
376   int ret, i;
377   gnutls_datum_t dat;
378   size_t size;
379   int ptr_size;
380
381   *crt_size = 0;
382   fprintf (stderr, "Loading certificate list...\n");
383
384   if (info->cert == NULL)
385     {
386       if (mand)
387         error (EXIT_FAILURE, 0, "missing --load-certificate");
388       else
389         return NULL;
390     }
391
392   fd = fopen (info->cert, "r");
393   if (fd == NULL)
394     error (EXIT_FAILURE, errno, "%s", info->cert);
395
396   size = fread (buffer, 1, sizeof (buffer) - 1, fd);
397   buffer[size] = 0;
398
399   fclose (fd);
400
401   ptr = buffer;
402   ptr_size = size;
403
404   for (i = 0; i < MAX_CERTS; i++)
405     {
406       ret = gnutls_x509_crt_init (&crt[i]);
407       if (ret < 0)
408         error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
409
410       dat.data = ptr;
411       dat.size = ptr_size;
412
413       ret = gnutls_x509_crt_import (crt[i], &dat, info->incert_format);
414       if (ret < 0 && *crt_size > 0)
415         break;
416       if (ret < 0)
417         error (EXIT_FAILURE, 0, "crt_import: %s", gnutls_strerror (ret));
418
419       ptr = strstr (ptr, "---END");
420       if (ptr == NULL)
421         break;
422       ptr++;
423
424       ptr_size = size;
425       ptr_size -=
426         (unsigned int) ((unsigned char *) ptr - (unsigned char *) buffer);
427
428       if (ptr_size < 0)
429         break;
430
431       (*crt_size)++;
432     }
433   fprintf (stderr, "Loaded %d certificates.\n", (int) *crt_size);
434
435   return crt;
436 }
437
438 /* Load the Certificate Request.
439  */
440 gnutls_x509_crq_t
441 load_request (common_info_st * info)
442 {
443   gnutls_x509_crq_t crq;
444   int ret;
445   gnutls_datum_t dat;
446   size_t size;
447
448   if (!info->request)
449     return NULL;
450
451   ret = gnutls_x509_crq_init (&crq);
452   if (ret < 0)
453     error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret));
454
455   dat.data = read_binary_file (info->request, &size);
456   dat.size = size;
457
458   if (!dat.data)
459     error (EXIT_FAILURE, errno, "reading --load-request: %s", info->request);
460
461   ret = gnutls_x509_crq_import (crq, &dat, info->incert_format);
462   if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
463     {
464       error (EXIT_FAILURE, 0,
465              "import error: could not find a valid PEM header");
466     }
467
468   free (dat.data);
469   if (ret < 0)
470     error (EXIT_FAILURE, 0, "importing --load-request: %s: %s",
471            info->request, gnutls_strerror (ret));
472
473   return crq;
474 }
475
476 /* Load the CA's private key.
477  */
478 gnutls_privkey_t
479 load_ca_private_key (common_info_st * info)
480 {
481   gnutls_privkey_t key;
482   gnutls_datum_t dat;
483   size_t size;
484
485   if (info->ca_privkey == NULL)
486     error (EXIT_FAILURE, 0, "missing --load-ca-privkey");
487
488 #ifdef ENABLE_PKCS11
489   if (strncmp(info->ca_privkey, "pkcs11:", 7) == 0)
490     return _load_pkcs11_privkey(info->ca_privkey);
491 #endif
492
493   dat.data = read_binary_file (info->ca_privkey, &size);
494   dat.size = size;
495
496   if (!dat.data)
497     error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s",
498            info->ca_privkey);
499
500   key = _load_privkey(&dat, info);
501
502   free (dat.data);
503
504   return key;
505 }
506
507 /* Loads the CA's certificate
508  */
509 gnutls_x509_crt_t
510 load_ca_cert (common_info_st * info)
511 {
512   gnutls_x509_crt_t crt;
513   int ret;
514   gnutls_datum_t dat;
515   size_t size;
516
517   if (info->ca == NULL)
518     error (EXIT_FAILURE, 0, "missing --load-ca-certificate");
519
520   ret = gnutls_x509_crt_init (&crt);
521   if (ret < 0)
522     error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
523
524   dat.data = read_binary_file (info->ca, &size);
525   dat.size = size;
526
527   if (!dat.data)
528     error (EXIT_FAILURE, errno, "reading --load-ca-certificate: %s",
529            info->ca);
530
531   ret = gnutls_x509_crt_import (crt, &dat, info->incert_format);
532   free (dat.data);
533   if (ret < 0)
534     error (EXIT_FAILURE, 0, "importing --load-ca-certificate: %s: %s",
535            info->ca, gnutls_strerror (ret));
536
537   return crt;
538 }
539
540 /* Load a public key.
541  * @mand should be non zero if it is required to read a public key.
542  */
543 gnutls_pubkey_t
544 load_pubkey (int mand, common_info_st * info)
545 {
546   gnutls_pubkey_t key;
547   int ret;
548   gnutls_datum_t dat;
549   size_t size;
550
551   if (!info->pubkey && !mand)
552     return NULL;
553
554   if (info->pubkey == NULL)
555     error (EXIT_FAILURE, 0, "missing --load-pubkey");
556
557 #ifdef ENABLE_PKCS11
558   if (strncmp(info->pubkey, "pkcs11:", 7) == 0)
559     return _load_pkcs11_pubkey(info->pubkey);
560 #endif
561
562   ret = gnutls_pubkey_init (&key);
563   if (ret < 0)
564     error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
565
566   dat.data = read_binary_file (info->pubkey, &size);
567   dat.size = size;
568
569   if (!dat.data)
570     error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey);
571
572   ret = gnutls_pubkey_import (key, &dat, info->incert_format);
573
574   free (dat.data);
575
576   if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
577     {
578       error (EXIT_FAILURE, 0,
579              "import error: could not find a valid PEM header; "
580              "check if your key has the PUBLIC KEY header");
581     }
582
583   if (ret < 0)
584     error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
585            info->pubkey, gnutls_strerror (ret));
586
587   return key;
588 }
589
590 gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info)
591 {
592 gnutls_pubkey_t pubkey;
593 int ret;
594
595   ret = gnutls_pubkey_init(&pubkey);
596   if (ret < 0)
597     error (EXIT_FAILURE, 0, "gnutls_pubkey_init: %s",
598            gnutls_strerror (ret));
599
600   ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
601   if (ret < 0) /* could not get (e.g. on PKCS #11 */
602     {
603       gnutls_pubkey_deinit(pubkey);
604       return load_pubkey(mand, info);
605     }
606
607   return pubkey;
608 }
609