blob: f10a768bc216170131409ab5013b72b5d14d41eb [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",
88 [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular",
89 [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted",
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' },
Lionel Debievefefeffb2022-11-14 11:03:42 +0100272 "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, " \
273 "'ecdsa', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'"
Juan Castillo212f7382015-12-15 16:37:57 +0000274 },
275 {
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100276 { "key-size", required_argument, NULL, 'b' },
277 "Key size (for supported algorithms)."
278 },
279 {
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800280 { "hash-alg", required_argument, NULL, 's' },
281 "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
282 },
283 {
Juan Castillo212f7382015-12-15 16:37:57 +0000284 { "save-keys", no_argument, NULL, 'k' },
285 "Save key pairs into files. Filenames must be provided"
286 },
287 {
288 { "new-keys", no_argument, NULL, 'n' },
289 "Generate new key pairs if no key files are provided"
290 },
291 {
292 { "print-cert", no_argument, NULL, 'p' },
293 "Print the certificates in the standard output"
294 }
295};
296
Juan Castillo11abdcd2014-10-21 11:30:42 +0100297int main(int argc, char *argv[])
298{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900299 STACK_OF(X509_EXTENSION) * sk;
Michalis Pappas38628942017-10-06 16:11:44 +0800300 X509_EXTENSION *cert_ext = NULL;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900301 ext_t *ext;
302 key_t *key;
303 cert_t *cert;
304 FILE *file;
Juan Castillo43529982016-01-22 11:05:24 +0000305 int i, j, ext_nid, nvctr;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100306 int c, opt_idx = 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100307 const struct option *cmd_opt;
308 const char *cur_opt;
Juan Castillof9f39c32015-06-01 16:34:23 +0100309 unsigned int err_code;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800310 unsigned char md[SHA512_DIGEST_LENGTH];
311 unsigned int md_len;
Juan Castilloac402932015-03-05 14:30:00 +0000312 const EVP_MD *md_info;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100313
314 NOTICE("CoT Generation Tool: %s\n", build_msg);
315 NOTICE("Target platform: %s\n", platform_msg);
316
Juan Castillof9f39c32015-06-01 16:34:23 +0100317 /* Set default options */
318 key_alg = KEY_ALG_RSA;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800319 hash_alg = HASH_ALG_SHA256;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100320 key_size = -1;
Juan Castillof9f39c32015-06-01 16:34:23 +0100321
Juan Castillo1218dd52015-07-03 16:23:16 +0100322 /* Add common command line options */
Juan Castillo212f7382015-12-15 16:37:57 +0000323 for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
324 cmd_opt_add(&common_cmd_opt[i]);
325 }
Juan Castillo1218dd52015-07-03 16:23:16 +0100326
327 /* Initialize the certificates */
328 if (cert_init() != 0) {
329 ERROR("Cannot initialize certificates\n");
330 exit(1);
331 }
332
333 /* Initialize the keys */
334 if (key_init() != 0) {
335 ERROR("Cannot initialize keys\n");
336 exit(1);
337 }
338
339 /* Initialize the new types and register OIDs for the extensions */
340 if (ext_init() != 0) {
Sandrine Bailleux0d11b482020-01-15 11:01:25 +0100341 ERROR("Cannot initialize extensions\n");
Juan Castillo1218dd52015-07-03 16:23:16 +0100342 exit(1);
343 }
344
345 /* Get the command line options populated during the initialization */
346 cmd_opt = cmd_opt_get_array();
347
Juan Castillo11abdcd2014-10-21 11:30:42 +0100348 while (1) {
349 /* getopt_long stores the option index here. */
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100350 c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100351
352 /* Detect the end of the options. */
353 if (c == -1) {
354 break;
355 }
356
357 switch (c) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100358 case 'a':
359 key_alg = get_key_alg(optarg);
360 if (key_alg < 0) {
361 ERROR("Invalid key algorithm '%s'\n", optarg);
362 exit(1);
363 }
364 break;
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100365 case 'b':
366 key_size = get_key_size(optarg);
367 if (key_size <= 0) {
368 ERROR("Invalid key size '%s'\n", optarg);
369 exit(1);
370 }
371 break;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100372 case 'h':
Juan Castillo1218dd52015-07-03 16:23:16 +0100373 print_help(argv[0], cmd_opt);
Roberto Vargas58a5b2b2018-06-27 08:23:22 +0100374 exit(0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100375 case 'k':
376 save_keys = 1;
377 break;
378 case 'n':
379 new_keys = 1;
380 break;
381 case 'p':
382 print_cert = 1;
383 break;
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800384 case 's':
385 hash_alg = get_hash_alg(optarg);
386 if (hash_alg < 0) {
387 ERROR("Invalid hash algorithm '%s'\n", optarg);
388 exit(1);
389 }
390 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100391 case CMD_OPT_EXT:
392 cur_opt = cmd_opt_get_name(opt_idx);
393 ext = ext_get_by_opt(cur_opt);
Juan Castillo43529982016-01-22 11:05:24 +0000394 ext->arg = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100395 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100396 case CMD_OPT_KEY:
397 cur_opt = cmd_opt_get_name(opt_idx);
398 key = key_get_by_opt(cur_opt);
399 key->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100400 break;
Juan Castillo1218dd52015-07-03 16:23:16 +0100401 case CMD_OPT_CERT:
402 cur_opt = cmd_opt_get_name(opt_idx);
403 cert = cert_get_by_opt(cur_opt);
404 cert->fn = strdup(optarg);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100405 break;
406 case '?':
407 default:
Juan Castillo212f7382015-12-15 16:37:57 +0000408 print_help(argv[0], cmd_opt);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100409 exit(1);
410 }
411 }
412
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100413 /* Select a reasonable default key-size */
414 if (key_size == -1) {
415 key_size = KEY_SIZES[key_alg][0];
416 }
417
Juan Castillo11abdcd2014-10-21 11:30:42 +0100418 /* Check command line arguments */
419 check_cmd_params();
420
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800421 /* Indicate SHA as image hash algorithm in the certificate
Juan Castilloac402932015-03-05 14:30:00 +0000422 * extension */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800423 if (hash_alg == HASH_ALG_SHA384) {
424 md_info = EVP_sha384();
425 md_len = SHA384_DIGEST_LENGTH;
426 } else if (hash_alg == HASH_ALG_SHA512) {
427 md_info = EVP_sha512();
428 md_len = SHA512_DIGEST_LENGTH;
429 } else {
430 md_info = EVP_sha256();
431 md_len = SHA256_DIGEST_LENGTH;
432 }
Juan Castilloac402932015-03-05 14:30:00 +0000433
Juan Castillo11abdcd2014-10-21 11:30:42 +0100434 /* Load private keys from files (or generate new ones) */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100435 for (i = 0 ; i < num_keys ; i++) {
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400436#if !USING_OPENSSL3
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900437 if (!key_new(&keys[i])) {
438 ERROR("Failed to allocate key container\n");
439 exit(1);
440 }
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400441#endif
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900442
Juan Castillof9f39c32015-06-01 16:34:23 +0100443 /* First try to load the key from disk */
Sandrine Bailleuxea9f2f52023-10-16 14:52:06 +0200444 err_code = key_load(&keys[i]);
445 if (err_code == KEY_ERR_NONE) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100446 /* Key loaded successfully */
447 continue;
448 }
449
450 /* Key not loaded. Check the error code */
Masahiro Yamadabccb1092017-02-06 21:15:01 +0900451 if (err_code == KEY_ERR_LOAD) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100452 /* File exists, but it does not contain a valid private
453 * key. Abort. */
454 ERROR("Error loading '%s'\n", keys[i].fn);
455 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100456 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100457
458 /* File does not exist, could not be opened or no filename was
459 * given */
460 if (new_keys) {
461 /* Try to create a new key */
462 NOTICE("Creating new key for '%s'\n", keys[i].desc);
Justin Chadwellfebe86c2019-07-29 17:13:45 +0100463 if (!key_create(&keys[i], key_alg, key_size)) {
Juan Castillof9f39c32015-06-01 16:34:23 +0100464 ERROR("Error creating key '%s'\n", keys[i].desc);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100465 exit(1);
466 }
Juan Castillof9f39c32015-06-01 16:34:23 +0100467 } else {
468 if (err_code == KEY_ERR_OPEN) {
469 ERROR("Error opening '%s'\n", keys[i].fn);
470 } else {
471 ERROR("Key '%s' not specified\n", keys[i].desc);
472 }
473 exit(1);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100474 }
475 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100476
Juan Castilloe6d30e92015-06-12 11:27:59 +0100477 /* Create the certificates */
478 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100479
Juan Castilloe6d30e92015-06-12 11:27:59 +0100480 cert = &certs[i];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100481
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000482 if (cert->fn == NULL) {
483 /* Certificate not requested. Skip to the next one */
484 continue;
485 }
486
Juan Castilloe6d30e92015-06-12 11:27:59 +0100487 /* Create a new stack of extensions. This stack will be used
488 * to create the certificate */
Juan Castillo11abdcd2014-10-21 11:30:42 +0100489 CHECK_NULL(sk, sk_X509_EXTENSION_new_null());
Juan Castillo11abdcd2014-10-21 11:30:42 +0100490
Juan Castilloe6d30e92015-06-12 11:27:59 +0100491 for (j = 0 ; j < cert->num_ext ; j++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100492
Juan Castilloe6d30e92015-06-12 11:27:59 +0100493 ext = &extensions[cert->ext[j]];
Juan Castillo11abdcd2014-10-21 11:30:42 +0100494
Juan Castilloe6d30e92015-06-12 11:27:59 +0100495 /* Get OpenSSL internal ID for this extension */
496 CHECK_OID(ext_nid, ext->oid);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100497
Juan Castilloe6d30e92015-06-12 11:27:59 +0100498 /*
499 * Three types of extensions are currently supported:
500 * - EXT_TYPE_NVCOUNTER
501 * - EXT_TYPE_HASH
502 * - EXT_TYPE_PKEY
503 */
504 switch (ext->type) {
505 case EXT_TYPE_NVCOUNTER:
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600506 if (ext->optional && ext->arg == NULL) {
507 /* Skip this NVCounter */
508 continue;
509 } else {
510 /* Checked by `check_cmd_params` */
511 assert(ext->arg != NULL);
Yatharth Kochar79f86402016-06-22 14:49:27 +0100512 nvctr = atoi(ext->arg);
513 CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000514 EXT_CRIT, nvctr));
Yatharth Kochar79f86402016-06-22 14:49:27 +0100515 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100516 break;
517 case EXT_TYPE_HASH:
Juan Castillo43529982016-01-22 11:05:24 +0000518 if (ext->arg == NULL) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100519 if (ext->optional) {
520 /* Include a hash filled with zeros */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800521 memset(md, 0x0, SHA512_DIGEST_LENGTH);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100522 } else {
523 /* Do not include this hash in the certificate */
Jimmy Brissonc913fa62021-01-20 15:34:51 -0600524 continue;
Yatharth Kochar5752b592015-08-21 15:30:55 +0100525 }
526 } else {
527 /* Calculate the hash of the file */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800528 if (!sha_file(hash_alg, ext->arg, md)) {
Yatharth Kochar5752b592015-08-21 15:30:55 +0100529 ERROR("Cannot calculate hash of %s\n",
Juan Castillo43529982016-01-22 11:05:24 +0000530 ext->arg);
Yatharth Kochar5752b592015-08-21 15:30:55 +0100531 exit(1);
532 }
Juan Castilloe6d30e92015-06-12 11:27:59 +0100533 }
534 CHECK_NULL(cert_ext, ext_new_hash(ext_nid,
535 EXT_CRIT, md_info, md,
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800536 md_len));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100537 break;
538 case EXT_TYPE_PKEY:
539 CHECK_NULL(cert_ext, ext_new_key(ext_nid,
Juan Castillo43529982016-01-22 11:05:24 +0000540 EXT_CRIT, keys[ext->attr.key].key));
Juan Castilloe6d30e92015-06-12 11:27:59 +0100541 break;
542 default:
Juan Castillo43529982016-01-22 11:05:24 +0000543 ERROR("Unknown extension type '%d' in %s\n",
544 ext->type, cert->cn);
Juan Castilloe6d30e92015-06-12 11:27:59 +0100545 exit(1);
546 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100547
Juan Castilloe6d30e92015-06-12 11:27:59 +0100548 /* Push the extension into the stack */
549 sk_X509_EXTENSION_push(sk, cert_ext);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100550 }
Juan Castillo11abdcd2014-10-21 11:30:42 +0100551
Soby Mathew2fd70f62017-08-31 11:50:29 +0100552 /* Create certificate. Signed with corresponding key */
Manish V Badarkhe2b7e70e2021-01-26 10:55:49 +0000553 if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100554 ERROR("Cannot create %s\n", cert->cn);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100555 exit(1);
556 }
557
Jimmy Brisson63d06932020-07-24 14:31:48 -0500558 for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL;
559 cert_ext = sk_X509_EXTENSION_pop(sk)) {
560 X509_EXTENSION_free(cert_ext);
561 }
562
Juan Castillo11abdcd2014-10-21 11:30:42 +0100563 sk_X509_EXTENSION_free(sk);
564 }
565
Juan Castillo11abdcd2014-10-21 11:30:42 +0100566
567 /* Print the certificates */
568 if (print_cert) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100569 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100570 if (!certs[i].x) {
571 continue;
572 }
573 printf("\n\n=====================================\n\n");
574 X509_print_fp(stdout, certs[i].x);
575 }
576 }
577
578 /* Save created certificates to files */
Juan Castilloe6d30e92015-06-12 11:27:59 +0100579 for (i = 0 ; i < num_certs ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100580 if (certs[i].x && certs[i].fn) {
581 file = fopen(certs[i].fn, "w");
582 if (file != NULL) {
583 i2d_X509_fp(file, certs[i].x);
584 fclose(file);
585 } else {
586 ERROR("Cannot create file %s\n", certs[i].fn);
587 }
588 }
589 }
590
591 /* Save keys */
592 if (save_keys) {
Juan Castilloe6d30e92015-06-12 11:27:59 +0100593 for (i = 0 ; i < num_keys ; i++) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100594 if (!key_store(&keys[i])) {
595 ERROR("Cannot save %s\n", keys[i].desc);
596 }
597 }
598 }
599
Jimmy Brisson53287962020-07-27 10:43:40 -0500600 /* If we got here, then we must have filled the key array completely.
601 * We can then safely call free on all of the keys in the array
602 */
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400603 key_cleanup();
Jimmy Brisson53287962020-07-27 10:43:40 -0500604
Juan Castillo11abdcd2014-10-21 11:30:42 +0100605#ifndef OPENSSL_NO_ENGINE
606 ENGINE_cleanup();
607#endif
608 CRYPTO_cleanup_all_ex_data();
609
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500610
611 /* We allocated strings through strdup, so now we have to free them */
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500612
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400613 ext_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500614
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400615 cert_cleanup();
Jimmy Brisson54db69e2020-07-27 11:23:20 -0500616
Juan Castillo11abdcd2014-10-21 11:30:42 +0100617 return 0;
618}