blob: aa21206c0281a4c6ffe886498dc02cf8bb7b2fd8 [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
Chris Kaya9f543a2024-06-14 11:31:03 +00002 * Copyright (c) 2015-2024, 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
Manish V Badarkhe7b425de2024-07-19 08:31:51 +01007#define _POSIX_C_SOURCE 200809L
8
Juan Castillo212f7382015-12-15 16:37:57 +00009#include <assert.h>
10#include <ctype.h>
Juan Castillo11abdcd2014-10-21 11:30:42 +010011#include <getopt.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
Justin Chadwellfebe86c2019-07-29 17:13:45 +010015#include <stdbool.h>
Juan Castillo11abdcd2014-10-21 11:30:42 +010016
17#include <openssl/conf.h>
18#include <openssl/engine.h>
19#include <openssl/err.h>
20#include <openssl/pem.h>
21#include <openssl/sha.h>
22#include <openssl/x509v3.h>
23
24#include "cert.h"
Juan Castillo1218dd52015-07-03 16:23:16 +010025#include "cmd_opt.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010026#include "debug.h"
27#include "ext.h"
28#include "key.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010029#include "sha.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010030
31/*
32 * Helper macros to simplify the code. This macro assigns the return value of
33 * the 'fn' function to 'v' and exits if the value is NULL.
34 */
35#define CHECK_NULL(v, fn) \
36 do { \
37 v = fn; \
38 if (v == NULL) { \
39 ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \
40 exit(1); \
41 } \
42 } while (0)
43
44/*
45 * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the
46 * NID is undefined.
47 */
48#define CHECK_OID(v, oid) \
49 do { \
50 v = OBJ_txt2nid(oid); \
51 if (v == NID_undef) { \
Sandrine Bailleux0d11b482020-01-15 11:01:25 +010052 ERROR("Cannot find extension %s\n", oid); \
Juan Castillo11abdcd2014-10-21 11:30:42 +010053 exit(1); \
54 } \
55 } while (0)
56
57#define MAX_FILENAME_LEN 1024
58#define VAL_DAYS 7300
59#define ID_TO_BIT_MASK(id) (1 << id)
Juan Castillof9f39c32015-06-01 16:34:23 +010060#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
Juan Castillo212f7382015-12-15 16:37:57 +000061#define HELP_OPT_MAX_LEN 128
Juan Castillo11abdcd2014-10-21 11:30:42 +010062
63/* Global options */
Juan Castillof9f39c32015-06-01 16:34:23 +010064static int key_alg;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080065static int hash_alg;
Justin Chadwellfebe86c2019-07-29 17:13:45 +010066static int key_size;
Juan Castillo11abdcd2014-10-21 11:30:42 +010067static int new_keys;
68static int save_keys;
69static int print_cert;
Juan Castillo11abdcd2014-10-21 11:30:42 +010070
Chris Kaya9f543a2024-06-14 11:31:03 +000071static const char build_msg[] = "Built : " __TIME__ ", " __DATE__;
72static const char platform_msg[] = PLAT_MSG;
Juan Castillo11abdcd2014-10-21 11:30:42 +010073
Juan Castillof9f39c32015-06-01 16:34:23 +010074static const char *key_algs_str[] = {
75 [KEY_ALG_RSA] = "rsa",
Juan Castilloa2224ab2015-06-30 13:36:57 +010076#ifndef OPENSSL_NO_EC
Lionel Debievefefeffb2022-11-14 11:03:42 +010077 [KEY_ALG_ECDSA_NIST] = "ecdsa",
Donald Chan50d53972024-04-10 14:56:53 -070078#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +010079 [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular",
80 [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted",
Donald Chan50d53972024-04-10 14:56:53 -070081#endif
Juan Castilloa2224ab2015-06-30 13:36:57 +010082#endif /* OPENSSL_NO_EC */
Juan Castillof9f39c32015-06-01 16:34:23 +010083};
84
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080085static const char *hash_algs_str[] = {
86 [HASH_ALG_SHA256] = "sha256",
87 [HASH_ALG_SHA384] = "sha384",
88 [HASH_ALG_SHA512] = "sha512",
89};
90
Juan Castillo1218dd52015-07-03 16:23:16 +010091static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo11abdcd2014-10-21 11:30:42 +010092{
Juan Castillo212f7382015-12-15 16:37:57 +000093 int rem, i = 0;
94 const struct option *opt;
95 char line[HELP_OPT_MAX_LEN];
96 char *p;
97
98 assert(cmd != NULL);
99 assert(long_opt != NULL);
100
Juan Castillo11abdcd2014-10-21 11:30:42 +0100101 printf("\n\n");
102 printf("The certificate generation tool loads the binary images and\n"
Lionel Debievefefeffb2022-11-14 11:03:42 +0100103 "optionally the RSA or ECC keys, and outputs the key and content\n"
Juan Castillo11abdcd2014-10-21 11:30:42 +0100104 "certificates properly signed to implement the chain of trust.\n"
105 "If keys are provided, they must be in PEM format.\n"
106 "Certificates are generated in DER format.\n");
107 printf("\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000108 printf("Usage:\n");
109 printf("\t%s [OPTIONS]\n\n", cmd);
110
111 printf("Available options:\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000112 opt = long_opt;
113 while (opt->name) {
114 p = line;
115 rem = HELP_OPT_MAX_LEN;
116 if (isalpha(opt->val)) {
117 /* Short format */
118 sprintf(p, "-%c,", (char)opt->val);
119 p += 3;
120 rem -= 3;
121 }
122 snprintf(p, rem, "--%s %s", opt->name,
123 (opt->has_arg == required_argument) ? "<arg>" : "");
124 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
125 opt++;
126 i++;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100127 }
128 printf("\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100129}
130
Juan Castillof9f39c32015-06-01 16:34:23 +0100131static int get_key_alg(const char *key_alg_str)
132{
133 int i;
134
135 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
136 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
137 return i;
138 }
139 }
140
141 return -1;
142}
143
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100144static int get_key_size(const char *key_size_str)
145{
146 char *end;
147 long key_size;
148
149 key_size = strtol(key_size_str, &end, 10);
150 if (*end != '\0')
151 return -1;
152
153 return key_size;
154}
155
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800156static int get_hash_alg(const char *hash_alg_str)
157{
158 int i;
159
160 for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
161 if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
162 return i;
163 }
164 }
165
166 return -1;
167}
168
Juan Castillo11abdcd2014-10-21 11:30:42 +0100169static void check_cmd_params(void)
170{
Juan Castillo86958fd2015-07-08 12:11:38 +0100171 cert_t *cert;
172 ext_t *ext;
Manish V Badarkhe7b425de2024-07-19 08:31:51 +0100173 cert_key_t *key;
Juan Castillo86958fd2015-07-08 12:11:38 +0100174 int i, j;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100175 bool valid_size;
Juan Castillo86958fd2015-07-08 12:11:38 +0100176
Juan Castillof9f39c32015-06-01 16:34:23 +0100177 /* Only save new keys */
178 if (save_keys && !new_keys) {
179 ERROR("Only new keys can be saved to disk\n");
180 exit(1);
181 }
182
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100183 /* Validate key-size */
184 valid_size = false;
185 for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
186 if (key_size == KEY_SIZES[key_alg][i]) {
187 valid_size = true;
188 break;
189 }
190 }
191 if (!valid_size) {
192 ERROR("'%d' is not a valid key size for '%s'\n",
193 key_size, key_algs_str[key_alg]);
194 NOTICE("Valid sizes are: ");
195 for (i = 0; i < KEY_SIZE_MAX_NUM &&
196 KEY_SIZES[key_alg][i] != 0; i++) {
197 printf("%d ", KEY_SIZES[key_alg][i]);
198 }
199 printf("\n");
200 exit(1);
201 }
202
Juan Castillo86958fd2015-07-08 12:11:38 +0100203 /* Check that all required options have been specified in the
204 * command line */
205 for (i = 0; i < num_certs; i++) {
206 cert = &certs[i];
207 if (cert->fn == NULL) {
208 /* Certificate not requested. Skip to the next one */
209 continue;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100210 }
211
Juan Castillo86958fd2015-07-08 12:11:38 +0100212 /* Check that all parameters required to create this certificate
213 * have been specified in the command line */
214 for (j = 0; j < cert->num_ext; j++) {
215 ext = &extensions[cert->ext[j]];
216 switch (ext->type) {
Juan Castillo43529982016-01-22 11:05:24 +0000217 case EXT_TYPE_NVCOUNTER:
218 /* Counter value must be specified */
219 if ((!ext->optional) && (ext->arg == NULL)) {
220 ERROR("Value for '%s' not specified\n",
221 ext->ln);
222 exit(1);
223 }
224 break;
Juan Castillo86958fd2015-07-08 12:11:38 +0100225 case EXT_TYPE_PKEY:
226 /* Key filename must be specified */
Juan Castillo43529982016-01-22 11:05:24 +0000227 key = &keys[ext->attr.key];
Juan Castillo86958fd2015-07-08 12:11:38 +0100228 if (!new_keys && key->fn == NULL) {
229 ERROR("Key '%s' required by '%s' not "
230 "specified\n", key->desc,
231 cert->cn);
232 exit(1);
233 }
234 break;
235 case EXT_TYPE_HASH:
Yatharth Kochar5752b592015-08-21 15:30:55 +0100236 /*
237 * Binary image must be specified
238 * unless it is explicitly made optional.
239 */
Juan Castillo43529982016-01-22 11:05:24 +0000240 if ((!ext->optional) && (ext->arg == NULL)) {
Juan Castillo86958fd2015-07-08 12:11:38 +0100241 ERROR("Image for '%s' not specified\n",
242 ext->ln);
243 exit(1);
244 }
245 break;
246 default:
Juan Castillo43529982016-01-22 11:05:24 +0000247 ERROR("Unknown extension type '%d' in '%s'\n",
248 ext->type, ext->ln);
Juan Castillo86958fd2015-07-08 12:11:38 +0100249 exit(1);
250 break;
251 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100252 }
253 }
254}
255
Juan Castillo212f7382015-12-15 16:37:57 +0000256/* Common command line options */
257static const cmd_opt_t common_cmd_opt[] = {
258 {
259 { "help", no_argument, NULL, 'h' },
260 "Print this message and exit"
261 },
262 {
263 { "key-alg", required_argument, NULL, 'a' },
Donald Chan50d53972024-04-10 14:56:53 -0700264 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, "
265#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +0100266 "'ecdsa', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'"
Donald Chan50d53972024-04-10 14:56:53 -0700267#else
268 "'ecdsa'"
269#endif
Juan Castillo212f7382015-12-15 16:37:57 +0000270 },
271 {
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100272 { "key-size", required_argument, NULL, 'b' },
273 "Key size (for supported algorithms)."
274 },
275 {
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800276 { "hash-alg", required_argument, NULL, 's' },
277 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
278 },
279 {
Juan Castillo212f7382015-12-15 16:37:57 +0000280 { "save-keys", no_argument, NULL, 'k' },
281 "Save key pairs into files. Filenames must be provided"
282 },
283 {
284 { "new-keys", no_argument, NULL, 'n' },
285 "Generate new key pairs if no key files are provided"
286 },
287 {
288 { "print-cert", no_argument, NULL, 'p' },
289 "Print the certificates in the standard output"
290 }
291};
292
Juan Castillo11abdcd2014-10-21 11:30:42 +0100293int main(int argc, char *argv[])
294{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900295 STACK_OF(X509_EXTENSION) * sk;
Michalis Pappas38628942017-10-06 16:11:44 +0800296 X509_EXTENSION *cert_ext = NULL;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900297 ext_t *ext;
Manish V Badarkhe7b425de2024-07-19 08:31:51 +0100298 cert_key_t *key;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900299 cert_t *cert;
300 FILE *file;
Juan Castillo43529982016-01-22 11:05:24 +0000301 int i, j, ext_nid, nvctr;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100302 int c, opt_idx = 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100303 const struct option *cmd_opt;
304 const char *cur_opt;
Juan Castillof9f39c32015-06-01 16:34:23 +0100305 unsigned int err_code;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800306 unsigned char md[SHA512_DIGEST_LENGTH];
307 unsigned int md_len;
Juan Castilloac402932015-03-05 14:30:00 +0000308 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100309
310 NOTICE("CoT Generation Tool: %s\n", build_msg);
311 NOTICE("Target platform: %s\n", platform_msg);
312
Juan Castillof9f39c32015-06-01 16:34:23 +0100313 /* Set default options */
314 key_alg = KEY_ALG_RSA;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800315 hash_alg = HASH_ALG_SHA256;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100316 key_size = -1;
Juan Castillof9f39c32015-06-01 16:34:23 +0100317
Juan Castillo1218dd52015-07-03 16:23:16 +0100318 /* Add common command line options */
Juan Castillo212f7382015-12-15 16:37:57 +0000319 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
320 cmd_opt_add(&common_cmd_opt[i]);
321 }
Juan Castillo1218dd52015-07-03 16:23:16 +0100322
323 /* Initialize the certificates */
324 if (cert_init() != 0) {
325 ERROR("Cannot initialize certificates\n");
326 exit(1);
327 }
328
329 /* Initialize the keys */
330 if (key_init() != 0) {
331 ERROR("Cannot initialize keys\n");
332 exit(1);
333 }
334
335 /* Initialize the new types and register OIDs for the extensions */
336 if (ext_init() != 0) {
Sandrine Bailleux0d11b482020-01-15 11:01:25 +0100337 ERROR("Cannot initialize extensions\n");
Juan Castillo1218dd52015-07-03 16:23:16 +0100338 exit(1);
339 }
340
341 /* Get the command line options populated during the initialization */
342 cmd_opt = cmd_opt_get_array();
343
Juan Castillo11abdcd2014-10-21 11:30:42 +0100344 while (1) {
345 /* getopt_long stores the option index here. */
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100346 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100347
348 /* Detect the end of the options. */
349 if (c == -1) {
350 break;
351 }
352
353 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100354 case 'a':
355 key_alg = get_key_alg(optarg);
356 if (key_alg < 0) {
357 ERROR("Invalid key algorithm '%s'\n", optarg);
358 exit(1);
359 }
360 break;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100361 case 'b':
362 key_size = get_key_size(optarg);
363 if (key_size <= 0) {
364 ERROR("Invalid key size '%s'\n", optarg);
365 exit(1);
366 }
367 break;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100368 case 'h':
Juan Castillo1218dd52015-07-03 16:23:16 +0100369 print_help(argv[0], cmd_opt);
Roberto Vargas58a5b2b2018-06-27 08:23:22 +0100370 exit(0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100371 case 'k':
372 save_keys = 1;
373 break;
374 case 'n':
375 new_keys = 1;
376 break;
377 case 'p':
378 print_cert = 1;
379 break;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800380 case 's':
381 hash_alg = get_hash_alg(optarg);
382 if (hash_alg < 0) {
383 ERROR("Invalid hash algorithm '%s'\n", optarg);
384 exit(1);
385 }
386 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100387 case CMD_OPT_EXT:
388 cur_opt = cmd_opt_get_name(opt_idx);
389 ext = ext_get_by_opt(cur_opt);
Juan Castillo43529982016-01-22 11:05:24 +0000390 ext->arg = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100391 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100392 case CMD_OPT_KEY:
393 cur_opt = cmd_opt_get_name(opt_idx);
394 key = key_get_by_opt(cur_opt);
395 key->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100396 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100397 case CMD_OPT_CERT:
398 cur_opt = cmd_opt_get_name(opt_idx);
399 cert = cert_get_by_opt(cur_opt);
400 cert->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100401 break;
402 case '?':
403 default:
Juan Castillo212f7382015-12-15 16:37:57 +0000404 print_help(argv[0], cmd_opt);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100405 exit(1);
406 }
407 }
408
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100409 /* Select a reasonable default key-size */
410 if (key_size == -1) {
411 key_size = KEY_SIZES[key_alg][0];
412 }
413
Juan Castillo11abdcd2014-10-21 11:30:42 +0100414 /* Check command line arguments */
415 check_cmd_params();
416
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800417 /* Indicate SHA as image hash algorithm in the certificate
Juan Castilloac402932015-03-05 14:30:00 +0000418 * extension */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800419 if (hash_alg == HASH_ALG_SHA384) {
420 md_info = EVP_sha384();
421 md_len = SHA384_DIGEST_LENGTH;
422 } else if (hash_alg == HASH_ALG_SHA512) {
423 md_info = EVP_sha512();
424 md_len = SHA512_DIGEST_LENGTH;
425 } else {
426 md_info = EVP_sha256();
427 md_len = SHA256_DIGEST_LENGTH;
428 }
Juan Castilloac402932015-03-05 14:30:00 +0000429
Juan Castillo11abdcd2014-10-21 11:30:42 +0100430 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100431 for (i = 0 ; i < num_keys ; i++) {
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400432#if !USING_OPENSSL3
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900433 if (!key_new(&keys[i])) {
434 ERROR("Failed to allocate key container\n");
435 exit(1);
436 }
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400437#endif
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900438
Juan Castillof9f39c32015-06-01 16:34:23 +0100439 /* First try to load the key from disk */
Sandrine Bailleuxea9f2f52023-10-16 14:52:06 +0200440 err_code = key_load(&keys[i]);
441 if (err_code == KEY_ERR_NONE) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100442 /* Key loaded successfully */
443 continue;
444 }
445
446 /* Key not loaded. Check the error code */
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900447 if (err_code == KEY_ERR_LOAD) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100448 /* File exists, but it does not contain a valid private
449 * key. Abort. */
450 ERROR("Error loading '%s'\n", keys[i].fn);
451 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100452 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100453
454 /* File does not exist, could not be opened or no filename was
455 * given */
456 if (new_keys) {
457 /* Try to create a new key */
458 NOTICE("Creating new key for '%s'\n", keys[i].desc);
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100459 if (!key_create(&keys[i], key_alg, key_size)) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100460 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100461 exit(1);
462 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100463 } else {
464 if (err_code == KEY_ERR_OPEN) {
465 ERROR("Error opening '%s'\n", keys[i].fn);
466 } else {
467 ERROR("Key '%s' not specified\n", keys[i].desc);
468 }
469 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100470 }
471 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100472
Juan Castilloe6d30e92015-06-12 11:27:59 +0100473 /* Create the certificates */
474 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100475
Juan Castilloe6d30e92015-06-12 11:27:59 +0100476 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100477
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000478 if (cert->fn == NULL) {
479 /* Certificate not requested. Skip to the next one */
480 continue;
481 }
482
Juan Castilloe6d30e92015-06-12 11:27:59 +0100483 /* Create a new stack of extensions. This stack will be used
484 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100485 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100486
Juan Castilloe6d30e92015-06-12 11:27:59 +0100487 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100488
Juan Castilloe6d30e92015-06-12 11:27:59 +0100489 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100490
Juan Castilloe6d30e92015-06-12 11:27:59 +0100491 /* Get OpenSSL internal ID for this extension */
492 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100493
Juan Castilloe6d30e92015-06-12 11:27:59 +0100494 /*
495 * Three types of extensions are currently supported:
496 * - EXT_TYPE_NVCOUNTER
497 * - EXT_TYPE_HASH
498 * - EXT_TYPE_PKEY
499 */
500 switch (ext->type) {
501 case EXT_TYPE_NVCOUNTER:
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600502 if (ext->optional && ext->arg == NULL) {
503 /* Skip this NVCounter */
504 continue;
505 } else {
506 /* Checked by `check_cmd_params` */
507 assert(ext->arg != NULL);
Yatharth Kochar79f86402016-06-22 14:49:27 +0100508 nvctr = atoi(ext->arg);
509 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000510 EXT_CRIT, nvctr));
Yatharth Kochar79f86402016-06-22 14:49:27 +0100511 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100512 break;
513 case EXT_TYPE_HASH:
Juan Castillo43529982016-01-22 11:05:24 +0000514 if (ext->arg == NULL) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100515 if (ext->optional) {
516 /* Include a hash filled with zeros */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800517 memset(md, 0x0, SHA512_DIGEST_LENGTH);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100518 } else {
519 /* Do not include this hash in the certificate */
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600520 continue;
Yatharth Kochar5752b592015-08-21 15:30:55 +0100521 }
522 } else {
523 /* Calculate the hash of the file */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800524 if (!sha_file(hash_alg, ext->arg, md)) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100525 ERROR("Cannot calculate hash of %s\n",
Juan Castillo43529982016-01-22 11:05:24 +0000526 ext->arg);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100527 exit(1);
528 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100529 }
530 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
531 EXT_CRIT, md_info, md,
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800532 md_len));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100533 break;
534 case EXT_TYPE_PKEY:
535 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000536 EXT_CRIT, keys[ext->attr.key].key));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100537 break;
538 default:
Juan Castillo43529982016-01-22 11:05:24 +0000539 ERROR("Unknown extension type '%d' in %s\n",
540 ext->type, cert->cn);
Juan Castilloe6d30e92015-06-12 11:27:59 +0100541 exit(1);
542 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100543
Juan Castilloe6d30e92015-06-12 11:27:59 +0100544 /* Push the extension into the stack */
545 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100546 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100547
Soby Mathew2fd70f62017-08-31 11:50:29 +0100548 /* Create certificate. Signed with corresponding key */
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000549 if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100550 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100551 exit(1);
552 }
553
Jimmy Brisson63d06932020-07-24 14:31:48 -0500554 for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
555 cert_ext = sk_X509_EXTENSION_pop(sk)) {
556 X509_EXTENSION_free(cert_ext);
557 }
558
Juan Castillo11abdcd2014-10-21 11:30:42 +0100559 sk_X509_EXTENSION_free(sk);
560 }
561
Juan Castillo11abdcd2014-10-21 11:30:42 +0100562
563 /* Print the certificates */
564 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100565 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100566 if (!certs[i].x) {
567 continue;
568 }
569 printf("\n\n=====================================\n\n");
570 X509_print_fp(stdout, certs[i].x);
571 }
572 }
573
574 /* Save created certificates to files */
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 && certs[i].fn) {
577 file = fopen(certs[i].fn, "w");
578 if (file != NULL) {
579 i2d_X509_fp(file, certs[i].x);
580 fclose(file);
581 } else {
582 ERROR("Cannot create file %s\n", certs[i].fn);
583 }
584 }
585 }
586
587 /* Save keys */
588 if (save_keys) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100589 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100590 if (!key_store(&keys[i])) {
591 ERROR("Cannot save %s\n", keys[i].desc);
592 }
593 }
594 }
595
Jimmy Brisson53287962020-07-27 10:43:40 -0500596 /* If we got here, then we must have filled the key array completely.
597 * We can then safely call free on all of the keys in the array
598 */
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400599 key_cleanup();
Jimmy Brisson53287962020-07-27 10:43:40 -0500600
Juan Castillo11abdcd2014-10-21 11:30:42 +0100601#ifndef OPENSSL_NO_ENGINE
602 ENGINE_cleanup();
603#endif
604 CRYPTO_cleanup_all_ex_data();
605
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500606
607 /* We allocated strings through strdup, so now we have to free them */
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500608
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400609 ext_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500610
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400611 cert_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500612
Juan Castillo11abdcd2014-10-21 11:30:42 +0100613 return 0;
614}