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