blob: 14610ed11212f10b4f982429951c5f0fc02216aa [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
Juan Pablo Conde3539c742022-10-25 19:41:02 -04002 * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
Juan Castillo11abdcd2014-10-21 11:30:42 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Juan Castillo11abdcd2014-10-21 11:30:42 +01005 */
6
Juan Castillo212f7382015-12-15 16:37:57 +00007#include <assert.h>
8#include <ctype.h>
Juan Castillo11abdcd2014-10-21 11:30:42 +01009#include <getopt.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
Justin Chadwellfebe86c2019-07-29 17:13:45 +010013#include <stdbool.h>
Juan Castillo11abdcd2014-10-21 11:30:42 +010014
15#include <openssl/conf.h>
16#include <openssl/engine.h>
17#include <openssl/err.h>
18#include <openssl/pem.h>
19#include <openssl/sha.h>
20#include <openssl/x509v3.h>
21
22#include "cert.h"
Juan Castillo1218dd52015-07-03 16:23:16 +010023#include "cmd_opt.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010024#include "debug.h"
25#include "ext.h"
26#include "key.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010027#include "sha.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010028
29/*
30 * Helper macros to simplify the code. This macro assigns the return value of
31 * the 'fn' function to 'v' and exits if the value is NULL.
32 */
33#define CHECK_NULL(v, fn) \
34 do { \
35 v = fn; \
36 if (v == NULL) { \
37 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
38 exit(1); \
39 } \
40 } while (0)
41
42/*
43 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
44 * NID is undefined.
45 */
46#define CHECK_OID(v, oid) \
47 do { \
48 v = OBJ_txt2nid(oid); \
49 if (v == NID_undef) { \
Sandrine Bailleux0d11b482020-01-15 11:01:25 +010050 ERROR("Cannot find extension %s\n", oid); \
Juan Castillo11abdcd2014-10-21 11:30:42 +010051 exit(1); \
52 } \
53 } while (0)
54
55#define MAX_FILENAME_LEN 1024
56#define VAL_DAYS 7300
57#define ID_TO_BIT_MASK(id) (1 << id)
Juan Castillof9f39c32015-06-01 16:34:23 +010058#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
Juan Castillo212f7382015-12-15 16:37:57 +000059#define HELP_OPT_MAX_LEN 128
Juan Castillo11abdcd2014-10-21 11:30:42 +010060
61/* Global options */
Juan Castillof9f39c32015-06-01 16:34:23 +010062static int key_alg;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080063static int hash_alg;
Justin Chadwellfebe86c2019-07-29 17:13:45 +010064static int key_size;
Juan Castillo11abdcd2014-10-21 11:30:42 +010065static int new_keys;
66static int save_keys;
67static int print_cert;
Juan Castillo11abdcd2014-10-21 11:30:42 +010068
Juan Castillo11abdcd2014-10-21 11:30:42 +010069/* Info messages created in the Makefile */
70extern const char build_msg[];
71extern const char platform_msg[];
72
73
74static char *strdup(const char *str)
75{
76 int n = strlen(str) + 1;
77 char *dup = malloc(n);
78 if (dup) {
79 strcpy(dup, str);
80 }
81 return dup;
82}
83
Juan Castillof9f39c32015-06-01 16:34:23 +010084static const char *key_algs_str[] = {
85 [KEY_ALG_RSA] = "rsa",
Juan Castilloa2224ab2015-06-30 13:36:57 +010086#ifndef OPENSSL_NO_EC
Lionel Debievefefeffb2022-11-14 11:03:42 +010087 [KEY_ALG_ECDSA_NIST] = "ecdsa",
Donald Chan50d53972024-04-10 14:56:53 -070088#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +010089 [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular",
90 [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted",
Donald Chan50d53972024-04-10 14:56:53 -070091#endif
Juan Castilloa2224ab2015-06-30 13:36:57 +010092#endif /* OPENSSL_NO_EC */
Juan Castillof9f39c32015-06-01 16:34:23 +010093};
94
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080095static const char *hash_algs_str[] = {
96 [HASH_ALG_SHA256] = "sha256",
97 [HASH_ALG_SHA384] = "sha384",
98 [HASH_ALG_SHA512] = "sha512",
99};
100
Juan Castillo1218dd52015-07-03 16:23:16 +0100101static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo11abdcd2014-10-21 11:30:42 +0100102{
Juan Castillo212f7382015-12-15 16:37:57 +0000103 int rem, i = 0;
104 const struct option *opt;
105 char line[HELP_OPT_MAX_LEN];
106 char *p;
107
108 assert(cmd != NULL);
109 assert(long_opt != NULL);
110
Juan Castillo11abdcd2014-10-21 11:30:42 +0100111 printf("\n\n");
112 printf("The certificate generation tool loads the binary images and\n"
Lionel Debievefefeffb2022-11-14 11:03:42 +0100113 "optionally the RSA or ECC keys, and outputs the key and content\n"
Juan Castillo11abdcd2014-10-21 11:30:42 +0100114 "certificates properly signed to implement the chain of trust.\n"
115 "If keys are provided, they must be in PEM format.\n"
116 "Certificates are generated in DER format.\n");
117 printf("\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000118 printf("Usage:\n");
119 printf("\t%s [OPTIONS]\n\n", cmd);
120
121 printf("Available options:\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000122 opt = long_opt;
123 while (opt->name) {
124 p = line;
125 rem = HELP_OPT_MAX_LEN;
126 if (isalpha(opt->val)) {
127 /* Short format */
128 sprintf(p, "-%c,", (char)opt->val);
129 p += 3;
130 rem -= 3;
131 }
132 snprintf(p, rem, "--%s %s", opt->name,
133 (opt->has_arg == required_argument) ? "<arg>" : "");
134 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
135 opt++;
136 i++;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100137 }
138 printf("\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100139}
140
Juan Castillof9f39c32015-06-01 16:34:23 +0100141static int get_key_alg(const char *key_alg_str)
142{
143 int i;
144
145 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
146 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
147 return i;
148 }
149 }
150
151 return -1;
152}
153
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100154static int get_key_size(const char *key_size_str)
155{
156 char *end;
157 long key_size;
158
159 key_size = strtol(key_size_str, &end, 10);
160 if (*end != '\0')
161 return -1;
162
163 return key_size;
164}
165
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800166static int get_hash_alg(const char *hash_alg_str)
167{
168 int i;
169
170 for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
171 if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
172 return i;
173 }
174 }
175
176 return -1;
177}
178
Juan Castillo11abdcd2014-10-21 11:30:42 +0100179static void check_cmd_params(void)
180{
Juan Castillo86958fd2015-07-08 12:11:38 +0100181 cert_t *cert;
182 ext_t *ext;
183 key_t *key;
184 int i, j;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100185 bool valid_size;
Juan Castillo86958fd2015-07-08 12:11:38 +0100186
Juan Castillof9f39c32015-06-01 16:34:23 +0100187 /* Only save new keys */
188 if (save_keys && !new_keys) {
189 ERROR("Only new keys can be saved to disk\n");
190 exit(1);
191 }
192
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100193 /* Validate key-size */
194 valid_size = false;
195 for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
196 if (key_size == KEY_SIZES[key_alg][i]) {
197 valid_size = true;
198 break;
199 }
200 }
201 if (!valid_size) {
202 ERROR("'%d' is not a valid key size for '%s'\n",
203 key_size, key_algs_str[key_alg]);
204 NOTICE("Valid sizes are: ");
205 for (i = 0; i < KEY_SIZE_MAX_NUM &&
206 KEY_SIZES[key_alg][i] != 0; i++) {
207 printf("%d ", KEY_SIZES[key_alg][i]);
208 }
209 printf("\n");
210 exit(1);
211 }
212
Juan Castillo86958fd2015-07-08 12:11:38 +0100213 /* Check that all required options have been specified in the
214 * command line */
215 for (i = 0; i < num_certs; i++) {
216 cert = &certs[i];
217 if (cert->fn == NULL) {
218 /* Certificate not requested. Skip to the next one */
219 continue;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100220 }
221
Juan Castillo86958fd2015-07-08 12:11:38 +0100222 /* Check that all parameters required to create this certificate
223 * have been specified in the command line */
224 for (j = 0; j < cert->num_ext; j++) {
225 ext = &extensions[cert->ext[j]];
226 switch (ext->type) {
Juan Castillo43529982016-01-22 11:05:24 +0000227 case EXT_TYPE_NVCOUNTER:
228 /* Counter value must be specified */
229 if ((!ext->optional) && (ext->arg == NULL)) {
230 ERROR("Value for '%s' not specified\n",
231 ext->ln);
232 exit(1);
233 }
234 break;
Juan Castillo86958fd2015-07-08 12:11:38 +0100235 case EXT_TYPE_PKEY:
236 /* Key filename must be specified */
Juan Castillo43529982016-01-22 11:05:24 +0000237 key = &keys[ext->attr.key];
Juan Castillo86958fd2015-07-08 12:11:38 +0100238 if (!new_keys && key->fn == NULL) {
239 ERROR("Key '%s' required by '%s' not "
240 "specified\n", key->desc,
241 cert->cn);
242 exit(1);
243 }
244 break;
245 case EXT_TYPE_HASH:
Yatharth Kochar5752b592015-08-21 15:30:55 +0100246 /*
247 * Binary image must be specified
248 * unless it is explicitly made optional.
249 */
Juan Castillo43529982016-01-22 11:05:24 +0000250 if ((!ext->optional) && (ext->arg == NULL)) {
Juan Castillo86958fd2015-07-08 12:11:38 +0100251 ERROR("Image for '%s' not specified\n",
252 ext->ln);
253 exit(1);
254 }
255 break;
256 default:
Juan Castillo43529982016-01-22 11:05:24 +0000257 ERROR("Unknown extension type '%d' in '%s'\n",
258 ext->type, ext->ln);
Juan Castillo86958fd2015-07-08 12:11:38 +0100259 exit(1);
260 break;
261 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100262 }
263 }
264}
265
Juan Castillo212f7382015-12-15 16:37:57 +0000266/* Common command line options */
267static const cmd_opt_t common_cmd_opt[] = {
268 {
269 { "help", no_argument, NULL, 'h' },
270 "Print this message and exit"
271 },
272 {
273 { "key-alg", required_argument, NULL, 'a' },
Donald Chan50d53972024-04-10 14:56:53 -0700274 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, "
275#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +0100276 "'ecdsa', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'"
Donald Chan50d53972024-04-10 14:56:53 -0700277#else
278 "'ecdsa'"
279#endif
Juan Castillo212f7382015-12-15 16:37:57 +0000280 },
281 {
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100282 { "key-size", required_argument, NULL, 'b' },
283 "Key size (for supported algorithms)."
284 },
285 {
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800286 { "hash-alg", required_argument, NULL, 's' },
287 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
288 },
289 {
Juan Castillo212f7382015-12-15 16:37:57 +0000290 { "save-keys", no_argument, NULL, 'k' },
291 "Save key pairs into files. Filenames must be provided"
292 },
293 {
294 { "new-keys", no_argument, NULL, 'n' },
295 "Generate new key pairs if no key files are provided"
296 },
297 {
298 { "print-cert", no_argument, NULL, 'p' },
299 "Print the certificates in the standard output"
300 }
301};
302
Juan Castillo11abdcd2014-10-21 11:30:42 +0100303int main(int argc, char *argv[])
304{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900305 STACK_OF(X509_EXTENSION) * sk;
Michalis Pappas38628942017-10-06 16:11:44 +0800306 X509_EXTENSION *cert_ext = NULL;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900307 ext_t *ext;
308 key_t *key;
309 cert_t *cert;
310 FILE *file;
Juan Castillo43529982016-01-22 11:05:24 +0000311 int i, j, ext_nid, nvctr;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100312 int c, opt_idx = 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100313 const struct option *cmd_opt;
314 const char *cur_opt;
Juan Castillof9f39c32015-06-01 16:34:23 +0100315 unsigned int err_code;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800316 unsigned char md[SHA512_DIGEST_LENGTH];
317 unsigned int md_len;
Juan Castilloac402932015-03-05 14:30:00 +0000318 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100319
320 NOTICE("CoT Generation Tool: %s\n", build_msg);
321 NOTICE("Target platform: %s\n", platform_msg);
322
Juan Castillof9f39c32015-06-01 16:34:23 +0100323 /* Set default options */
324 key_alg = KEY_ALG_RSA;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800325 hash_alg = HASH_ALG_SHA256;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100326 key_size = -1;
Juan Castillof9f39c32015-06-01 16:34:23 +0100327
Juan Castillo1218dd52015-07-03 16:23:16 +0100328 /* Add common command line options */
Juan Castillo212f7382015-12-15 16:37:57 +0000329 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
330 cmd_opt_add(&common_cmd_opt[i]);
331 }
Juan Castillo1218dd52015-07-03 16:23:16 +0100332
333 /* Initialize the certificates */
334 if (cert_init() != 0) {
335 ERROR("Cannot initialize certificates\n");
336 exit(1);
337 }
338
339 /* Initialize the keys */
340 if (key_init() != 0) {
341 ERROR("Cannot initialize keys\n");
342 exit(1);
343 }
344
345 /* Initialize the new types and register OIDs for the extensions */
346 if (ext_init() != 0) {
Sandrine Bailleux0d11b482020-01-15 11:01:25 +0100347 ERROR("Cannot initialize extensions\n");
Juan Castillo1218dd52015-07-03 16:23:16 +0100348 exit(1);
349 }
350
351 /* Get the command line options populated during the initialization */
352 cmd_opt = cmd_opt_get_array();
353
Juan Castillo11abdcd2014-10-21 11:30:42 +0100354 while (1) {
355 /* getopt_long stores the option index here. */
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100356 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100357
358 /* Detect the end of the options. */
359 if (c == -1) {
360 break;
361 }
362
363 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100364 case 'a':
365 key_alg = get_key_alg(optarg);
366 if (key_alg < 0) {
367 ERROR("Invalid key algorithm '%s'\n", optarg);
368 exit(1);
369 }
370 break;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100371 case 'b':
372 key_size = get_key_size(optarg);
373 if (key_size <= 0) {
374 ERROR("Invalid key size '%s'\n", optarg);
375 exit(1);
376 }
377 break;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100378 case 'h':
Juan Castillo1218dd52015-07-03 16:23:16 +0100379 print_help(argv[0], cmd_opt);
Roberto Vargas58a5b2b2018-06-27 08:23:22 +0100380 exit(0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100381 case 'k':
382 save_keys = 1;
383 break;
384 case 'n':
385 new_keys = 1;
386 break;
387 case 'p':
388 print_cert = 1;
389 break;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800390 case 's':
391 hash_alg = get_hash_alg(optarg);
392 if (hash_alg < 0) {
393 ERROR("Invalid hash algorithm '%s'\n", optarg);
394 exit(1);
395 }
396 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100397 case CMD_OPT_EXT:
398 cur_opt = cmd_opt_get_name(opt_idx);
399 ext = ext_get_by_opt(cur_opt);
Juan Castillo43529982016-01-22 11:05:24 +0000400 ext->arg = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100401 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100402 case CMD_OPT_KEY:
403 cur_opt = cmd_opt_get_name(opt_idx);
404 key = key_get_by_opt(cur_opt);
405 key->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100406 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100407 case CMD_OPT_CERT:
408 cur_opt = cmd_opt_get_name(opt_idx);
409 cert = cert_get_by_opt(cur_opt);
410 cert->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100411 break;
412 case '?':
413 default:
Juan Castillo212f7382015-12-15 16:37:57 +0000414 print_help(argv[0], cmd_opt);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100415 exit(1);
416 }
417 }
418
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100419 /* Select a reasonable default key-size */
420 if (key_size == -1) {
421 key_size = KEY_SIZES[key_alg][0];
422 }
423
Juan Castillo11abdcd2014-10-21 11:30:42 +0100424 /* Check command line arguments */
425 check_cmd_params();
426
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800427 /* Indicate SHA as image hash algorithm in the certificate
Juan Castilloac402932015-03-05 14:30:00 +0000428 * extension */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800429 if (hash_alg == HASH_ALG_SHA384) {
430 md_info = EVP_sha384();
431 md_len = SHA384_DIGEST_LENGTH;
432 } else if (hash_alg == HASH_ALG_SHA512) {
433 md_info = EVP_sha512();
434 md_len = SHA512_DIGEST_LENGTH;
435 } else {
436 md_info = EVP_sha256();
437 md_len = SHA256_DIGEST_LENGTH;
438 }
Juan Castilloac402932015-03-05 14:30:00 +0000439
Juan Castillo11abdcd2014-10-21 11:30:42 +0100440 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100441 for (i = 0 ; i < num_keys ; i++) {
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400442#if !USING_OPENSSL3
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900443 if (!key_new(&keys[i])) {
444 ERROR("Failed to allocate key container\n");
445 exit(1);
446 }
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400447#endif
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900448
Juan Castillof9f39c32015-06-01 16:34:23 +0100449 /* First try to load the key from disk */
Sandrine Bailleuxea9f2f52023-10-16 14:52:06 +0200450 err_code = key_load(&keys[i]);
451 if (err_code == KEY_ERR_NONE) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100452 /* Key loaded successfully */
453 continue;
454 }
455
456 /* Key not loaded. Check the error code */
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900457 if (err_code == KEY_ERR_LOAD) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100458 /* File exists, but it does not contain a valid private
459 * key. Abort. */
460 ERROR("Error loading '%s'\n", keys[i].fn);
461 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100462 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100463
464 /* File does not exist, could not be opened or no filename was
465 * given */
466 if (new_keys) {
467 /* Try to create a new key */
468 NOTICE("Creating new key for '%s'\n", keys[i].desc);
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100469 if (!key_create(&keys[i], key_alg, key_size)) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100470 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100471 exit(1);
472 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100473 } else {
474 if (err_code == KEY_ERR_OPEN) {
475 ERROR("Error opening '%s'\n", keys[i].fn);
476 } else {
477 ERROR("Key '%s' not specified\n", keys[i].desc);
478 }
479 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100480 }
481 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100482
Juan Castilloe6d30e92015-06-12 11:27:59 +0100483 /* Create the certificates */
484 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100485
Juan Castilloe6d30e92015-06-12 11:27:59 +0100486 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100487
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000488 if (cert->fn == NULL) {
489 /* Certificate not requested. Skip to the next one */
490 continue;
491 }
492
Juan Castilloe6d30e92015-06-12 11:27:59 +0100493 /* Create a new stack of extensions. This stack will be used
494 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100495 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100496
Juan Castilloe6d30e92015-06-12 11:27:59 +0100497 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100498
Juan Castilloe6d30e92015-06-12 11:27:59 +0100499 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100500
Juan Castilloe6d30e92015-06-12 11:27:59 +0100501 /* Get OpenSSL internal ID for this extension */
502 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100503
Juan Castilloe6d30e92015-06-12 11:27:59 +0100504 /*
505 * Three types of extensions are currently supported:
506 * - EXT_TYPE_NVCOUNTER
507 * - EXT_TYPE_HASH
508 * - EXT_TYPE_PKEY
509 */
510 switch (ext->type) {
511 case EXT_TYPE_NVCOUNTER:
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600512 if (ext->optional && ext->arg == NULL) {
513 /* Skip this NVCounter */
514 continue;
515 } else {
516 /* Checked by `check_cmd_params` */
517 assert(ext->arg != NULL);
Yatharth Kochar79f86402016-06-22 14:49:27 +0100518 nvctr = atoi(ext->arg);
519 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000520 EXT_CRIT, nvctr));
Yatharth Kochar79f86402016-06-22 14:49:27 +0100521 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100522 break;
523 case EXT_TYPE_HASH:
Juan Castillo43529982016-01-22 11:05:24 +0000524 if (ext->arg == NULL) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100525 if (ext->optional) {
526 /* Include a hash filled with zeros */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800527 memset(md, 0x0, SHA512_DIGEST_LENGTH);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100528 } else {
529 /* Do not include this hash in the certificate */
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600530 continue;
Yatharth Kochar5752b592015-08-21 15:30:55 +0100531 }
532 } else {
533 /* Calculate the hash of the file */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800534 if (!sha_file(hash_alg, ext->arg, md)) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100535 ERROR("Cannot calculate hash of %s\n",
Juan Castillo43529982016-01-22 11:05:24 +0000536 ext->arg);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100537 exit(1);
538 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100539 }
540 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
541 EXT_CRIT, md_info, md,
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800542 md_len));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100543 break;
544 case EXT_TYPE_PKEY:
545 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000546 EXT_CRIT, keys[ext->attr.key].key));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100547 break;
548 default:
Juan Castillo43529982016-01-22 11:05:24 +0000549 ERROR("Unknown extension type '%d' in %s\n",
550 ext->type, cert->cn);
Juan Castilloe6d30e92015-06-12 11:27:59 +0100551 exit(1);
552 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100553
Juan Castilloe6d30e92015-06-12 11:27:59 +0100554 /* Push the extension into the stack */
555 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100556 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100557
Soby Mathew2fd70f62017-08-31 11:50:29 +0100558 /* Create certificate. Signed with corresponding key */
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000559 if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100560 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100561 exit(1);
562 }
563
Jimmy Brisson63d06932020-07-24 14:31:48 -0500564 for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
565 cert_ext = sk_X509_EXTENSION_pop(sk)) {
566 X509_EXTENSION_free(cert_ext);
567 }
568
Juan Castillo11abdcd2014-10-21 11:30:42 +0100569 sk_X509_EXTENSION_free(sk);
570 }
571
Juan Castillo11abdcd2014-10-21 11:30:42 +0100572
573 /* Print the certificates */
574 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100575 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100576 if (!certs[i].x) {
577 continue;
578 }
579 printf("\n\n=====================================\n\n");
580 X509_print_fp(stdout, certs[i].x);
581 }
582 }
583
584 /* Save created certificates to files */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100585 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100586 if (certs[i].x && certs[i].fn) {
587 file = fopen(certs[i].fn, "w");
588 if (file != NULL) {
589 i2d_X509_fp(file, certs[i].x);
590 fclose(file);
591 } else {
592 ERROR("Cannot create file %s\n", certs[i].fn);
593 }
594 }
595 }
596
597 /* Save keys */
598 if (save_keys) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100599 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100600 if (!key_store(&keys[i])) {
601 ERROR("Cannot save %s\n", keys[i].desc);
602 }
603 }
604 }
605
Jimmy Brisson53287962020-07-27 10:43:40 -0500606 /* If we got here, then we must have filled the key array completely.
607 * We can then safely call free on all of the keys in the array
608 */
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400609 key_cleanup();
Jimmy Brisson53287962020-07-27 10:43:40 -0500610
Juan Castillo11abdcd2014-10-21 11:30:42 +0100611#ifndef OPENSSL_NO_ENGINE
612 ENGINE_cleanup();
613#endif
614 CRYPTO_cleanup_all_ex_data();
615
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500616
617 /* We allocated strings through strdup, so now we have to free them */
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500618
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400619 ext_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500620
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400621 cert_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500622
Juan Castillo11abdcd2014-10-21 11:30:42 +0100623 return 0;
624}