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
);