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/>.
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>
39 #include <sys/types.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
);
54 safe_open_rw (const char *file
, int privkey_op
)
61 omask
= umask (S_IRGRP
| S_IWGRP
| S_IROTH
| S_IWOTH
);
64 fh
= fopen (file
, "wb");
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
;
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
= (char *) 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
));
101 key
.size
= raw_key_size
;
106 static gnutls_privkey_t
_load_privkey(gnutls_datum_t
*dat
, common_info_st
* info
)
109 gnutls_privkey_t key
;
110 gnutls_x509_privkey_t xkey
;
112 ret
= gnutls_x509_privkey_init (&xkey
);
114 error (EXIT_FAILURE
, 0, "x509_privkey_init: %s", gnutls_strerror (ret
));
116 ret
= gnutls_privkey_init (&key
);
118 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
122 const char *pass
= get_pass ();
124 gnutls_x509_privkey_import_pkcs8 (xkey
, dat
, info
->incert_format
,
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");
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
);
143 error (EXIT_FAILURE
, 0, "gnutls_privkey_import_x509: %s",
144 gnutls_strerror (ret
));
151 static gnutls_privkey_t
_load_pkcs11_privkey(const char* url
)
154 gnutls_pkcs11_privkey_t p11key
;
155 gnutls_privkey_t key
;
157 ret
= gnutls_privkey_init (&key
);
159 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
161 ret
= gnutls_pkcs11_privkey_init (&p11key
);
163 error (EXIT_FAILURE
, 0, "pkcs11_privkey_init: %s", gnutls_strerror (ret
));
165 ret
= gnutls_pkcs11_privkey_import_url(p11key
, url
, 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
);
172 error (EXIT_FAILURE
, 0, "gnutls_privkey_import_pkcs11: %s",
173 gnutls_strerror (ret
));
178 static gnutls_pubkey_t
_load_pkcs11_pubkey(const char* url
)
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
);
189 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
190 gnutls_strerror (ret
));
194 ret
= gnutls_pkcs11_obj_init (&obj
);
197 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
198 gnutls_strerror (ret
));
202 ret
= gnutls_pkcs11_obj_import_url (obj
, url
, obj_flags
);
205 fprintf (stderr
, "Error in %s:%d: %s: %s\n", __func__
, __LINE__
,
206 gnutls_strerror (ret
), url
);
210 switch (gnutls_pkcs11_obj_get_type (obj
))
212 case GNUTLS_PKCS11_OBJ_X509_CRT
:
213 ret
= gnutls_x509_crt_init (&xcrt
);
216 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
217 gnutls_strerror (ret
));
221 ret
= gnutls_x509_crt_import_pkcs11 (xcrt
, obj
);
224 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
225 gnutls_strerror (ret
));
229 ret
= gnutls_pubkey_import_x509 (pubkey
, xcrt
, 0);
232 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
233 gnutls_strerror (ret
));
237 gnutls_x509_crt_deinit (xcrt
);
239 case GNUTLS_PKCS11_OBJ_PUBKEY
:
241 ret
= gnutls_pubkey_import_pkcs11 (pubkey
, obj
, 0);
244 fprintf (stderr
, "Error in %s:%d: %s\n", __func__
, __LINE__
,
245 gnutls_strerror (ret
));
252 fprintf(stderr
, "Unsupported PKCS #11 object\n");
258 gnutls_pkcs11_obj_deinit (obj
);
262 #endif /* ENABLE_PKCS11 */
264 /* Load the private key.
265 * @mand should be non zero if it is required to read a private key.
268 load_private_key (int mand
, common_info_st
* info
)
270 gnutls_privkey_t key
;
274 if (!info
->privkey
&& !mand
)
277 if (info
->privkey
== NULL
)
278 error (EXIT_FAILURE
, 0, "missing --load-privkey");
281 if (strncmp(info
->privkey
, "pkcs11:", 7) == 0)
282 return _load_pkcs11_privkey(info
->privkey
);
285 dat
.data
= read_binary_file (info
->privkey
, &size
);
289 error (EXIT_FAILURE
, errno
, "reading --load-privkey: %s", info
->privkey
);
291 key
= _load_privkey(&dat
, info
);
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
;
309 if (!info
->privkey
&& !mand
)
312 if (info
->privkey
== NULL
)
313 error (EXIT_FAILURE
, 0, "missing --load-privkey");
315 ret
= gnutls_x509_privkey_init (&key
);
317 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
319 dat
.data
= read_binary_file (info
->privkey
, &size
);
323 error (EXIT_FAILURE
, errno
, "reading --load-privkey: %s", info
->privkey
);
327 const char *pass
= get_pass ();
329 gnutls_x509_privkey_import_pkcs8 (key
, &dat
, info
->incert_format
,
333 ret
= gnutls_x509_privkey_import (key
, &dat
, info
->incert_format
);
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");
345 error (EXIT_FAILURE
, 0, "importing --load-privkey: %s: %s",
346 info
->privkey
, gnutls_strerror (ret
));
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.
356 load_cert (int mand
, common_info_st
* info
)
358 gnutls_x509_crt_t
*crt
;
361 crt
= load_cert_list (mand
, &size
, info
);
363 return crt
? crt
[0] : NULL
;
366 #define MAX_CERTS 256
368 /* Loads a certificate list
371 load_cert_list (int mand
, size_t * crt_size
, common_info_st
* info
)
374 static gnutls_x509_crt_t crt
[MAX_CERTS
];
382 fprintf (stderr
, "Loading certificate list...\n");
384 if (info
->cert
== NULL
)
387 error (EXIT_FAILURE
, 0, "missing --load-certificate");
392 fd
= fopen (info
->cert
, "r");
394 error (EXIT_FAILURE
, errno
, "%s", info
->cert
);
396 size
= fread (buffer
, 1, sizeof (buffer
) - 1, fd
);
404 for (i
= 0; i
< MAX_CERTS
; i
++)
406 ret
= gnutls_x509_crt_init (&crt
[i
]);
408 error (EXIT_FAILURE
, 0, "crt_init: %s", gnutls_strerror (ret
));
413 ret
= gnutls_x509_crt_import (crt
[i
], &dat
, info
->incert_format
);
414 if (ret
< 0 && *crt_size
> 0)
417 error (EXIT_FAILURE
, 0, "crt_import: %s", gnutls_strerror (ret
));
419 ptr
= strstr (ptr
, "---END");
426 (unsigned int) ((unsigned char *) ptr
- (unsigned char *) buffer
);
433 fprintf (stderr
, "Loaded %d certificates.\n", (int) *crt_size
);
438 /* Load the Certificate Request.
441 load_request (common_info_st
* info
)
443 gnutls_x509_crq_t crq
;
451 ret
= gnutls_x509_crq_init (&crq
);
453 error (EXIT_FAILURE
, 0, "crq_init: %s", gnutls_strerror (ret
));
455 dat
.data
= read_binary_file (info
->request
, &size
);
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");
470 error (EXIT_FAILURE
, 0, "importing --load-request: %s: %s",
471 info
->request
, gnutls_strerror (ret
));
476 /* Load the CA's private key.
479 load_ca_private_key (common_info_st
* info
)
481 gnutls_privkey_t key
;
485 if (info
->ca_privkey
== NULL
)
486 error (EXIT_FAILURE
, 0, "missing --load-ca-privkey");
489 if (strncmp(info
->ca_privkey
, "pkcs11:", 7) == 0)
490 return _load_pkcs11_privkey(info
->ca_privkey
);
493 dat
.data
= read_binary_file (info
->ca_privkey
, &size
);
497 error (EXIT_FAILURE
, errno
, "reading --load-ca-privkey: %s",
500 key
= _load_privkey(&dat
, info
);
507 /* Loads the CA's certificate
510 load_ca_cert (common_info_st
* info
)
512 gnutls_x509_crt_t crt
;
517 if (info
->ca
== NULL
)
518 error (EXIT_FAILURE
, 0, "missing --load-ca-certificate");
520 ret
= gnutls_x509_crt_init (&crt
);
522 error (EXIT_FAILURE
, 0, "crt_init: %s", gnutls_strerror (ret
));
524 dat
.data
= read_binary_file (info
->ca
, &size
);
528 error (EXIT_FAILURE
, errno
, "reading --load-ca-certificate: %s",
531 ret
= gnutls_x509_crt_import (crt
, &dat
, info
->incert_format
);
534 error (EXIT_FAILURE
, 0, "importing --load-ca-certificate: %s: %s",
535 info
->ca
, gnutls_strerror (ret
));
540 /* Load a public key.
541 * @mand should be non zero if it is required to read a public key.
544 load_pubkey (int mand
, common_info_st
* info
)
551 if (!info
->pubkey
&& !mand
)
554 if (info
->pubkey
== NULL
)
555 error (EXIT_FAILURE
, 0, "missing --load-pubkey");
558 if (strncmp(info
->pubkey
, "pkcs11:", 7) == 0)
559 return _load_pkcs11_pubkey(info
->pubkey
);
562 ret
= gnutls_pubkey_init (&key
);
564 error (EXIT_FAILURE
, 0, "privkey_init: %s", gnutls_strerror (ret
));
566 dat
.data
= read_binary_file (info
->pubkey
, &size
);
570 error (EXIT_FAILURE
, errno
, "reading --load-pubkey: %s", info
->pubkey
);
572 ret
= gnutls_pubkey_import (key
, &dat
, info
->incert_format
);
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");
584 error (EXIT_FAILURE
, 0, "importing --load-pubkey: %s: %s",
585 info
->pubkey
, gnutls_strerror (ret
));
590 gnutls_pubkey_t
load_public_key_or_import(int mand
, gnutls_privkey_t privkey
, common_info_st
* info
)
592 gnutls_pubkey_t pubkey
;
595 ret
= gnutls_pubkey_init(&pubkey
);
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
);