blob: 5bf41ccd09e2d944e4e18b2395d41ee72d8c4309 [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <getopt.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36#include <openssl/conf.h>
37#include <openssl/engine.h>
38#include <openssl/err.h>
39#include <openssl/pem.h>
40#include <openssl/sha.h>
41#include <openssl/x509v3.h>
42
43#include "cert.h"
44#include "debug.h"
45#include "ext.h"
46#include "key.h"
47#include "platform_oid.h"
48#include "sha.h"
Juan Castilloe6d30e92015-06-12 11:27:59 +010049#include "tbbr/tbb_ext.h"
50#include "tbbr/tbb_cert.h"
51#include "tbbr/tbb_key.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010052
53/*
54 * Helper macros to simplify the code. This macro assigns the return value of
55 * the 'fn' function to 'v' and exits if the value is NULL.
56 */
57#define CHECK_NULL(v, fn) \
58 do { \
59 v = fn; \
60 if (v == NULL) { \
61 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
62 exit(1); \
63 } \
64 } while (0)
65
66/*
67 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
68 * NID is undefined.
69 */
70#define CHECK_OID(v, oid) \
71 do { \
72 v = OBJ_txt2nid(oid); \
73 if (v == NID_undef) { \
74 ERROR("Cannot find TBB extension %s\n", oid); \
75 exit(1); \
76 } \
77 } while (0)
78
79#define MAX_FILENAME_LEN 1024
80#define VAL_DAYS 7300
81#define ID_TO_BIT_MASK(id) (1 << id)
Juan Castillof9f39c32015-06-01 16:34:23 +010082#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
Juan Castillo11abdcd2014-10-21 11:30:42 +010083
84/* Files */
85enum {
86 /* Image file names (inputs) */
87 BL2_ID = 0,
88 BL30_ID,
89 BL31_ID,
90 BL32_ID,
91 BL33_ID,
92 /* Certificate file names (outputs) */
93 BL2_CERT_ID,
94 TRUSTED_KEY_CERT_ID,
95 BL30_KEY_CERT_ID,
96 BL30_CERT_ID,
97 BL31_KEY_CERT_ID,
98 BL31_CERT_ID,
99 BL32_KEY_CERT_ID,
100 BL32_CERT_ID,
101 BL33_KEY_CERT_ID,
102 BL33_CERT_ID,
103 /* Key file names (input/output) */
104 ROT_KEY_ID,
105 TRUSTED_WORLD_KEY_ID,
106 NON_TRUSTED_WORLD_KEY_ID,
107 BL30_KEY_ID,
108 BL31_KEY_ID,
109 BL32_KEY_ID,
110 BL33_KEY_ID,
111 NUM_OPTS
112};
113
114/* Global options */
Juan Castillof9f39c32015-06-01 16:34:23 +0100115static int key_alg;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100116static int new_keys;
117static int save_keys;
118static int print_cert;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100119
Juan Castillo11abdcd2014-10-21 11:30:42 +0100120/* Info messages created in the Makefile */
121extern const char build_msg[];
122extern const char platform_msg[];
123
124
125static char *strdup(const char *str)
126{
127 int n = strlen(str) + 1;
128 char *dup = malloc(n);
129 if (dup) {
130 strcpy(dup, str);
131 }
132 return dup;
133}
134
Juan Castillof9f39c32015-06-01 16:34:23 +0100135static const char *key_algs_str[] = {
136 [KEY_ALG_RSA] = "rsa",
Juan Castilloa2224ab2015-06-30 13:36:57 +0100137#ifndef OPENSSL_NO_EC
Juan Castillof9f39c32015-06-01 16:34:23 +0100138 [KEY_ALG_ECDSA] = "ecdsa"
Juan Castilloa2224ab2015-06-30 13:36:57 +0100139#endif /* OPENSSL_NO_EC */
Juan Castillof9f39c32015-06-01 16:34:23 +0100140};
141
Juan Castillo11abdcd2014-10-21 11:30:42 +0100142/* Command line options */
143static const struct option long_opt[] = {
144 /* Binary images */
145 {"bl2", required_argument, 0, BL2_ID},
146 {"bl30", required_argument, 0, BL30_ID},
147 {"bl31", required_argument, 0, BL31_ID},
148 {"bl32", required_argument, 0, BL32_ID},
149 {"bl33", required_argument, 0, BL33_ID},
150 /* Certificate files */
151 {"bl2-cert", required_argument, 0, BL2_CERT_ID},
152 {"trusted-key-cert", required_argument, 0, TRUSTED_KEY_CERT_ID},
153 {"bl30-key-cert", required_argument, 0, BL30_KEY_CERT_ID},
154 {"bl30-cert", required_argument, 0, BL30_CERT_ID},
155 {"bl31-key-cert", required_argument, 0, BL31_KEY_CERT_ID},
156 {"bl31-cert", required_argument, 0, BL31_CERT_ID},
157 {"bl32-key-cert", required_argument, 0, BL32_KEY_CERT_ID},
158 {"bl32-cert", required_argument, 0, BL32_CERT_ID},
159 {"bl33-key-cert", required_argument, 0, BL33_KEY_CERT_ID},
160 {"bl33-cert", required_argument, 0, BL33_CERT_ID},
161 /* Private key files */
162 {"rot-key", required_argument, 0, ROT_KEY_ID},
163 {"trusted-world-key", required_argument, 0, TRUSTED_WORLD_KEY_ID},
164 {"non-trusted-world-key", required_argument, 0, NON_TRUSTED_WORLD_KEY_ID},
165 {"bl30-key", required_argument, 0, BL30_KEY_ID},
166 {"bl31-key", required_argument, 0, BL31_KEY_ID},
167 {"bl32-key", required_argument, 0, BL32_KEY_ID},
168 {"bl33-key", required_argument, 0, BL33_KEY_ID},
169 /* Common options */
Juan Castillof9f39c32015-06-01 16:34:23 +0100170 {"key-alg", required_argument, 0, 'a'},
Juan Castillo11abdcd2014-10-21 11:30:42 +0100171 {"help", no_argument, 0, 'h'},
172 {"save-keys", no_argument, 0, 'k'},
173 {"new-chain", no_argument, 0, 'n'},
174 {"print-cert", no_argument, 0, 'p'},
175 {0, 0, 0, 0}
176};
177
178static void print_help(const char *cmd)
179{
180 int i = 0;
181 printf("\n\n");
182 printf("The certificate generation tool loads the binary images and\n"
183 "optionally the RSA keys, and outputs the key and content\n"
184 "certificates properly signed to implement the chain of trust.\n"
185 "If keys are provided, they must be in PEM format.\n"
186 "Certificates are generated in DER format.\n");
187 printf("\n");
188 printf("Usage:\n\n");
189 printf(" %s [-hknp] \\\n", cmd);
190 for (i = 0; i < NUM_OPTS; i++) {
191 printf(" --%s <file> \\\n", long_opt[i].name);
192 }
193 printf("\n");
Juan Castillof9f39c32015-06-01 16:34:23 +0100194 printf("-a Key algorithm: rsa (default), ecdsa\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100195 printf("-h Print help and exit\n");
196 printf("-k Save key pairs into files. Filenames must be provided\n");
197 printf("-n Generate new key pairs if no key files are provided\n");
198 printf("-p Print the certificates in the standard output\n");
199 printf("\n");
200
201 exit(0);
202}
203
Juan Castillof9f39c32015-06-01 16:34:23 +0100204static int get_key_alg(const char *key_alg_str)
205{
206 int i;
207
208 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
209 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
210 return i;
211 }
212 }
213
214 return -1;
215}
216
Juan Castillo11abdcd2014-10-21 11:30:42 +0100217static void check_cmd_params(void)
218{
Juan Castillo86958fd2015-07-08 12:11:38 +0100219 cert_t *cert;
220 ext_t *ext;
221 key_t *key;
222 int i, j;
223
Juan Castillof9f39c32015-06-01 16:34:23 +0100224 /* Only save new keys */
225 if (save_keys && !new_keys) {
226 ERROR("Only new keys can be saved to disk\n");
227 exit(1);
228 }
229
Juan Castillo86958fd2015-07-08 12:11:38 +0100230 /* Check that all required options have been specified in the
231 * command line */
232 for (i = 0; i < num_certs; i++) {
233 cert = &certs[i];
234 if (cert->fn == NULL) {
235 /* Certificate not requested. Skip to the next one */
236 continue;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100237 }
238
Juan Castillo86958fd2015-07-08 12:11:38 +0100239 /* Check that all parameters required to create this certificate
240 * have been specified in the command line */
241 for (j = 0; j < cert->num_ext; j++) {
242 ext = &extensions[cert->ext[j]];
243 switch (ext->type) {
244 case EXT_TYPE_PKEY:
245 /* Key filename must be specified */
246 key = &keys[ext->data.key];
247 if (!new_keys && key->fn == NULL) {
248 ERROR("Key '%s' required by '%s' not "
249 "specified\n", key->desc,
250 cert->cn);
251 exit(1);
252 }
253 break;
254 case EXT_TYPE_HASH:
255 /* Binary image must be specified */
256 if (ext->data.fn == NULL) {
257 ERROR("Image for '%s' not specified\n",
258 ext->ln);
259 exit(1);
260 }
261 break;
262 default:
263 ERROR("Unknown extension type in '%s'\n",
264 ext->ln);
265 exit(1);
266 break;
267 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100268 }
269 }
270}
271
272int main(int argc, char *argv[])
273{
274 STACK_OF(X509_EXTENSION) * sk = NULL;
Juan Castilloe6d30e92015-06-12 11:27:59 +0100275 X509_EXTENSION *cert_ext = NULL;
276 ext_t *ext = NULL;
277 cert_t *cert;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100278 FILE *file = NULL;
Juan Castilloe6d30e92015-06-12 11:27:59 +0100279 int i, j, ext_nid;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100280 int c, opt_idx = 0;
Juan Castillof9f39c32015-06-01 16:34:23 +0100281 unsigned int err_code;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100282 unsigned char md[SHA256_DIGEST_LENGTH];
Juan Castilloac402932015-03-05 14:30:00 +0000283 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100284
285 NOTICE("CoT Generation Tool: %s\n", build_msg);
286 NOTICE("Target platform: %s\n", platform_msg);
287
Juan Castillof9f39c32015-06-01 16:34:23 +0100288 /* Set default options */
289 key_alg = KEY_ALG_RSA;
290
Juan Castillo11abdcd2014-10-21 11:30:42 +0100291 while (1) {
292 /* getopt_long stores the option index here. */
Juan Castillof9f39c32015-06-01 16:34:23 +0100293 c = getopt_long(argc, argv, "ahknp", long_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100294
295 /* Detect the end of the options. */
296 if (c == -1) {
297 break;
298 }
299
300 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100301 case 'a':
302 key_alg = get_key_alg(optarg);
303 if (key_alg < 0) {
304 ERROR("Invalid key algorithm '%s'\n", optarg);
305 exit(1);
306 }
307 break;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100308 case 'h':
309 print_help(argv[0]);
310 break;
311 case 'k':
312 save_keys = 1;
313 break;
314 case 'n':
315 new_keys = 1;
316 break;
317 case 'p':
318 print_cert = 1;
319 break;
320 case BL2_ID:
Juan Castilloe6d30e92015-06-12 11:27:59 +0100321 extensions[BL2_HASH_EXT].data.fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100322 break;
323 case BL30_ID:
Juan Castilloe6d30e92015-06-12 11:27:59 +0100324 extensions[BL30_HASH_EXT].data.fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100325 break;
326 case BL31_ID:
Juan Castilloe6d30e92015-06-12 11:27:59 +0100327 extensions[BL31_HASH_EXT].data.fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100328 break;
329 case BL32_ID:
Juan Castilloe6d30e92015-06-12 11:27:59 +0100330 extensions[BL32_HASH_EXT].data.fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100331 break;
332 case BL33_ID:
Juan Castilloe6d30e92015-06-12 11:27:59 +0100333 extensions[BL33_HASH_EXT].data.fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100334 break;
335 case BL2_CERT_ID:
336 certs[BL2_CERT].fn = strdup(optarg);
337 break;
338 case TRUSTED_KEY_CERT_ID:
339 certs[TRUSTED_KEY_CERT].fn = strdup(optarg);
340 break;
341 case BL30_KEY_CERT_ID:
342 certs[BL30_KEY_CERT].fn = strdup(optarg);
343 break;
344 case BL30_CERT_ID:
345 certs[BL30_CERT].fn = strdup(optarg);
346 break;
347 case BL31_KEY_CERT_ID:
348 certs[BL31_KEY_CERT].fn = strdup(optarg);
349 break;
350 case BL31_CERT_ID:
351 certs[BL31_CERT].fn = strdup(optarg);
352 break;
353 case BL32_KEY_CERT_ID:
354 certs[BL32_KEY_CERT].fn = strdup(optarg);
355 break;
356 case BL32_CERT_ID:
357 certs[BL32_CERT].fn = strdup(optarg);
358 break;
359 case BL33_KEY_CERT_ID:
360 certs[BL33_KEY_CERT].fn = strdup(optarg);
361 break;
362 case BL33_CERT_ID:
363 certs[BL33_CERT].fn = strdup(optarg);
364 break;
365 case ROT_KEY_ID:
366 keys[ROT_KEY].fn = strdup(optarg);
367 break;
368 case TRUSTED_WORLD_KEY_ID:
369 keys[TRUSTED_WORLD_KEY].fn = strdup(optarg);
370 break;
371 case NON_TRUSTED_WORLD_KEY_ID:
372 keys[NON_TRUSTED_WORLD_KEY].fn = strdup(optarg);
373 break;
374 case BL30_KEY_ID:
375 keys[BL30_KEY].fn = strdup(optarg);
376 break;
377 case BL31_KEY_ID:
378 keys[BL31_KEY].fn = strdup(optarg);
379 break;
380 case BL32_KEY_ID:
381 keys[BL32_KEY].fn = strdup(optarg);
382 break;
383 case BL33_KEY_ID:
384 keys[BL33_KEY].fn = strdup(optarg);
385 break;
386 case '?':
387 default:
388 printf("%s\n", optarg);
389 exit(1);
390 }
391 }
392
Juan Castillo11abdcd2014-10-21 11:30:42 +0100393 /* Check command line arguments */
394 check_cmd_params();
395
396 /* Register the new types and OIDs for the extensions */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100397 if (ext_register(extensions) != 0) {
398 ERROR("Cannot register TBB extensions\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100399 exit(1);
400 }
401
Juan Castilloac402932015-03-05 14:30:00 +0000402 /* Indicate SHA256 as image hash algorithm in the certificate
403 * extension */
404 md_info = EVP_sha256();
405
Juan Castillo11abdcd2014-10-21 11:30:42 +0100406 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100407 for (i = 0 ; i < num_keys ; i++) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100408 /* First try to load the key from disk */
409 if (key_load(&keys[i], &err_code)) {
410 /* Key loaded successfully */
411 continue;
412 }
413
414 /* Key not loaded. Check the error code */
415 if (err_code == KEY_ERR_MALLOC) {
416 /* Cannot allocate memory. Abort. */
417 ERROR("Malloc error while loading '%s'\n", keys[i].fn);
418 exit(1);
419 } else if (err_code == KEY_ERR_LOAD) {
420 /* File exists, but it does not contain a valid private
421 * key. Abort. */
422 ERROR("Error loading '%s'\n", keys[i].fn);
423 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100424 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100425
426 /* File does not exist, could not be opened or no filename was
427 * given */
428 if (new_keys) {
429 /* Try to create a new key */
430 NOTICE("Creating new key for '%s'\n", keys[i].desc);
431 if (!key_create(&keys[i], key_alg)) {
432 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100433 exit(1);
434 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100435 } else {
436 if (err_code == KEY_ERR_OPEN) {
437 ERROR("Error opening '%s'\n", keys[i].fn);
438 } else {
439 ERROR("Key '%s' not specified\n", keys[i].desc);
440 }
441 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100442 }
443 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100444
Juan Castilloe6d30e92015-06-12 11:27:59 +0100445 /* Create the certificates */
446 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100447
Juan Castilloe6d30e92015-06-12 11:27:59 +0100448 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100449
Juan Castilloe6d30e92015-06-12 11:27:59 +0100450 /* Create a new stack of extensions. This stack will be used
451 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100452 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100453
Juan Castilloe6d30e92015-06-12 11:27:59 +0100454 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100455
Juan Castilloe6d30e92015-06-12 11:27:59 +0100456 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100457
Juan Castilloe6d30e92015-06-12 11:27:59 +0100458 /* Get OpenSSL internal ID for this extension */
459 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100460
Juan Castilloe6d30e92015-06-12 11:27:59 +0100461 /*
462 * Three types of extensions are currently supported:
463 * - EXT_TYPE_NVCOUNTER
464 * - EXT_TYPE_HASH
465 * - EXT_TYPE_PKEY
466 */
467 switch (ext->type) {
468 case EXT_TYPE_NVCOUNTER:
469 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
470 EXT_CRIT, ext->data.nvcounter));
471 break;
472 case EXT_TYPE_HASH:
473 if (ext->data.fn == NULL) {
474 break;
475 }
476 if (!sha_file(ext->data.fn, md)) {
477 ERROR("Cannot calculate hash of %s\n",
478 ext->data.fn);
479 exit(1);
480 }
481 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
482 EXT_CRIT, md_info, md,
483 SHA256_DIGEST_LENGTH));
484 break;
485 case EXT_TYPE_PKEY:
486 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
487 EXT_CRIT, keys[ext->data.key].key));
488 break;
489 default:
490 ERROR("Unknown extension type in %s\n",
491 cert->cn);
492 exit(1);
493 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100494
Juan Castilloe6d30e92015-06-12 11:27:59 +0100495 /* Push the extension into the stack */
496 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100497 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100498
Juan Castilloe6d30e92015-06-12 11:27:59 +0100499 /* Create certificate. Signed with ROT key */
Juan Castillo86958fd2015-07-08 12:11:38 +0100500 if (cert->fn && !cert_new(cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100501 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100502 exit(1);
503 }
504
505 sk_X509_EXTENSION_free(sk);
506 }
507
Juan Castillo11abdcd2014-10-21 11:30:42 +0100508
509 /* Print the certificates */
510 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100511 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100512 if (!certs[i].x) {
513 continue;
514 }
515 printf("\n\n=====================================\n\n");
516 X509_print_fp(stdout, certs[i].x);
517 }
518 }
519
520 /* Save created certificates to files */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100521 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100522 if (certs[i].x && certs[i].fn) {
523 file = fopen(certs[i].fn, "w");
524 if (file != NULL) {
525 i2d_X509_fp(file, certs[i].x);
526 fclose(file);
527 } else {
528 ERROR("Cannot create file %s\n", certs[i].fn);
529 }
530 }
531 }
532
533 /* Save keys */
534 if (save_keys) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100535 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100536 if (!key_store(&keys[i])) {
537 ERROR("Cannot save %s\n", keys[i].desc);
538 }
539 }
540 }
541
Juan Castillo11abdcd2014-10-21 11:30:42 +0100542#ifndef OPENSSL_NO_ENGINE
543 ENGINE_cleanup();
544#endif
545 CRYPTO_cleanup_all_ex_data();
546
547 return 0;
548}