bumped version
[gnutls.git] / src / certtool-common.c
blobe2fdab9ace99c3da7ed562cbc1333ff4072ed5d0
1 /*
2 * Copyright (C) 2003-2012 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
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.
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.
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/>.
21 #include <config.h>
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>
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"
44 /* Gnulib portability files. */
45 #include <read-file.h>
47 unsigned char buffer[64 * 1024];
48 const int buffer_size = sizeof (buffer);
51 FILE *
52 safe_open_rw (const char *file, int privkey_op)
54 mode_t omask = 0;
55 FILE *fh;
57 if (privkey_op != 0)
59 omask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
62 fh = fopen (file, "wb");
64 if (privkey_op != 0)
66 umask (omask);
69 return fh;
72 gnutls_datum_t *
73 load_secret_key (int mand, common_info_st * info)
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;
81 fprintf (stderr, "Loading secret key...\n");
83 if (info->secret_key == NULL)
85 if (mand)
86 error (EXIT_FAILURE, 0, "missing --secret-key");
87 else
88 return NULL;
91 hex_key.data = (void *) info->secret_key;
92 hex_key.size = strlen (info->secret_key);
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));
98 key.data = (void*)raw_key;
99 key.size = raw_key_size;
101 return &key;
104 static gnutls_privkey_t _load_privkey(gnutls_datum_t *dat, common_info_st * info)
106 int ret;
107 gnutls_privkey_t key;
108 gnutls_x509_privkey_t xkey;
110 ret = gnutls_x509_privkey_init (&xkey);
111 if (ret < 0)
112 error (EXIT_FAILURE, 0, "x509_privkey_init: %s", gnutls_strerror (ret));
114 ret = gnutls_privkey_init (&key);
115 if (ret < 0)
116 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
118 if (info->pkcs8)
120 const char *pass = get_pass ();
121 ret =
122 gnutls_x509_privkey_import_pkcs8 (xkey, dat, info->incert_format,
123 pass, 0);
125 else
126 ret = gnutls_x509_privkey_import (xkey, dat, info->incert_format);
128 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
135 if (ret < 0)
136 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
137 info->privkey, gnutls_strerror (ret));
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));
144 return key;
147 #ifdef ENABLE_PKCS11
149 static gnutls_privkey_t _load_pkcs11_privkey(const char* url)
151 int ret;
152 gnutls_pkcs11_privkey_t p11key;
153 gnutls_privkey_t key;
155 ret = gnutls_privkey_init (&key);
156 if (ret < 0)
157 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
159 ret = gnutls_pkcs11_privkey_init (&p11key);
160 if (ret < 0)
161 error (EXIT_FAILURE, 0, "pkcs11_privkey_init: %s", gnutls_strerror (ret));
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));
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));
173 return key;
176 static gnutls_pubkey_t _load_pkcs11_pubkey(const char* url)
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;
184 ret = gnutls_pubkey_init (&pubkey);
185 if (ret < 0)
187 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
188 gnutls_strerror (ret));
189 exit (1);
192 ret = gnutls_pkcs11_obj_init (&obj);
193 if (ret < 0)
195 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
196 gnutls_strerror (ret));
197 exit (1);
200 ret = gnutls_pkcs11_obj_import_url (obj, url, obj_flags);
201 if (ret < 0)
203 fprintf (stderr, "Error in %s:%d: %s: %s\n", __func__, __LINE__,
204 gnutls_strerror (ret), url);
205 exit (1);
208 switch (gnutls_pkcs11_obj_get_type (obj))
210 case GNUTLS_PKCS11_OBJ_X509_CRT:
211 ret = gnutls_x509_crt_init (&xcrt);
212 if (ret < 0)
214 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
215 gnutls_strerror (ret));
216 exit (1);
219 ret = gnutls_x509_crt_import_pkcs11 (xcrt, obj);
220 if (ret < 0)
222 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
223 gnutls_strerror (ret));
224 exit (1);
227 ret = gnutls_pubkey_import_x509 (pubkey, xcrt, 0);
228 if (ret < 0)
230 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
231 gnutls_strerror (ret));
232 exit (1);
235 gnutls_x509_crt_deinit (xcrt);
236 break;
237 case GNUTLS_PKCS11_OBJ_PUBKEY:
239 ret = gnutls_pubkey_import_pkcs11 (pubkey, obj, 0);
240 if (ret < 0)
242 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
243 gnutls_strerror (ret));
244 exit (1);
247 break;
248 default:
250 fprintf(stderr, "Unsupported PKCS #11 object\n");
251 exit (1);
252 break;
256 gnutls_pkcs11_obj_deinit (obj);
257 return pubkey;
260 #endif /* ENABLE_PKCS11 */
262 /* Load the private key.
263 * @mand should be non zero if it is required to read a private key.
265 gnutls_privkey_t
266 load_private_key (int mand, common_info_st * info)
268 gnutls_privkey_t key;
269 gnutls_datum_t dat;
270 size_t size;
272 if (!info->privkey && !mand)
273 return NULL;
275 if (info->privkey == NULL)
276 error (EXIT_FAILURE, 0, "missing --load-privkey");
278 #ifdef ENABLE_PKCS11
279 if (strncmp(info->privkey, "pkcs11:", 7) == 0)
280 return _load_pkcs11_privkey(info->privkey);
281 #endif
283 dat.data = (void*)read_binary_file (info->privkey, &size);
284 dat.size = size;
286 if (!dat.data)
287 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
289 key = _load_privkey(&dat, info);
291 free (dat.data);
293 return key;
296 /* Load the private key.
297 * @mand should be non zero if it is required to read a private key.
299 gnutls_x509_privkey_t
300 load_x509_private_key (int mand, common_info_st * info)
302 gnutls_x509_privkey_t key;
303 int ret;
304 gnutls_datum_t dat;
305 size_t size;
307 if (!info->privkey && !mand)
308 return NULL;
310 if (info->privkey == NULL)
311 error (EXIT_FAILURE, 0, "missing --load-privkey");
313 ret = gnutls_x509_privkey_init (&key);
314 if (ret < 0)
315 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
317 dat.data = (void*)read_binary_file (info->privkey, &size);
318 dat.size = size;
320 if (!dat.data)
321 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
323 if (info->pkcs8)
325 const char *pass = get_pass ();
326 ret =
327 gnutls_x509_privkey_import_pkcs8 (key, &dat, info->incert_format,
328 pass, 0);
330 else
331 ret = gnutls_x509_privkey_import (key, &dat, info->incert_format);
333 free (dat.data);
335 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
342 if (ret < 0)
343 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
344 info->privkey, gnutls_strerror (ret));
346 return key;
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.
353 gnutls_x509_crt_t
354 load_cert (int mand, common_info_st * info)
356 gnutls_x509_crt_t *crt;
357 size_t size;
359 crt = load_cert_list (mand, &size, info);
361 return crt ? crt[0] : NULL;
364 #define MAX_CERTS 256
366 /* Loads a certificate list
368 gnutls_x509_crt_t *
369 load_cert_list (int mand, size_t * crt_size, common_info_st * info)
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;
379 *crt_size = 0;
380 fprintf (stderr, "Loading certificate list...\n");
382 if (info->cert == NULL)
384 if (mand)
385 error (EXIT_FAILURE, 0, "missing --load-certificate");
386 else
387 return NULL;
390 fd = fopen (info->cert, "r");
391 if (fd == NULL)
392 error (EXIT_FAILURE, errno, "%s", info->cert);
394 size = fread (buffer, 1, sizeof (buffer) - 1, fd);
395 buffer[size] = 0;
397 fclose (fd);
399 ptr = (void*)buffer;
400 ptr_size = size;
402 for (i = 0; i < MAX_CERTS; i++)
404 ret = gnutls_x509_crt_init (&crt[i]);
405 if (ret < 0)
406 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
408 dat.data = (void*)ptr;
409 dat.size = ptr_size;
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));
417 ptr = strstr (ptr, "---END");
418 if (ptr == NULL)
419 break;
420 ptr++;
422 ptr_size = size;
423 ptr_size -=
424 (unsigned int) ((unsigned char *) ptr - (unsigned char *) buffer);
426 if (ptr_size < 0)
427 break;
429 (*crt_size)++;
431 fprintf (stderr, "Loaded %d certificates.\n", (int) *crt_size);
433 return crt;
436 /* Load the Certificate Request.
438 gnutls_x509_crq_t
439 load_request (common_info_st * info)
441 gnutls_x509_crq_t crq;
442 int ret;
443 gnutls_datum_t dat;
444 size_t size;
446 if (!info->request)
447 return NULL;
449 ret = gnutls_x509_crq_init (&crq);
450 if (ret < 0)
451 error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret));
453 dat.data = (void*)read_binary_file (info->request, &size);
454 dat.size = size;
456 if (!dat.data)
457 error (EXIT_FAILURE, errno, "reading --load-request: %s", info->request);
459 ret = gnutls_x509_crq_import (crq, &dat, info->incert_format);
460 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
462 error (EXIT_FAILURE, 0,
463 "import error: could not find a valid PEM header");
466 free (dat.data);
467 if (ret < 0)
468 error (EXIT_FAILURE, 0, "importing --load-request: %s: %s",
469 info->request, gnutls_strerror (ret));
471 return crq;
474 /* Load the CA's private key.
476 gnutls_privkey_t
477 load_ca_private_key (common_info_st * info)
479 gnutls_privkey_t key;
480 gnutls_datum_t dat;
481 size_t size;
483 if (info->ca_privkey == NULL)
484 error (EXIT_FAILURE, 0, "missing --load-ca-privkey");
486 #ifdef ENABLE_PKCS11
487 if (strncmp(info->ca_privkey, "pkcs11:", 7) == 0)
488 return _load_pkcs11_privkey(info->ca_privkey);
489 #endif
491 dat.data = (void*)read_binary_file (info->ca_privkey, &size);
492 dat.size = size;
494 if (!dat.data)
495 error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s",
496 info->ca_privkey);
498 key = _load_privkey(&dat, info);
500 free (dat.data);
502 return key;
505 /* Loads the CA's certificate
507 gnutls_x509_crt_t
508 load_ca_cert (common_info_st * info)
510 gnutls_x509_crt_t crt;
511 int ret;
512 gnutls_datum_t dat;
513 size_t size;
515 if (info->ca == NULL)
516 error (EXIT_FAILURE, 0, "missing --load-ca-certificate");
518 ret = gnutls_x509_crt_init (&crt);
519 if (ret < 0)
520 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
522 dat.data = (void*)read_binary_file (info->ca, &size);
523 dat.size = size;
525 if (!dat.data)
526 error (EXIT_FAILURE, errno, "reading --load-ca-certificate: %s",
527 info->ca);
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));
535 return crt;
538 /* Load a public key.
539 * @mand should be non zero if it is required to read a public key.
541 gnutls_pubkey_t
542 load_pubkey (int mand, common_info_st * info)
544 gnutls_pubkey_t key;
545 int ret;
546 gnutls_datum_t dat;
547 size_t size;
549 if (!info->pubkey && !mand)
550 return NULL;
552 if (info->pubkey == NULL)
553 error (EXIT_FAILURE, 0, "missing --load-pubkey");
555 #ifdef ENABLE_PKCS11
556 if (strncmp(info->pubkey, "pkcs11:", 7) == 0)
557 return _load_pkcs11_pubkey(info->pubkey);
558 #endif
560 ret = gnutls_pubkey_init (&key);
561 if (ret < 0)
562 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
564 dat.data = (void*)read_binary_file (info->pubkey, &size);
565 dat.size = size;
567 if (!dat.data)
568 error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey);
570 ret = gnutls_pubkey_import (key, &dat, info->incert_format);
572 free (dat.data);
574 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
581 if (ret < 0)
582 error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
583 info->pubkey, gnutls_strerror (ret));
585 return key;
588 gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info)
590 gnutls_pubkey_t pubkey;
591 int ret;
593 ret = gnutls_pubkey_init(&pubkey);
594 if (ret < 0)
595 error (EXIT_FAILURE, 0, "gnutls_pubkey_init: %s",
596 gnutls_strerror (ret));
598 ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
599 if (ret < 0) /* could not get (e.g. on PKCS #11 */
601 gnutls_pubkey_deinit(pubkey);
602 return load_pubkey(mand, info);
605 return pubkey;
609 get_bits (gnutls_pk_algorithm_t key_type, int info_bits, const char* info_sec_param)
611 int bits;
613 if (info_bits != 0)
615 static int warned = 0;
617 if (warned == 0)
619 warned = 1;
620 fprintf (stderr,
621 "** Note: Please use the --sec-param instead of --bits\n");
623 bits = info_bits;
625 else
627 if (info_sec_param)
629 bits =
630 gnutls_sec_param_to_pk_bits (key_type,
631 str_to_sec_param (info_sec_param));
633 else
634 bits =
635 gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_NORMAL);
638 return bits;
641 gnutls_sec_param_t str_to_sec_param (const char *str)
643 if (strcasecmp (str, "low") == 0)
645 return GNUTLS_SEC_PARAM_LOW;
647 else if (strcasecmp (str, "normal") == 0)
649 return GNUTLS_SEC_PARAM_NORMAL;
651 else if (strcasecmp (str, "high") == 0)
653 return GNUTLS_SEC_PARAM_HIGH;
655 else if (strcasecmp (str, "ultra") == 0)
657 return GNUTLS_SEC_PARAM_ULTRA;
659 else
661 fprintf (stderr, "Unknown security parameter string: %s\n", str);
662 exit (1);