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/>.
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>
37 #include <sys/types.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);
52 safe_open_rw (const char *file, int privkey_op)
59 omask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
62 fh = fopen (file, "wb");
73 load_secret_key (int mand, common_info_st * info)
76 size_t raw_key_size = sizeof (raw_key);
77 static gnutls_datum_t key;
78 gnutls_datum_t hex_key;
81 fprintf (stderr, "Loading secret key...\n");
83 if (info->secret_key == NULL)
86 error (EXIT_FAILURE, 0, "missing --secret-key");
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);
96 error (EXIT_FAILURE, 0, "hex_decode: %s", gnutls_strerror (ret));
98 key.data = (void*)raw_key;
99 key.size = raw_key_size;
104 static gnutls_privkey_t _load_privkey(gnutls_datum_t *dat, common_info_st * info)
107 gnutls_privkey_t key;
108 gnutls_x509_privkey_t xkey;
110 ret = gnutls_x509_privkey_init (&xkey);
112 error (EXIT_FAILURE, 0, "x509_privkey_init: %s", gnutls_strerror (ret));
114 ret = gnutls_privkey_init (&key);
116 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
120 const char *pass = get_pass ();
122 gnutls_x509_privkey_import_pkcs8 (xkey, dat, info->incert_format,
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");
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);
141 error (EXIT_FAILURE, 0, "gnutls_privkey_import_x509: %s",
142 gnutls_strerror (ret));
149 static gnutls_privkey_t _load_pkcs11_privkey(const char* url)
152 gnutls_pkcs11_privkey_t p11key;
153 gnutls_privkey_t key;
155 ret = gnutls_privkey_init (&key);
157 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
159 ret = gnutls_pkcs11_privkey_init (&p11key);
161 error (EXIT_FAILURE, 0, "pkcs11_privkey_init: %s", gnutls_strerror (ret));
163 ret = gnutls_pkcs11_privkey_import_url(p11key, url, 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);
170 error (EXIT_FAILURE, 0, "gnutls_privkey_import_pkcs11: %s",
171 gnutls_strerror (ret));
176 static gnutls_pubkey_t _load_pkcs11_pubkey(const char* url)
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);
187 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
188 gnutls_strerror (ret));
192 ret = gnutls_pkcs11_obj_init (&obj);
195 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
196 gnutls_strerror (ret));
200 ret = gnutls_pkcs11_obj_import_url (obj, url, obj_flags);
203 fprintf (stderr, "Error in %s:%d: %s: %s\n", __func__, __LINE__,
204 gnutls_strerror (ret), url);
208 switch (gnutls_pkcs11_obj_get_type (obj))
210 case GNUTLS_PKCS11_OBJ_X509_CRT:
211 ret = gnutls_x509_crt_init (&xcrt);
214 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
215 gnutls_strerror (ret));
219 ret = gnutls_x509_crt_import_pkcs11 (xcrt, obj);
222 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
223 gnutls_strerror (ret));
227 ret = gnutls_pubkey_import_x509 (pubkey, xcrt, 0);
230 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
231 gnutls_strerror (ret));
235 gnutls_x509_crt_deinit (xcrt);
237 case GNUTLS_PKCS11_OBJ_PUBKEY:
239 ret = gnutls_pubkey_import_pkcs11 (pubkey, obj, 0);
242 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
243 gnutls_strerror (ret));
250 fprintf(stderr, "Unsupported PKCS #11 object\n");
256 gnutls_pkcs11_obj_deinit (obj);
260 #endif /* ENABLE_PKCS11 */
262 /* Load the private key.
263 * @mand should be non zero if it is required to read a private key.
266 load_private_key (int mand, common_info_st * info)
268 gnutls_privkey_t key;
272 if (!info->privkey && !mand)
275 if (info->privkey == NULL)
276 error (EXIT_FAILURE, 0, "missing --load-privkey");
279 if (strncmp(info->privkey, "pkcs11:", 7) == 0)
280 return _load_pkcs11_privkey(info->privkey);
283 dat.data = (void*)read_binary_file (info->privkey, &size);
287 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
289 key = _load_privkey(&dat, info);
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;
307 if (!info->privkey && !mand)
310 if (info->privkey == NULL)
311 error (EXIT_FAILURE, 0, "missing --load-privkey");
313 ret = gnutls_x509_privkey_init (&key);
315 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
317 dat.data = (void*)read_binary_file (info->privkey, &size);
321 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
325 const char *pass = get_pass ();
327 gnutls_x509_privkey_import_pkcs8 (key, &dat, info->incert_format,
331 ret = gnutls_x509_privkey_import (key, &dat, info->incert_format);
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");
343 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
344 info->privkey, gnutls_strerror (ret));
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.
354 load_cert (int mand, common_info_st * info)
356 gnutls_x509_crt_t *crt;
359 crt = load_cert_list (mand, &size, info);
361 return crt ? crt[0] : NULL;
364 #define MAX_CERTS 256
366 /* Loads a certificate list
369 load_cert_list (int mand, size_t * crt_size, common_info_st * info)
372 static gnutls_x509_crt_t crt[MAX_CERTS];
380 fprintf (stderr, "Loading certificate list...\n");
382 if (info->cert == NULL)
385 error (EXIT_FAILURE, 0, "missing --load-certificate");
390 fd = fopen (info->cert, "r");
392 error (EXIT_FAILURE, errno, "%s", info->cert);
394 size = fread (buffer, 1, sizeof (buffer) - 1, fd);
402 for (i = 0; i < MAX_CERTS; i++)
404 ret = gnutls_x509_crt_init (&crt[i]);
406 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
408 dat.data = (void*)ptr;
411 ret = gnutls_x509_crt_import (crt[i], &dat, info->incert_format);
412 if (ret < 0 && *crt_size > 0)
415 error (EXIT_FAILURE, 0, "crt_import: %s", gnutls_strerror (ret));
417 ptr = strstr (ptr, "---END");
424 (unsigned int) ((unsigned char *) ptr - (unsigned char *) buffer);
431 fprintf (stderr, "Loaded %d certificates.\n", (int) *crt_size);
436 /* Load the Certificate Request.
439 load_request (common_info_st * info)
441 gnutls_x509_crq_t crq;
449 ret = gnutls_x509_crq_init (&crq);
451 error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret));
453 dat.data = (void*)read_binary_file (info->request, &size);
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");
468 error (EXIT_FAILURE, 0, "importing --load-request: %s: %s",
469 info->request, gnutls_strerror (ret));
474 /* Load the CA's private key.
477 load_ca_private_key (common_info_st * info)
479 gnutls_privkey_t key;
483 if (info->ca_privkey == NULL)
484 error (EXIT_FAILURE, 0, "missing --load-ca-privkey");
487 if (strncmp(info->ca_privkey, "pkcs11:", 7) == 0)
488 return _load_pkcs11_privkey(info->ca_privkey);
491 dat.data = (void*)read_binary_file (info->ca_privkey, &size);
495 error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s",
498 key = _load_privkey(&dat, info);
505 /* Loads the CA's certificate
508 load_ca_cert (common_info_st * info)
510 gnutls_x509_crt_t crt;
515 if (info->ca == NULL)
516 error (EXIT_FAILURE, 0, "missing --load-ca-certificate");
518 ret = gnutls_x509_crt_init (&crt);
520 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
522 dat.data = (void*)read_binary_file (info->ca, &size);
526 error (EXIT_FAILURE, errno, "reading --load-ca-certificate: %s",
529 ret = gnutls_x509_crt_import (crt, &dat, info->incert_format);
532 error (EXIT_FAILURE, 0, "importing --load-ca-certificate: %s: %s",
533 info->ca, gnutls_strerror (ret));
538 /* Load a public key.
539 * @mand should be non zero if it is required to read a public key.
542 load_pubkey (int mand, common_info_st * info)
549 if (!info->pubkey && !mand)
552 if (info->pubkey == NULL)
553 error (EXIT_FAILURE, 0, "missing --load-pubkey");
556 if (strncmp(info->pubkey, "pkcs11:", 7) == 0)
557 return _load_pkcs11_pubkey(info->pubkey);
560 ret = gnutls_pubkey_init (&key);
562 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
564 dat.data = (void*)read_binary_file (info->pubkey, &size);
568 error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey);
570 ret = gnutls_pubkey_import (key, &dat, info->incert_format);
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");
582 error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
583 info->pubkey, gnutls_strerror (ret));
588 gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info)
590 gnutls_pubkey_t pubkey;
593 ret = gnutls_pubkey_init(&pubkey);
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);
609 get_bits (gnutls_pk_algorithm_t key_type, int info_bits, const char* info_sec_param)
615 static int warned = 0;
621 "** Note: Please use the --sec-param instead of --bits\n");
630 gnutls_sec_param_to_pk_bits (key_type,
631 str_to_sec_param (info_sec_param));
635 gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_NORMAL);
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;
661 fprintf (stderr, "Unknown security parameter string: %s\n", str);