If a callback fails try the other.
[gnutls.git] / src / certtool-common.c
blob1482d34b681910fecef3af040727febc2e78a0b7
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
3 * 2011 Free Software Foundation, Inc.
5 * This file is part of GnuTLS.
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.
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.
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/>.
22 #include <config.h>
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>
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"
46 /* Gnulib portability files. */
47 #include <read-file.h>
49 unsigned char buffer[64 * 1024];
50 const int buffer_size = sizeof (buffer);
53 FILE *
54 safe_open_rw (const char *file, int privkey_op)
56 mode_t omask = 0;
57 FILE *fh;
59 if (privkey_op != 0)
61 omask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
64 fh = fopen (file, "wb");
66 if (privkey_op != 0)
68 umask (omask);
71 return fh;
74 gnutls_datum_t *
75 load_secret_key (int mand, common_info_st * info)
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;
83 fprintf (stderr, "Loading secret key...\n");
85 if (info->secret_key == NULL)
87 if (mand)
88 error (EXIT_FAILURE, 0, "missing --secret-key");
89 else
90 return NULL;
93 hex_key.data = (char *) info->secret_key;
94 hex_key.size = strlen (info->secret_key);
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));
100 key.data = raw_key;
101 key.size = raw_key_size;
103 return &key;
106 static gnutls_privkey_t _load_privkey(gnutls_datum_t *dat, common_info_st * info)
108 int ret;
109 gnutls_privkey_t key;
110 gnutls_x509_privkey_t xkey;
112 ret = gnutls_x509_privkey_init (&xkey);
113 if (ret < 0)
114 error (EXIT_FAILURE, 0, "x509_privkey_init: %s", gnutls_strerror (ret));
116 ret = gnutls_privkey_init (&key);
117 if (ret < 0)
118 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
120 if (info->pkcs8)
122 const char *pass = get_pass ();
123 ret =
124 gnutls_x509_privkey_import_pkcs8 (xkey, dat, info->incert_format,
125 pass, 0);
127 else
128 ret = gnutls_x509_privkey_import (xkey, dat, info->incert_format);
130 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
137 if (ret < 0)
138 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
139 info->privkey, gnutls_strerror (ret));
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));
146 return key;
149 #ifdef ENABLE_PKCS11
151 static gnutls_privkey_t _load_pkcs11_privkey(const char* url)
153 int ret;
154 gnutls_pkcs11_privkey_t p11key;
155 gnutls_privkey_t key;
157 ret = gnutls_privkey_init (&key);
158 if (ret < 0)
159 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
161 ret = gnutls_pkcs11_privkey_init (&p11key);
162 if (ret < 0)
163 error (EXIT_FAILURE, 0, "pkcs11_privkey_init: %s", gnutls_strerror (ret));
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));
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));
175 return key;
178 static gnutls_pubkey_t _load_pkcs11_pubkey(const char* url)
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;
186 ret = gnutls_pubkey_init (&pubkey);
187 if (ret < 0)
189 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
190 gnutls_strerror (ret));
191 exit (1);
194 ret = gnutls_pkcs11_obj_init (&obj);
195 if (ret < 0)
197 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
198 gnutls_strerror (ret));
199 exit (1);
202 ret = gnutls_pkcs11_obj_import_url (obj, url, obj_flags);
203 if (ret < 0)
205 fprintf (stderr, "Error in %s:%d: %s: %s\n", __func__, __LINE__,
206 gnutls_strerror (ret), url);
207 exit (1);
210 switch (gnutls_pkcs11_obj_get_type (obj))
212 case GNUTLS_PKCS11_OBJ_X509_CRT:
213 ret = gnutls_x509_crt_init (&xcrt);
214 if (ret < 0)
216 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
217 gnutls_strerror (ret));
218 exit (1);
221 ret = gnutls_x509_crt_import_pkcs11 (xcrt, obj);
222 if (ret < 0)
224 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
225 gnutls_strerror (ret));
226 exit (1);
229 ret = gnutls_pubkey_import_x509 (pubkey, xcrt, 0);
230 if (ret < 0)
232 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
233 gnutls_strerror (ret));
234 exit (1);
237 gnutls_x509_crt_deinit (xcrt);
238 break;
239 case GNUTLS_PKCS11_OBJ_PUBKEY:
241 ret = gnutls_pubkey_import_pkcs11 (pubkey, obj, 0);
242 if (ret < 0)
244 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
245 gnutls_strerror (ret));
246 exit (1);
249 break;
250 default:
252 fprintf(stderr, "Unsupported PKCS #11 object\n");
253 exit (1);
254 break;
258 gnutls_pkcs11_obj_deinit (obj);
259 return pubkey;
262 #endif /* ENABLE_PKCS11 */
264 /* Load the private key.
265 * @mand should be non zero if it is required to read a private key.
267 gnutls_privkey_t
268 load_private_key (int mand, common_info_st * info)
270 gnutls_privkey_t key;
271 gnutls_datum_t dat;
272 size_t size;
274 if (!info->privkey && !mand)
275 return NULL;
277 if (info->privkey == NULL)
278 error (EXIT_FAILURE, 0, "missing --load-privkey");
280 #ifdef ENABLE_PKCS11
281 if (strncmp(info->privkey, "pkcs11:", 7) == 0)
282 return _load_pkcs11_privkey(info->privkey);
283 #endif
285 dat.data = read_binary_file (info->privkey, &size);
286 dat.size = size;
288 if (!dat.data)
289 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
291 key = _load_privkey(&dat, info);
293 free (dat.data);
295 return key;
298 /* Load the private key.
299 * @mand should be non zero if it is required to read a private key.
301 gnutls_x509_privkey_t
302 load_x509_private_key (int mand, common_info_st * info)
304 gnutls_x509_privkey_t key;
305 int ret;
306 gnutls_datum_t dat;
307 size_t size;
309 if (!info->privkey && !mand)
310 return NULL;
312 if (info->privkey == NULL)
313 error (EXIT_FAILURE, 0, "missing --load-privkey");
315 ret = gnutls_x509_privkey_init (&key);
316 if (ret < 0)
317 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
319 dat.data = read_binary_file (info->privkey, &size);
320 dat.size = size;
322 if (!dat.data)
323 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
325 if (info->pkcs8)
327 const char *pass = get_pass ();
328 ret =
329 gnutls_x509_privkey_import_pkcs8 (key, &dat, info->incert_format,
330 pass, 0);
332 else
333 ret = gnutls_x509_privkey_import (key, &dat, info->incert_format);
335 free (dat.data);
337 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
344 if (ret < 0)
345 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
346 info->privkey, gnutls_strerror (ret));
348 return key;
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.
355 gnutls_x509_crt_t
356 load_cert (int mand, common_info_st * info)
358 gnutls_x509_crt_t *crt;
359 size_t size;
361 crt = load_cert_list (mand, &size, info);
363 return crt ? crt[0] : NULL;
366 #define MAX_CERTS 256
368 /* Loads a certificate list
370 gnutls_x509_crt_t *
371 load_cert_list (int mand, size_t * crt_size, common_info_st * info)
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;
381 *crt_size = 0;
382 fprintf (stderr, "Loading certificate list...\n");
384 if (info->cert == NULL)
386 if (mand)
387 error (EXIT_FAILURE, 0, "missing --load-certificate");
388 else
389 return NULL;
392 fd = fopen (info->cert, "r");
393 if (fd == NULL)
394 error (EXIT_FAILURE, errno, "%s", info->cert);
396 size = fread (buffer, 1, sizeof (buffer) - 1, fd);
397 buffer[size] = 0;
399 fclose (fd);
401 ptr = buffer;
402 ptr_size = size;
404 for (i = 0; i < MAX_CERTS; i++)
406 ret = gnutls_x509_crt_init (&crt[i]);
407 if (ret < 0)
408 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
410 dat.data = ptr;
411 dat.size = ptr_size;
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));
419 ptr = strstr (ptr, "---END");
420 if (ptr == NULL)
421 break;
422 ptr++;
424 ptr_size = size;
425 ptr_size -=
426 (unsigned int) ((unsigned char *) ptr - (unsigned char *) buffer);
428 if (ptr_size < 0)
429 break;
431 (*crt_size)++;
433 fprintf (stderr, "Loaded %d certificates.\n", (int) *crt_size);
435 return crt;
438 /* Load the Certificate Request.
440 gnutls_x509_crq_t
441 load_request (common_info_st * info)
443 gnutls_x509_crq_t crq;
444 int ret;
445 gnutls_datum_t dat;
446 size_t size;
448 if (!info->request)
449 return NULL;
451 ret = gnutls_x509_crq_init (&crq);
452 if (ret < 0)
453 error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret));
455 dat.data = read_binary_file (info->request, &size);
456 dat.size = size;
458 if (!dat.data)
459 error (EXIT_FAILURE, errno, "reading --load-request: %s", info->request);
461 ret = gnutls_x509_crq_import (crq, &dat, info->incert_format);
462 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
464 error (EXIT_FAILURE, 0,
465 "import error: could not find a valid PEM header");
468 free (dat.data);
469 if (ret < 0)
470 error (EXIT_FAILURE, 0, "importing --load-request: %s: %s",
471 info->request, gnutls_strerror (ret));
473 return crq;
476 /* Load the CA's private key.
478 gnutls_privkey_t
479 load_ca_private_key (common_info_st * info)
481 gnutls_privkey_t key;
482 gnutls_datum_t dat;
483 size_t size;
485 if (info->ca_privkey == NULL)
486 error (EXIT_FAILURE, 0, "missing --load-ca-privkey");
488 #ifdef ENABLE_PKCS11
489 if (strncmp(info->ca_privkey, "pkcs11:", 7) == 0)
490 return _load_pkcs11_privkey(info->ca_privkey);
491 #endif
493 dat.data = read_binary_file (info->ca_privkey, &size);
494 dat.size = size;
496 if (!dat.data)
497 error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s",
498 info->ca_privkey);
500 key = _load_privkey(&dat, info);
502 free (dat.data);
504 return key;
507 /* Loads the CA's certificate
509 gnutls_x509_crt_t
510 load_ca_cert (common_info_st * info)
512 gnutls_x509_crt_t crt;
513 int ret;
514 gnutls_datum_t dat;
515 size_t size;
517 if (info->ca == NULL)
518 error (EXIT_FAILURE, 0, "missing --load-ca-certificate");
520 ret = gnutls_x509_crt_init (&crt);
521 if (ret < 0)
522 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
524 dat.data = read_binary_file (info->ca, &size);
525 dat.size = size;
527 if (!dat.data)
528 error (EXIT_FAILURE, errno, "reading --load-ca-certificate: %s",
529 info->ca);
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));
537 return crt;
540 /* Load a public key.
541 * @mand should be non zero if it is required to read a public key.
543 gnutls_pubkey_t
544 load_pubkey (int mand, common_info_st * info)
546 gnutls_pubkey_t key;
547 int ret;
548 gnutls_datum_t dat;
549 size_t size;
551 if (!info->pubkey && !mand)
552 return NULL;
554 if (info->pubkey == NULL)
555 error (EXIT_FAILURE, 0, "missing --load-pubkey");
557 #ifdef ENABLE_PKCS11
558 if (strncmp(info->pubkey, "pkcs11:", 7) == 0)
559 return _load_pkcs11_pubkey(info->pubkey);
560 #endif
562 ret = gnutls_pubkey_init (&key);
563 if (ret < 0)
564 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
566 dat.data = read_binary_file (info->pubkey, &size);
567 dat.size = size;
569 if (!dat.data)
570 error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey);
572 ret = gnutls_pubkey_import (key, &dat, info->incert_format);
574 free (dat.data);
576 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
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");
583 if (ret < 0)
584 error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
585 info->pubkey, gnutls_strerror (ret));
587 return key;
590 gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info)
592 gnutls_pubkey_t pubkey;
593 int ret;
595 ret = gnutls_pubkey_init(&pubkey);
596 if (ret < 0)
597 error (EXIT_FAILURE, 0, "gnutls_pubkey_init: %s",
598 gnutls_strerror (ret));
600 ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
601 if (ret < 0) /* could not get (e.g. on PKCS #11 */
603 gnutls_pubkey_deinit(pubkey);
604 return load_pubkey(mand, info);
607 return pubkey;