Allow for bit strings that are not a multiple of 8.
[gnutls.git] / src / certtool-common.c
bloba24f035d18bbdb7e47eb7586a3882a1612936b9a
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 <common.h>
42 #include "certtool-common.h"
43 #include "certtool-cfg.h"
45 /* Gnulib portability files. */
46 #include <read-file.h>
48 unsigned char buffer[64 * 1024];
49 const int buffer_size = sizeof (buffer);
52 FILE *
53 safe_open_rw (const char *file, int privkey_op)
55 mode_t omask = 0;
56 FILE *fh;
58 if (privkey_op != 0)
60 omask = umask (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
63 fh = fopen (file, "wb");
65 if (privkey_op != 0)
67 umask (omask);
70 return fh;
73 gnutls_datum_t *
74 load_secret_key (int mand, common_info_st * info)
76 char raw_key[64];
77 size_t raw_key_size = sizeof (raw_key);
78 static gnutls_datum_t key;
79 gnutls_datum_t hex_key;
80 int ret;
82 if (info->verbose)
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 = (void *) 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 = (void*)raw_key;
101 key.size = raw_key_size;
103 return &key;
106 const char* get_password(common_info_st * cinfo, unsigned int *flags, int confirm)
108 if (cinfo->null_password)
110 if (flags) *flags |= GNUTLS_PKCS_NULL_PASSWORD;
111 return NULL;
113 else if (cinfo->password)
115 if (cinfo->password[0] == 0 && flags)
116 *flags |= GNUTLS_PKCS_PLAIN;
117 return cinfo->password;
119 else
121 if (confirm)
122 return get_confirmed_pass (true);
123 else
124 return get_pass ();
128 static gnutls_privkey_t _load_privkey(gnutls_datum_t *dat, common_info_st * info)
130 int ret;
131 gnutls_privkey_t key;
132 unsigned int flags = 0;
133 const char* pass;
135 ret = gnutls_privkey_init (&key);
136 if (ret < 0)
137 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
139 ret = gnutls_privkey_import_x509_raw (key, dat, info->incert_format, NULL, 0);
140 if (ret == GNUTLS_E_DECRYPTION_FAILED)
142 pass = get_password (info, &flags, 0);
143 ret = gnutls_privkey_import_x509_raw (key, dat, info->incert_format, pass, flags);
146 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
148 error (EXIT_FAILURE, 0,
149 "import error: could not find a valid PEM header; "
150 "check if your key is PKCS #12 encoded");
153 if (ret < 0)
154 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
155 info->privkey, gnutls_strerror (ret));
157 return key;
160 static gnutls_privkey_t _load_url_privkey(const char* url)
162 int ret;
163 gnutls_privkey_t key;
165 ret = gnutls_privkey_init (&key);
166 if (ret < 0)
167 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
169 ret = gnutls_privkey_import_url(key, url, 0);
170 if (ret < 0)
171 error (EXIT_FAILURE, 0, "importing key: %s: %s",
172 url, gnutls_strerror (ret));
174 return key;
177 static gnutls_pubkey_t _load_url_pubkey(const char* url)
179 int ret;
180 gnutls_pubkey_t pubkey;
181 unsigned int obj_flags = 0;
183 ret = gnutls_pubkey_init (&pubkey);
184 if (ret < 0)
186 fprintf (stderr, "Error in %s:%d: %s\n", __func__, __LINE__,
187 gnutls_strerror (ret));
188 exit (1);
191 ret = gnutls_pubkey_import_url (pubkey, url, obj_flags);
192 if (ret < 0)
194 fprintf (stderr, "Error in %s:%d: %s: %s\n", __func__, __LINE__,
195 gnutls_strerror (ret), url);
196 exit (1);
199 return pubkey;
202 /* Load the private key.
203 * @mand should be non zero if it is required to read a private key.
205 gnutls_privkey_t
206 load_private_key (int mand, common_info_st * info)
208 gnutls_privkey_t key;
209 gnutls_datum_t dat;
210 size_t size;
212 if (!info->privkey && !mand)
213 return NULL;
215 if (info->privkey == NULL)
216 error (EXIT_FAILURE, 0, "missing --load-privkey");
218 if (gnutls_url_is_supported(info->privkey) != 0)
219 return _load_url_privkey(info->privkey);
221 dat.data = (void*)read_binary_file (info->privkey, &size);
222 dat.size = size;
224 if (!dat.data)
225 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
227 key = _load_privkey(&dat, info);
229 free (dat.data);
231 return key;
234 /* Load the private key.
235 * @mand should be non zero if it is required to read a private key.
237 gnutls_x509_privkey_t
238 load_x509_private_key (int mand, common_info_st * info)
240 gnutls_x509_privkey_t key;
241 int ret;
242 gnutls_datum_t dat;
243 size_t size;
244 unsigned int flags = 0;
245 const char* pass;
247 if (!info->privkey && !mand)
248 return NULL;
250 if (info->privkey == NULL)
251 error (EXIT_FAILURE, 0, "missing --load-privkey");
253 ret = gnutls_x509_privkey_init (&key);
254 if (ret < 0)
255 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
257 dat.data = (void*)read_binary_file (info->privkey, &size);
258 dat.size = size;
260 if (!dat.data)
261 error (EXIT_FAILURE, errno, "reading --load-privkey: %s", info->privkey);
263 if (info->pkcs8)
265 pass = get_password (info, &flags, 0);
266 ret =
267 gnutls_x509_privkey_import_pkcs8 (key, &dat, info->incert_format,
268 pass, flags);
270 else
272 ret = gnutls_x509_privkey_import2 (key, &dat, info->incert_format, NULL, 0);
273 if (ret == GNUTLS_E_DECRYPTION_FAILED)
275 pass = get_password (info, &flags, 0);
276 ret = gnutls_x509_privkey_import2 (key, &dat, info->incert_format, pass, flags);
280 free (dat.data);
282 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
284 error (EXIT_FAILURE, 0,
285 "import error: could not find a valid PEM header; "
286 "check if your key is PKCS #12 encoded");
289 if (ret < 0)
290 error (EXIT_FAILURE, 0, "importing --load-privkey: %s: %s",
291 info->privkey, gnutls_strerror (ret));
293 return key;
297 /* Loads the certificate
298 * If mand is non zero then a certificate is mandatory. Otherwise
299 * null will be returned if the certificate loading fails.
301 gnutls_x509_crt_t
302 load_cert (int mand, common_info_st * info)
304 gnutls_x509_crt_t *crt;
305 size_t size;
307 crt = load_cert_list (mand, &size, info);
309 return crt ? crt[0] : NULL;
312 #define MAX_CERTS 256
314 /* Loads a certificate list
316 gnutls_x509_crt_t *
317 load_cert_list (int mand, size_t * crt_size, common_info_st * info)
319 FILE *fd;
320 static gnutls_x509_crt_t crt[MAX_CERTS];
321 char *ptr;
322 int ret, i;
323 gnutls_datum_t dat;
324 size_t size;
325 int ptr_size;
327 *crt_size = 0;
328 if (info->verbose)
329 fprintf (stderr, "Loading certificate list...\n");
331 if (info->cert == NULL)
333 if (mand)
334 error (EXIT_FAILURE, 0, "missing --load-certificate");
335 else
336 return NULL;
339 fd = fopen (info->cert, "r");
340 if (fd == NULL)
341 error (EXIT_FAILURE, errno, "%s", info->cert);
343 size = fread (buffer, 1, sizeof (buffer) - 1, fd);
344 buffer[size] = 0;
346 fclose (fd);
348 ptr = (void*)buffer;
349 ptr_size = size;
351 for (i = 0; i < MAX_CERTS; i++)
353 ret = gnutls_x509_crt_init (&crt[i]);
354 if (ret < 0)
355 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
357 dat.data = (void*)ptr;
358 dat.size = ptr_size;
360 ret = gnutls_x509_crt_import (crt[i], &dat, info->incert_format);
361 if (ret < 0 && *crt_size > 0)
362 break;
363 if (ret < 0)
364 error (EXIT_FAILURE, 0, "crt_import: %s", gnutls_strerror (ret));
366 ptr = strstr (ptr, "---END");
367 if (ptr == NULL)
368 break;
369 ptr++;
371 ptr_size = size;
372 ptr_size -=
373 (unsigned int) ((unsigned char *) ptr - (unsigned char *) buffer);
375 if (ptr_size < 0)
376 break;
378 (*crt_size)++;
380 if (info->verbose)
381 fprintf (stderr, "Loaded %d certificates.\n", (int) *crt_size);
383 return crt;
386 /* Load the Certificate Request.
388 gnutls_x509_crq_t
389 load_request (common_info_st * info)
391 gnutls_x509_crq_t crq;
392 int ret;
393 gnutls_datum_t dat;
394 size_t size;
396 if (!info->request)
397 return NULL;
399 ret = gnutls_x509_crq_init (&crq);
400 if (ret < 0)
401 error (EXIT_FAILURE, 0, "crq_init: %s", gnutls_strerror (ret));
403 dat.data = (void*)read_binary_file (info->request, &size);
404 dat.size = size;
406 if (!dat.data)
407 error (EXIT_FAILURE, errno, "reading --load-request: %s", info->request);
409 ret = gnutls_x509_crq_import (crq, &dat, info->incert_format);
410 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
412 error (EXIT_FAILURE, 0,
413 "import error: could not find a valid PEM header");
416 free (dat.data);
417 if (ret < 0)
418 error (EXIT_FAILURE, 0, "importing --load-request: %s: %s",
419 info->request, gnutls_strerror (ret));
421 return crq;
424 /* Load the CA's private key.
426 gnutls_privkey_t
427 load_ca_private_key (common_info_st * info)
429 gnutls_privkey_t key;
430 gnutls_datum_t dat;
431 size_t size;
433 if (info->ca_privkey == NULL)
434 error (EXIT_FAILURE, 0, "missing --load-ca-privkey");
436 if (gnutls_url_is_supported(info->ca_privkey) != 0)
437 return _load_url_privkey(info->ca_privkey);
439 dat.data = (void*)read_binary_file (info->ca_privkey, &size);
440 dat.size = size;
442 if (!dat.data)
443 error (EXIT_FAILURE, errno, "reading --load-ca-privkey: %s",
444 info->ca_privkey);
446 key = _load_privkey(&dat, info);
448 free (dat.data);
450 return key;
453 /* Loads the CA's certificate
455 gnutls_x509_crt_t
456 load_ca_cert (common_info_st * info)
458 gnutls_x509_crt_t crt;
459 int ret;
460 gnutls_datum_t dat;
461 size_t size;
463 if (info->ca == NULL)
464 error (EXIT_FAILURE, 0, "missing --load-ca-certificate");
466 ret = gnutls_x509_crt_init (&crt);
467 if (ret < 0)
468 error (EXIT_FAILURE, 0, "crt_init: %s", gnutls_strerror (ret));
470 dat.data = (void*)read_binary_file (info->ca, &size);
471 dat.size = size;
473 if (!dat.data)
474 error (EXIT_FAILURE, errno, "reading --load-ca-certificate: %s",
475 info->ca);
477 ret = gnutls_x509_crt_import (crt, &dat, info->incert_format);
478 free (dat.data);
479 if (ret < 0)
480 error (EXIT_FAILURE, 0, "importing --load-ca-certificate: %s: %s",
481 info->ca, gnutls_strerror (ret));
483 return crt;
486 /* Load a public key.
487 * @mand should be non zero if it is required to read a public key.
489 gnutls_pubkey_t
490 load_pubkey (int mand, common_info_st * info)
492 gnutls_pubkey_t key;
493 int ret;
494 gnutls_datum_t dat;
495 size_t size;
497 if (!info->pubkey && !mand)
498 return NULL;
500 if (info->pubkey == NULL)
501 error (EXIT_FAILURE, 0, "missing --load-pubkey");
503 if (gnutls_url_is_supported(info->pubkey) != 0)
504 return _load_url_pubkey(info->pubkey);
506 ret = gnutls_pubkey_init (&key);
507 if (ret < 0)
508 error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
510 dat.data = (void*)read_binary_file (info->pubkey, &size);
511 dat.size = size;
513 if (!dat.data)
514 error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info->pubkey);
516 ret = gnutls_pubkey_import (key, &dat, info->incert_format);
518 free (dat.data);
520 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
522 error (EXIT_FAILURE, 0,
523 "import error: could not find a valid PEM header; "
524 "check if your key has the PUBLIC KEY header");
527 if (ret < 0)
528 error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
529 info->pubkey, gnutls_strerror (ret));
531 return key;
534 gnutls_pubkey_t load_public_key_or_import(int mand, gnutls_privkey_t privkey, common_info_st * info)
536 gnutls_pubkey_t pubkey;
537 int ret;
539 ret = gnutls_pubkey_init(&pubkey);
540 if (ret < 0)
541 error (EXIT_FAILURE, 0, "gnutls_pubkey_init: %s",
542 gnutls_strerror (ret));
544 if (!privkey || (ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0)) < 0)
545 { /* could not get (e.g. on PKCS #11 */
546 gnutls_pubkey_deinit(pubkey);
547 return load_pubkey(mand, info);
550 return pubkey;
554 get_bits (gnutls_pk_algorithm_t key_type, int info_bits, const char* info_sec_param, int warn)
556 int bits;
558 if (info_bits != 0)
560 static int warned = 0;
562 if (warned == 0 && warn != 0)
564 warned = 1;
565 fprintf (stderr,
566 "** Note: Please use the --sec-param instead of --bits\n");
568 bits = info_bits;
570 else
572 if (info_sec_param)
574 bits =
575 gnutls_sec_param_to_pk_bits (key_type,
576 str_to_sec_param (info_sec_param));
578 else
579 bits =
580 gnutls_sec_param_to_pk_bits (key_type, GNUTLS_SEC_PARAM_NORMAL);
583 return bits;
586 gnutls_sec_param_t str_to_sec_param (const char *str)
588 if (strcasecmp (str, "low") == 0)
590 return GNUTLS_SEC_PARAM_LOW;
592 else if (strcasecmp (str, "legacy") == 0)
594 return GNUTLS_SEC_PARAM_LEGACY;
596 else if (strcasecmp (str, "normal") == 0)
598 return GNUTLS_SEC_PARAM_NORMAL;
600 else if (strcasecmp (str, "high") == 0)
602 return GNUTLS_SEC_PARAM_HIGH;
604 else if (strcasecmp (str, "ultra") == 0)
606 return GNUTLS_SEC_PARAM_ULTRA;
608 else
610 fprintf (stderr, "Unknown security parameter string: %s\n", str);
611 exit (1);
616 static void
617 print_hex_datum (FILE* outfile, gnutls_datum_t * dat)
619 unsigned int j;
620 #define SPACE "\t"
621 fprintf (outfile, "\n" SPACE);
622 for (j = 0; j < dat->size; j++)
624 fprintf (outfile, "%.2x:", (unsigned char) dat->data[j]);
625 if ((j + 1) % 15 == 0)
626 fprintf (outfile, "\n" SPACE);
628 fprintf (outfile, "\n");
631 void
632 print_dsa_pkey (FILE* outfile, gnutls_datum_t * x, gnutls_datum_t * y, gnutls_datum_t * p,
633 gnutls_datum_t * q, gnutls_datum_t * g)
635 if (x)
637 fprintf (outfile, "private key:");
638 print_hex_datum (outfile, x);
640 fprintf (outfile, "public key:");
641 print_hex_datum (outfile, y);
642 fprintf (outfile, "p:");
643 print_hex_datum (outfile, p);
644 fprintf (outfile, "q:");
645 print_hex_datum (outfile, q);
646 fprintf (outfile, "g:");
647 print_hex_datum (outfile, g);
650 void
651 print_ecc_pkey (FILE* outfile, gnutls_ecc_curve_t curve, gnutls_datum_t* k, gnutls_datum_t * x, gnutls_datum_t * y)
653 fprintf (outfile, "curve:\t%s\n", gnutls_ecc_curve_get_name(curve));
654 if (k)
656 fprintf (outfile, "private key:");
657 print_hex_datum (outfile, k);
659 fprintf (outfile, "x:");
660 print_hex_datum (outfile, x);
661 fprintf (outfile, "y:");
662 print_hex_datum (outfile, y);
665 void
666 print_rsa_pkey (FILE* outfile, gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d,
667 gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u,
668 gnutls_datum_t * exp1, gnutls_datum_t * exp2)
670 fprintf (outfile, "modulus:");
671 print_hex_datum (outfile, m);
672 fprintf (outfile, "public exponent:");
673 print_hex_datum (outfile, e);
674 if (d)
676 fprintf (outfile, "private exponent:");
677 print_hex_datum (outfile, d);
678 fprintf (outfile, "prime1:");
679 print_hex_datum (outfile, p);
680 fprintf (outfile, "prime2:");
681 print_hex_datum (outfile, q);
682 fprintf (outfile, "coefficient:");
683 print_hex_datum (outfile, u);
684 if (exp1 && exp2)
686 fprintf (outfile, "exp1:");
687 print_hex_datum (outfile, exp1);
688 fprintf (outfile, "exp2:");
689 print_hex_datum (outfile, exp2);
694 void _pubkey_info(FILE* outfile, gnutls_certificate_print_formats_t format, gnutls_pubkey_t pubkey)
696 gnutls_datum_t data;
697 int ret;
698 size_t size;
700 ret = gnutls_pubkey_print(pubkey, format, &data);
701 if (ret < 0)
702 error (EXIT_FAILURE, 0, "pubkey_print error: %s", gnutls_strerror (ret));
704 fprintf (outfile, "%s\n", data.data);
705 gnutls_free (data.data);
707 size = buffer_size;
708 ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
709 if (ret < 0)
710 error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
712 fprintf (outfile, "\n%s\n", buffer);