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>
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
);
53 safe_open_rw (const char *file
, int privkey_op
)
60 omask
= umask (S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
);
63 fh
= fopen (file
, "wb");
74 load_secret_key (int mand
, common_info_st
* info
)
77 size_t raw_key_size
= sizeof (raw_key
);
78 static gnutls_datum_t key
;
79 gnutls_datum_t hex_key
;
83 fprintf (stderr
, "Loading secret key...\n");
85 if (info
->secret_key
== NULL
)
88 error (EXIT_FAILURE
, 0, "missing --secret-key");
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
);
98 error (EXIT_FAILURE
, 0, "hex_decode: %s", gnutls_strerror (ret
));
100 key
.data
= (void*)raw_key
;
101 key
.size
= raw_key_size
;
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
;
113 else if (cinfo
->password
)
115 if (cinfo
->password
[0] == 0 && flags
)
116 *flags
|= GNUTLS_PKCS_PLAIN
;
117 return cinfo
->password
;
122 return get_confirmed_pass (true);
128 static gnutls_privkey_t
_load_privkey(gnutls_datum_t
*dat
, common_info_st
* info
)
131 gnutls_privkey_t key
;
132 unsigned int flags
= 0;
135 ret
= gnutls_privkey_init (&key
);
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");
154 error (EXIT_FAILURE
, 0, "importing --load-privkey: %s: %s",
155 info
->privkey
, gnutls_strerror (ret
));
160 static gnutls_privkey_t
_load_url_privkey(const char* url
)
163 gnutls_privkey_t key
;
165 ret
= gnutls_privkey_init (&key
);
167 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
169 ret
= gnutls_privkey_import_url(key
, url
, 0);
171 error (EXIT_FAILURE
, 0, "importing key: %s: %s",
172 url
, gnutls_strerror (ret
));
177 static gnutls_pubkey_t
_load_url_pubkey(const char* url
)
180 gnutls_pubkey_t pubkey
;
181 unsigned int obj_flags
= 0;
183 ret
= gnutls_pubkey_init (&pubkey
);
186 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
187 gnutls_strerror (ret
));
191 ret
= gnutls_pubkey_import_url (pubkey
, url
, obj_flags
);
194 fprintf (stderr
, "Error in %s:%d: %s: %s\n", __func__
, __LINE__
,
195 gnutls_strerror (ret
), url
);
202 /* Load the private key.
203 * @mand should be non zero if it is required to read a private key.
206 load_private_key (int mand
, common_info_st
* info
)
208 gnutls_privkey_t key
;
212 if (!info
->privkey
&& !mand
)
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
);
225 error (EXIT_FAILURE
, errno
, "reading --load-privkey: %s", info
->privkey
);
227 key
= _load_privkey(&dat
, info
);
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
;
244 unsigned int flags
= 0;
247 if (!info
->privkey
&& !mand
)
250 if (info
->privkey
== NULL
)
251 error (EXIT_FAILURE
, 0, "missing --load-privkey");
253 ret
= gnutls_x509_privkey_init (&key
);
255 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
257 dat
.data
= (void*)read_binary_file (info
->privkey
, &size
);
261 error (EXIT_FAILURE
, errno
, "reading --load-privkey: %s", info
->privkey
);
265 pass
= get_password (info
, &flags
, 0);
267 gnutls_x509_privkey_import_pkcs8 (key
, &dat
, info
->incert_format
,
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
);
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");
290 error (EXIT_FAILURE
, 0, "importing --load-privkey: %s: %s",
291 info
->privkey
, gnutls_strerror (ret
));
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.
302 load_cert (int mand
, common_info_st
* info
)
304 gnutls_x509_crt_t
*crt
;
307 crt
= load_cert_list (mand
, &size
, info
);
309 return crt
? crt
[0] : NULL
;
312 #define MAX_CERTS 256
314 /* Loads a certificate list
317 load_cert_list (int mand
, size_t * crt_size
, common_info_st
* info
)
320 static gnutls_x509_crt_t crt
[MAX_CERTS
];
329 fprintf (stderr
, "Loading certificate list...\n");
331 if (info
->cert
== NULL
)
334 error (EXIT_FAILURE
, 0, "missing --load-certificate");
339 fd
= fopen (info
->cert
, "r");
341 error (EXIT_FAILURE
, errno
, "%s", info
->cert
);
343 size
= fread (buffer
, 1, sizeof (buffer
) - 1, fd
);
351 for (i
= 0; i
< MAX_CERTS
; i
++)
353 ret
= gnutls_x509_crt_init (&crt
[i
]);
355 error (EXIT_FAILURE
, 0, "crt_init: %s", gnutls_strerror (ret
));
357 dat
.data
= (void*)ptr
;
360 ret
= gnutls_x509_crt_import (crt
[i
], &dat
, info
->incert_format
);
361 if (ret
< 0 && *crt_size
> 0)
364 error (EXIT_FAILURE
, 0, "crt_import: %s", gnutls_strerror (ret
));
366 ptr
= strstr (ptr
, "---END");
373 (unsigned int) ((unsigned char *) ptr
- (unsigned char *) buffer
);
381 fprintf (stderr
, "Loaded %d certificates.\n", (int) *crt_size
);
386 /* Load the Certificate Request.
389 load_request (common_info_st
* info
)
391 gnutls_x509_crq_t crq
;
399 ret
= gnutls_x509_crq_init (&crq
);
401 error (EXIT_FAILURE
, 0, "crq_init: %s", gnutls_strerror (ret
));
403 dat
.data
= (void*)read_binary_file (info
->request
, &size
);
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");
418 error (EXIT_FAILURE
, 0, "importing --load-request: %s: %s",
419 info
->request
, gnutls_strerror (ret
));
424 /* Load the CA's private key.
427 load_ca_private_key (common_info_st
* info
)
429 gnutls_privkey_t key
;
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
);
443 error (EXIT_FAILURE
, errno
, "reading --load-ca-privkey: %s",
446 key
= _load_privkey(&dat
, info
);
453 /* Loads the CA's certificate
456 load_ca_cert (common_info_st
* info
)
458 gnutls_x509_crt_t crt
;
463 if (info
->ca
== NULL
)
464 error (EXIT_FAILURE
, 0, "missing --load-ca-certificate");
466 ret
= gnutls_x509_crt_init (&crt
);
468 error (EXIT_FAILURE
, 0, "crt_init: %s", gnutls_strerror (ret
));
470 dat
.data
= (void*)read_binary_file (info
->ca
, &size
);
474 error (EXIT_FAILURE
, errno
, "reading --load-ca-certificate: %s",
477 ret
= gnutls_x509_crt_import (crt
, &dat
, info
->incert_format
);
480 error (EXIT_FAILURE
, 0, "importing --load-ca-certificate: %s: %s",
481 info
->ca
, gnutls_strerror (ret
));
486 /* Load a public key.
487 * @mand should be non zero if it is required to read a public key.
490 load_pubkey (int mand
, common_info_st
* info
)
497 if (!info
->pubkey
&& !mand
)
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
);
508 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
510 dat
.data
= (void*)read_binary_file (info
->pubkey
, &size
);
514 error (EXIT_FAILURE
, errno
, "reading --load-pubkey: %s", info
->pubkey
);
516 ret
= gnutls_pubkey_import (key
, &dat
, info
->incert_format
);
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");
528 error (EXIT_FAILURE
, 0, "importing --load-pubkey: %s: %s",
529 info
->pubkey
, gnutls_strerror (ret
));
534 gnutls_pubkey_t
load_public_key_or_import(int mand
, gnutls_privkey_t privkey
, common_info_st
* info
)
536 gnutls_pubkey_t pubkey
;
539 ret
= gnutls_pubkey_init(&pubkey
);
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
);
554 get_bits (gnutls_pk_algorithm_t key_type
, int info_bits
, const char* info_sec_param
, int warn
)
560 static int warned
= 0;
562 if (warned
== 0 && warn
!= 0)
566 "** Note: Please use the --sec-param instead of --bits\n");
575 gnutls_sec_param_to_pk_bits (key_type
,
576 str_to_sec_param (info_sec_param
));
580 gnutls_sec_param_to_pk_bits (key_type
, GNUTLS_SEC_PARAM_NORMAL
);
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
;
610 fprintf (stderr
, "Unknown security parameter string: %s\n", str
);
617 print_hex_datum (FILE* outfile
, gnutls_datum_t
* dat
)
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");
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
)
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
);
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
));
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
);
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
);
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
);
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
)
700 ret
= gnutls_pubkey_print(pubkey
, format
, &data
);
702 error (EXIT_FAILURE
, 0, "pubkey_print error: %s", gnutls_strerror (ret
));
704 fprintf (outfile
, "%s\n", data
.data
);
705 gnutls_free (data
.data
);
708 ret
= gnutls_pubkey_export (pubkey
, GNUTLS_X509_FMT_PEM
, buffer
, &size
);
710 error (EXIT_FAILURE
, 0, "export error: %s", gnutls_strerror (ret
));
712 fprintf (outfile
, "\n%s\n", buffer
);