blob: edc2d683b7958acf84660f85efdd4ac01d0910f0 [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
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
Chris Kaya9f543a2024-06-14 11:31:03 +000069static const char build_msg[] = "Built : " __TIME__ ", " __DATE__;
70static const char platform_msg[] = PLAT_MSG;
Juan Castillo11abdcd2014-10-21 11:30:42 +010071
72static char *strdup(const char *str)
73{
74 int n = strlen(str) + 1;
75 char *dup = malloc(n);
76 if (dup) {
77 strcpy(dup, str);
78 }
79 return dup;
80}
81
Juan Castillof9f39c32015-06-01 16:34:23 +010082static const char *key_algs_str[] = {
83 [KEY_ALG_RSA] = "rsa",
Juan Castilloa2224ab2015-06-30 13:36:57 +010084#ifndef OPENSSL_NO_EC
Lionel Debievefefeffb2022-11-14 11:03:42 +010085 [KEY_ALG_ECDSA_NIST] = "ecdsa",
Donald Chan50d53972024-04-10 14:56:53 -070086#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +010087 [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular",
88 [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted",
Donald Chan50d53972024-04-10 14:56:53 -070089#endif
Juan Castilloa2224ab2015-06-30 13:36:57 +010090#endif /* OPENSSL_NO_EC */
Juan Castillof9f39c32015-06-01 16:34:23 +010091};
92
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080093static const char *hash_algs_str[] = {
94 [HASH_ALG_SHA256] = "sha256",
95 [HASH_ALG_SHA384] = "sha384",
96 [HASH_ALG_SHA512] = "sha512",
97};
98
Juan Castillo1218dd52015-07-03 16:23:16 +010099static void print_help(const char *cmd, const struct option *long_opt)
Juan Castillo11abdcd2014-10-21 11:30:42 +0100100{
Juan Castillo212f7382015-12-15 16:37:57 +0000101 int rem, i = 0;
102 const struct option *opt;
103 char line[HELP_OPT_MAX_LEN];
104 char *p;
105
106 assert(cmd != NULL);
107 assert(long_opt != NULL);
108
Juan Castillo11abdcd2014-10-21 11:30:42 +0100109 printf("\n\n");
110 printf("The certificate generation tool loads the binary images and\n"
Lionel Debievefefeffb2022-11-14 11:03:42 +0100111 "optionally the RSA or ECC keys, and outputs the key and content\n"
Juan Castillo11abdcd2014-10-21 11:30:42 +0100112 "certificates properly signed to implement the chain of trust.\n"
113 "If keys are provided, they must be in PEM format.\n"
114 "Certificates are generated in DER format.\n");
115 printf("\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000116 printf("Usage:\n");
117 printf("\t%s [OPTIONS]\n\n", cmd);
118
119 printf("Available options:\n");
Juan Castillo212f7382015-12-15 16:37:57 +0000120 opt = long_opt;
121 while (opt->name) {
122 p = line;
123 rem = HELP_OPT_MAX_LEN;
124 if (isalpha(opt->val)) {
125 /* Short format */
126 sprintf(p, "-%c,", (char)opt->val);
127 p += 3;
128 rem -= 3;
129 }
130 snprintf(p, rem, "--%s %s", opt->name,
131 (opt->has_arg == required_argument) ? "<arg>" : "");
132 printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
133 opt++;
134 i++;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100135 }
136 printf("\n");
Juan Castillo11abdcd2014-10-21 11:30:42 +0100137}
138
Juan Castillof9f39c32015-06-01 16:34:23 +0100139static int get_key_alg(const char *key_alg_str)
140{
141 int i;
142
143 for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
144 if (0 == strcmp(key_alg_str, key_algs_str[i])) {
145 return i;
146 }
147 }
148
149 return -1;
150}
151
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100152static int get_key_size(const char *key_size_str)
153{
154 char *end;
155 long key_size;
156
157 key_size = strtol(key_size_str, &end, 10);
158 if (*end != '\0')
159 return -1;
160
161 return key_size;
162}
163
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800164static int get_hash_alg(const char *hash_alg_str)
165{
166 int i;
167
168 for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) {
169 if (0 == strcmp(hash_alg_str, hash_algs_str[i])) {
170 return i;
171 }
172 }
173
174 return -1;
175}
176
Juan Castillo11abdcd2014-10-21 11:30:42 +0100177static void check_cmd_params(void)
178{
Juan Castillo86958fd2015-07-08 12:11:38 +0100179 cert_t *cert;
180 ext_t *ext;
181 key_t *key;
182 int i, j;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100183 bool valid_size;
Juan Castillo86958fd2015-07-08 12:11:38 +0100184
Juan Castillof9f39c32015-06-01 16:34:23 +0100185 /* Only save new keys */
186 if (save_keys && !new_keys) {
187 ERROR("Only new keys can be saved to disk\n");
188 exit(1);
189 }
190
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100191 /* Validate key-size */
192 valid_size = false;
193 for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
194 if (key_size == KEY_SIZES[key_alg][i]) {
195 valid_size = true;
196 break;
197 }
198 }
199 if (!valid_size) {
200 ERROR("'%d' is not a valid key size for '%s'\n",
201 key_size, key_algs_str[key_alg]);
202 NOTICE("Valid sizes are: ");
203 for (i = 0; i < KEY_SIZE_MAX_NUM &&
204 KEY_SIZES[key_alg][i] != 0; i++) {
205 printf("%d ", KEY_SIZES[key_alg][i]);
206 }
207 printf("\n");
208 exit(1);
209 }
210
Juan Castillo86958fd2015-07-08 12:11:38 +0100211 /* Check that all required options have been specified in the
212 * command line */
213 for (i = 0; i < num_certs; i++) {
214 cert = &certs[i];
215 if (cert->fn == NULL) {
216 /* Certificate not requested. Skip to the next one */
217 continue;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100218 }
219
Juan Castillo86958fd2015-07-08 12:11:38 +0100220 /* Check that all parameters required to create this certificate
221 * have been specified in the command line */
222 for (j = 0; j < cert->num_ext; j++) {
223 ext = &extensions[cert->ext[j]];
224 switch (ext->type) {
Juan Castillo43529982016-01-22 11:05:24 +0000225 case EXT_TYPE_NVCOUNTER:
226 /* Counter value must be specified */
227 if ((!ext->optional) && (ext->arg == NULL)) {
228 ERROR("Value for '%s' not specified\n",
229 ext->ln);
230 exit(1);
231 }
232 break;
Juan Castillo86958fd2015-07-08 12:11:38 +0100233 case EXT_TYPE_PKEY:
234 /* Key filename must be specified */
Juan Castillo43529982016-01-22 11:05:24 +0000235 key = &keys[ext->attr.key];
Juan Castillo86958fd2015-07-08 12:11:38 +0100236 if (!new_keys && key->fn == NULL) {
237 ERROR("Key '%s' required by '%s' not "
238 "specified\n", key->desc,
239 cert->cn);
240 exit(1);
241 }
242 break;
243 case EXT_TYPE_HASH:
Yatharth Kochar5752b592015-08-21 15:30:55 +0100244 /*
245 * Binary image must be specified
246 * unless it is explicitly made optional.
247 */
Juan Castillo43529982016-01-22 11:05:24 +0000248 if ((!ext->optional) && (ext->arg == NULL)) {
Juan Castillo86958fd2015-07-08 12:11:38 +0100249 ERROR("Image for '%s' not specified\n",
250 ext->ln);
251 exit(1);
252 }
253 break;
254 default:
Juan Castillo43529982016-01-22 11:05:24 +0000255 ERROR("Unknown extension type '%d' in '%s'\n",
256 ext->type, ext->ln);
Juan Castillo86958fd2015-07-08 12:11:38 +0100257 exit(1);
258 break;
259 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100260 }
261 }
262}
263
Juan Castillo212f7382015-12-15 16:37:57 +0000264/* Common command line options */
265static const cmd_opt_t common_cmd_opt[] = {
266 {
267 { "help", no_argument, NULL, 'h' },
268 "Print this message and exit"
269 },
270 {
271 { "key-alg", required_argument, NULL, 'a' },
Donald Chan50d53972024-04-10 14:56:53 -0700272 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, "
273#if OPENSSL_VERSION_NUMBER >= 0x10100000L
Lionel Debievefefeffb2022-11-14 11:03:42 +0100274 "'ecdsa', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'"
Donald Chan50d53972024-04-10 14:56:53 -0700275#else
276 "'ecdsa'"
277#endif
Juan Castillo212f7382015-12-15 16:37:57 +0000278 },
279 {
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100280 { "key-size", required_argument, NULL, 'b' },
281 "Key size (for supported algorithms)."
282 },
283 {
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800284 { "hash-alg", required_argument, NULL, 's' },
285 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
286 },
287 {
Juan Castillo212f7382015-12-15 16:37:57 +0000288 { "save-keys", no_argument, NULL, 'k' },
289 "Save key pairs into files. Filenames must be provided"
290 },
291 {
292 { "new-keys", no_argument, NULL, 'n' },
293 "Generate new key pairs if no key files are provided"
294 },
295 {
296 { "print-cert", no_argument, NULL, 'p' },
297 "Print the certificates in the standard output"
298 }
299};
300
Juan Castillo11abdcd2014-10-21 11:30:42 +0100301int main(int argc, char *argv[])
302{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900303 STACK_OF(X509_EXTENSION) * sk;
Michalis Pappas38628942017-10-06 16:11:44 +0800304 X509_EXTENSION *cert_ext = NULL;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900305 ext_t *ext;
306 key_t *key;
307 cert_t *cert;
308 FILE *file;
Juan Castillo43529982016-01-22 11:05:24 +0000309 int i, j, ext_nid, nvctr;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100310 int c, opt_idx = 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100311 const struct option *cmd_opt;
312 const char *cur_opt;
Juan Castillof9f39c32015-06-01 16:34:23 +0100313 unsigned int err_code;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800314 unsigned char md[SHA512_DIGEST_LENGTH];
315 unsigned int md_len;
Juan Castilloac402932015-03-05 14:30:00 +0000316 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100317
318 NOTICE("CoT Generation Tool: %s\n", build_msg);
319 NOTICE("Target platform: %s\n", platform_msg);
320
Juan Castillof9f39c32015-06-01 16:34:23 +0100321 /* Set default options */
322 key_alg = KEY_ALG_RSA;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800323 hash_alg = HASH_ALG_SHA256;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100324 key_size = -1;
Juan Castillof9f39c32015-06-01 16:34:23 +0100325
Juan Castillo1218dd52015-07-03 16:23:16 +0100326 /* Add common command line options */
Juan Castillo212f7382015-12-15 16:37:57 +0000327 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
328 cmd_opt_add(&common_cmd_opt[i]);
329 }
Juan Castillo1218dd52015-07-03 16:23:16 +0100330
331 /* Initialize the certificates */
332 if (cert_init() != 0) {
333 ERROR("Cannot initialize certificates\n");
334 exit(1);
335 }
336
337 /* Initialize the keys */
338 if (key_init() != 0) {
339 ERROR("Cannot initialize keys\n");
340 exit(1);
341 }
342
343 /* Initialize the new types and register OIDs for the extensions */
344 if (ext_init() != 0) {
Sandrine Bailleux0d11b482020-01-15 11:01:25 +0100345 ERROR("Cannot initialize extensions\n");
Juan Castillo1218dd52015-07-03 16:23:16 +0100346 exit(1);
347 }
348
349 /* Get the command line options populated during the initialization */
350 cmd_opt = cmd_opt_get_array();
351
Juan Castillo11abdcd2014-10-21 11:30:42 +0100352 while (1) {
353 /* getopt_long stores the option index here. */
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100354 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100355
356 /* Detect the end of the options. */
357 if (c == -1) {
358 break;
359 }
360
361 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100362 case 'a':
363 key_alg = get_key_alg(optarg);
364 if (key_alg < 0) {
365 ERROR("Invalid key algorithm '%s'\n", optarg);
366 exit(1);
367 }
368 break;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100369 case 'b':
370 key_size = get_key_size(optarg);
371 if (key_size <= 0) {
372 ERROR("Invalid key size '%s'\n", optarg);
373 exit(1);
374 }
375 break;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100376 case 'h':
Juan Castillo1218dd52015-07-03 16:23:16 +0100377 print_help(argv[0], cmd_opt);
Roberto Vargas58a5b2b2018-06-27 08:23:22 +0100378 exit(0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100379 case 'k':
380 save_keys = 1;
381 break;
382 case 'n':
383 new_keys = 1;
384 break;
385 case 'p':
386 print_cert = 1;
387 break;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800388 case 's':
389 hash_alg = get_hash_alg(optarg);
390 if (hash_alg < 0) {
391 ERROR("Invalid hash algorithm '%s'\n", optarg);
392 exit(1);
393 }
394 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100395 case CMD_OPT_EXT:
396 cur_opt = cmd_opt_get_name(opt_idx);
397 ext = ext_get_by_opt(cur_opt);
Juan Castillo43529982016-01-22 11:05:24 +0000398 ext->arg = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100399 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100400 case CMD_OPT_KEY:
401 cur_opt = cmd_opt_get_name(opt_idx);
402 key = key_get_by_opt(cur_opt);
403 key->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100404 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100405 case CMD_OPT_CERT:
406 cur_opt = cmd_opt_get_name(opt_idx);
407 cert = cert_get_by_opt(cur_opt);
408 cert->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100409 break;
410 case '?':
411 default:
Juan Castillo212f7382015-12-15 16:37:57 +0000412 print_help(argv[0], cmd_opt);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100413 exit(1);
414 }
415 }
416
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100417 /* Select a reasonable default key-size */
418 if (key_size == -1) {
419 key_size = KEY_SIZES[key_alg][0];
420 }
421
Juan Castillo11abdcd2014-10-21 11:30:42 +0100422 /* Check command line arguments */
423 check_cmd_params();
424
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800425 /* Indicate SHA as image hash algorithm in the certificate
Juan Castilloac402932015-03-05 14:30:00 +0000426 * extension */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800427 if (hash_alg == HASH_ALG_SHA384) {
428 md_info = EVP_sha384();
429 md_len = SHA384_DIGEST_LENGTH;
430 } else if (hash_alg == HASH_ALG_SHA512) {
431 md_info = EVP_sha512();
432 md_len = SHA512_DIGEST_LENGTH;
433 } else {
434 md_info = EVP_sha256();
435 md_len = SHA256_DIGEST_LENGTH;
436 }
Juan Castilloac402932015-03-05 14:30:00 +0000437
Juan Castillo11abdcd2014-10-21 11:30:42 +0100438 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100439 for (i = 0 ; i < num_keys ; i++) {
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400440#if !USING_OPENSSL3
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900441 if (!key_new(&keys[i])) {
442 ERROR("Failed to allocate key container\n");
443 exit(1);
444 }
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400445#endif
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900446
Juan Castillof9f39c32015-06-01 16:34:23 +0100447 /* First try to load the key from disk */
Sandrine Bailleuxea9f2f52023-10-16 14:52:06 +0200448 err_code = key_load(&keys[i]);
449 if (err_code == KEY_ERR_NONE) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100450 /* Key loaded successfully */
451 continue;
452 }
453
454 /* Key not loaded. Check the error code */
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900455 if (err_code == KEY_ERR_LOAD) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100456 /* File exists, but it does not contain a valid private
457 * key. Abort. */
458 ERROR("Error loading '%s'\n", keys[i].fn);
459 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100460 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100461
462 /* File does not exist, could not be opened or no filename was
463 * given */
464 if (new_keys) {
465 /* Try to create a new key */
466 NOTICE("Creating new key for '%s'\n", keys[i].desc);
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100467 if (!key_create(&keys[i], key_alg, key_size)) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100468 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100469 exit(1);
470 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100471 } else {
472 if (err_code == KEY_ERR_OPEN) {
473 ERROR("Error opening '%s'\n", keys[i].fn);
474 } else {
475 ERROR("Key '%s' not specified\n", keys[i].desc);
476 }
477 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100478 }
479 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100480
Juan Castilloe6d30e92015-06-12 11:27:59 +0100481 /* Create the certificates */
482 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100483
Juan Castilloe6d30e92015-06-12 11:27:59 +0100484 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100485
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000486 if (cert->fn == NULL) {
487 /* Certificate not requested. Skip to the next one */
488 continue;
489 }
490
Juan Castilloe6d30e92015-06-12 11:27:59 +0100491 /* Create a new stack of extensions. This stack will be used
492 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100493 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100494
Juan Castilloe6d30e92015-06-12 11:27:59 +0100495 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100496
Juan Castilloe6d30e92015-06-12 11:27:59 +0100497 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100498
Juan Castilloe6d30e92015-06-12 11:27:59 +0100499 /* Get OpenSSL internal ID for this extension */
500 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100501
Juan Castilloe6d30e92015-06-12 11:27:59 +0100502 /*
503 * Three types of extensions are currently supported:
504 * - EXT_TYPE_NVCOUNTER
505 * - EXT_TYPE_HASH
506 * - EXT_TYPE_PKEY
507 */
508 switch (ext->type) {
509 case EXT_TYPE_NVCOUNTER:
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600510 if (ext->optional && ext->arg == NULL) {
511 /* Skip this NVCounter */
512 continue;
513 } else {
514 /* Checked by `check_cmd_params` */
515 assert(ext->arg != NULL);
Yatharth Kochar79f86402016-06-22 14:49:27 +0100516 nvctr = atoi(ext->arg);
517 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000518 EXT_CRIT, nvctr));
Yatharth Kochar79f86402016-06-22 14:49:27 +0100519 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100520 break;
521 case EXT_TYPE_HASH:
Juan Castillo43529982016-01-22 11:05:24 +0000522 if (ext->arg == NULL) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100523 if (ext->optional) {
524 /* Include a hash filled with zeros */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800525 memset(md, 0x0, SHA512_DIGEST_LENGTH);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100526 } else {
527 /* Do not include this hash in the certificate */
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600528 continue;
Yatharth Kochar5752b592015-08-21 15:30:55 +0100529 }
530 } else {
531 /* Calculate the hash of the file */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800532 if (!sha_file(hash_alg, ext->arg, md)) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100533 ERROR("Cannot calculate hash of %s\n",
Juan Castillo43529982016-01-22 11:05:24 +0000534 ext->arg);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100535 exit(1);
536 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100537 }
538 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
539 EXT_CRIT, md_info, md,
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800540 md_len));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100541 break;
542 case EXT_TYPE_PKEY:
543 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000544 EXT_CRIT, keys[ext->attr.key].key));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100545 break;
546 default:
Juan Castillo43529982016-01-22 11:05:24 +0000547 ERROR("Unknown extension type '%d' in %s\n",
548 ext->type, cert->cn);
Juan Castilloe6d30e92015-06-12 11:27:59 +0100549 exit(1);
550 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100551
Juan Castilloe6d30e92015-06-12 11:27:59 +0100552 /* Push the extension into the stack */
553 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100554 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100555
Soby Mathew2fd70f62017-08-31 11:50:29 +0100556 /* Create certificate. Signed with corresponding key */
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000557 if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100558 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100559 exit(1);
560 }
561
Jimmy Brisson63d06932020-07-24 14:31:48 -0500562 for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
563 cert_ext = sk_X509_EXTENSION_pop(sk)) {
564 X509_EXTENSION_free(cert_ext);
565 }
566
Juan Castillo11abdcd2014-10-21 11:30:42 +0100567 sk_X509_EXTENSION_free(sk);
568 }
569
Juan Castillo11abdcd2014-10-21 11:30:42 +0100570
571 /* Print the certificates */
572 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100573 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100574 if (!certs[i].x) {
575 continue;
576 }
577 printf("\n\n=====================================\n\n");
578 X509_print_fp(stdout, certs[i].x);
579 }
580 }
581
582 /* Save created certificates to files */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100583 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100584 if (certs[i].x && certs[i].fn) {
585 file = fopen(certs[i].fn, "w");
586 if (file != NULL) {
587 i2d_X509_fp(file, certs[i].x);
588 fclose(file);
589 } else {
590 ERROR("Cannot create file %s\n", certs[i].fn);
591 }
592 }
593 }
594
595 /* Save keys */
596 if (save_keys) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100597 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100598 if (!key_store(&keys[i])) {
599 ERROR("Cannot save %s\n", keys[i].desc);
600 }
601 }
602 }
603
Jimmy Brisson53287962020-07-27 10:43:40 -0500604 /* If we got here, then we must have filled the key array completely.
605 * We can then safely call free on all of the keys in the array
606 */
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400607 key_cleanup();
Jimmy Brisson53287962020-07-27 10:43:40 -0500608
Juan Castillo11abdcd2014-10-21 11:30:42 +0100609#ifndef OPENSSL_NO_ENGINE
610 ENGINE_cleanup();
611#endif
612 CRYPTO_cleanup_all_ex_data();
613
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500614
615 /* We allocated strings through strdup, so now we have to free them */
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500616
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400617 ext_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500618
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400619 cert_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500620
Juan Castillo11abdcd2014-10-21 11:30:42 +0100621 return 0;
622}