blob: 4a36ee8f710dcd2a0c0606ceb683c5dbc0771e05 [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
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <openssl/conf.h>
12#include <openssl/err.h>
Soby Mathewd5b22d32017-05-22 16:12:33 +010013#include <openssl/opensslv.h>
Juan Castillo11abdcd2014-10-21 11:30:42 +010014#include <openssl/pem.h>
15#include <openssl/sha.h>
16#include <openssl/x509v3.h>
17
18#include "cert.h"
Juan Castillo1218dd52015-07-03 16:23:16 +010019#include "cmd_opt.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010020#include "debug.h"
21#include "key.h"
Juan Castillo11abdcd2014-10-21 11:30:42 +010022#include "sha.h"
23
24#define SERIAL_RAND_BITS 64
25
Pankaj Guptadd906e62020-12-09 14:02:38 +053026cert_t *certs;
27unsigned int num_certs;
28
Juan Castillo11abdcd2014-10-21 11:30:42 +010029int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
30{
31 BIGNUM *btmp;
32 int ret = 0;
33 if (b)
34 btmp = b;
35 else
36 btmp = BN_new();
37
38 if (!btmp)
39 return 0;
40
Juan Pablo Conde3539c742022-10-25 19:41:02 -040041#if USING_OPENSSL3
Juan Pablo Conde7275a5a2022-03-02 18:10:08 -050042 if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
Juan Pablo Conde3539c742022-10-25 19:41:02 -040043#else
44 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
45#endif
Juan Castillo11abdcd2014-10-21 11:30:42 +010046 goto error;
47 if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
48 goto error;
49
50 ret = 1;
51
52error:
53
54 if (!b)
55 BN_free(btmp);
56
57 return ret;
58}
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080059const EVP_MD *get_digest(int alg)
60{
61 switch (alg) {
62 case HASH_ALG_SHA256:
63 return EVP_sha256();
64 case HASH_ALG_SHA384:
65 return EVP_sha384();
66 case HASH_ALG_SHA512:
67 return EVP_sha512();
68 default:
69 return NULL;
70 }
71}
Juan Castillo11abdcd2014-10-21 11:30:42 +010072
73int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
74{
75 X509_EXTENSION *ex;
76 X509V3_CTX ctx;
77
78 /* No configuration database */
79 X509V3_set_ctx_nodb(&ctx);
80
81 /* Set issuer and subject certificates in the context */
82 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
83 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
84 if (!ex) {
85 ERR_print_errors_fp(stdout);
86 return 0;
87 }
88
89 X509_add_ext(subject, ex, -1);
90 X509_EXTENSION_free(ex);
91
92 return 1;
93}
94
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080095int cert_new(
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080096 int md_alg,
97 cert_t *cert,
98 int days,
99 int ca,
100 STACK_OF(X509_EXTENSION) * sk)
Juan Castillo11abdcd2014-10-21 11:30:42 +0100101{
Juan Castilloe6d30e92015-06-12 11:27:59 +0100102 EVP_PKEY *pkey = keys[cert->key].key;
103 cert_t *issuer_cert = &certs[cert->issuer];
104 EVP_PKEY *ikey = keys[issuer_cert->key].key;
105 X509 *issuer = issuer_cert->x;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900106 X509 *x;
107 X509_EXTENSION *ex;
108 X509_NAME *name;
109 ASN1_INTEGER *sno;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100110 int i, num, rc = 0;
Michalis Pappas38628942017-10-06 16:11:44 +0800111 EVP_MD_CTX *mdCtx;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100112 EVP_PKEY_CTX *pKeyCtx = NULL;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100113
114 /* Create the certificate structure */
115 x = X509_new();
116 if (!x) {
117 return 0;
118 }
119
120 /* If we do not have a key, use the issuer key (the certificate will
121 * become self signed). This happens in content certificates. */
122 if (!pkey) {
123 pkey = ikey;
124 }
125
126 /* If we do not have an issuer certificate, use our own (the certificate
127 * will become self signed) */
128 if (!issuer) {
129 issuer = x;
130 }
131
Michalis Pappas38628942017-10-06 16:11:44 +0800132 mdCtx = EVP_MD_CTX_create();
133 if (mdCtx == NULL) {
134 ERR_print_errors_fp(stdout);
135 goto END;
136 }
Soby Mathew2fd70f62017-08-31 11:50:29 +0100137
138 /* Sign the certificate with the issuer key */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800139 if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
Soby Mathewd5b22d32017-05-22 16:12:33 +0100140 ERR_print_errors_fp(stdout);
141 goto END;
142 }
143
Soby Mathew2fd70f62017-08-31 11:50:29 +0100144 /*
Justin Chadwell3168a202019-09-09 15:24:31 +0100145 * Set additional parameters if issuing public key algorithm is RSA.
146 * This is not required for ECDSA.
Soby Mathew2fd70f62017-08-31 11:50:29 +0100147 */
Justin Chadwell3168a202019-09-09 15:24:31 +0100148 if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100149 if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
150 ERR_print_errors_fp(stdout);
151 goto END;
152 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100153
Donald Chanb12b3ae2024-04-08 15:23:43 -0700154 if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, EVP_MD_size(get_digest(md_alg)))) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100155 ERR_print_errors_fp(stdout);
156 goto END;
157 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100158
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800159 if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100160 ERR_print_errors_fp(stdout);
161 goto END;
162 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100163 }
164
Juan Castillo11abdcd2014-10-21 11:30:42 +0100165 /* x509.v3 */
166 X509_set_version(x, 2);
167
168 /* Random serial number */
169 sno = ASN1_INTEGER_new();
170 rand_serial(NULL, sno);
171 X509_set_serialNumber(x, sno);
172 ASN1_INTEGER_free(sno);
173
174 X509_gmtime_adj(X509_get_notBefore(x), 0);
175 X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
176 X509_set_pubkey(x, pkey);
177
178 /* Subject name */
179 name = X509_get_subject_name(x);
180 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
181 (const unsigned char *)cert->cn, -1, -1, 0);
182 X509_set_subject_name(x, name);
183
184 /* Issuer name */
185 name = X509_get_issuer_name(x);
186 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
Juan Castilloe6d30e92015-06-12 11:27:59 +0100187 (const unsigned char *)issuer_cert->cn, -1, -1, 0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100188 X509_set_issuer_name(x, name);
189
190 /* Add various extensions: standard extensions */
191 cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
192 cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
193 if (ca) {
194 cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
195 cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
196 } else {
197 cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
198 }
199
200 /* Add custom extensions */
201 if (sk != NULL) {
202 num = sk_X509_EXTENSION_num(sk);
203 for (i = 0; i < num; i++) {
204 ex = sk_X509_EXTENSION_value(sk, i);
205 X509_add_ext(x, ex, -1);
206 }
207 }
208
Michalis Pappas38628942017-10-06 16:11:44 +0800209 if (!X509_sign_ctx(x, mdCtx)) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100210 ERR_print_errors_fp(stdout);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100211 goto END;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100212 }
213
Soby Mathewd5b22d32017-05-22 16:12:33 +0100214 /* X509 certificate signed successfully */
215 rc = 1;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100216 cert->x = x;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100217
218END:
Michalis Pappas38628942017-10-06 16:11:44 +0800219 EVP_MD_CTX_destroy(mdCtx);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100220 return rc;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100221}
Juan Castillo1218dd52015-07-03 16:23:16 +0100222
223int cert_init(void)
224{
Juan Castillo212f7382015-12-15 16:37:57 +0000225 cmd_opt_t cmd_opt;
Juan Castillo1218dd52015-07-03 16:23:16 +0100226 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100227 unsigned int i;
228
Pankaj Guptadd906e62020-12-09 14:02:38 +0530229 certs = malloc((num_def_certs * sizeof(def_certs[0]))
230#ifdef PDEF_CERTS
231 + (num_pdef_certs * sizeof(pdef_certs[0]))
232#endif
233 );
234 if (certs == NULL) {
235 ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
236 return 1;
237 }
238
239 memcpy(&certs[0], &def_certs[0],
240 (num_def_certs * sizeof(def_certs[0])));
241
242#ifdef PDEF_CERTS
243 memcpy(&certs[num_def_certs], &pdef_certs[0],
244 (num_pdef_certs * sizeof(pdef_certs[0])));
245
246 num_certs = num_def_certs + num_pdef_certs;
247#else
248 num_certs = num_def_certs;
249#endif
250
Juan Castillo1218dd52015-07-03 16:23:16 +0100251 for (i = 0; i < num_certs; i++) {
252 cert = &certs[i];
Juan Castillo212f7382015-12-15 16:37:57 +0000253 cmd_opt.long_opt.name = cert->opt;
254 cmd_opt.long_opt.has_arg = required_argument;
255 cmd_opt.long_opt.flag = NULL;
256 cmd_opt.long_opt.val = CMD_OPT_CERT;
257 cmd_opt.help_msg = cert->help_msg;
258 cmd_opt_add(&cmd_opt);
Juan Castillo1218dd52015-07-03 16:23:16 +0100259 }
260
Juan Castillo212f7382015-12-15 16:37:57 +0000261 return 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100262}
263
264cert_t *cert_get_by_opt(const char *opt)
265{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900266 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100267 unsigned int i;
268
269 for (i = 0; i < num_certs; i++) {
270 cert = &certs[i];
271 if (0 == strcmp(cert->opt, opt)) {
272 return cert;
273 }
274 }
275
276 return NULL;
277}
Juan Pablo Conde3539c742022-10-25 19:41:02 -0400278
279void cert_cleanup(void)
280{
281 unsigned int i;
282
283 for (i = 0; i < num_certs; i++) {
284 if (certs[i].fn != NULL) {
285 void *ptr = (void *)certs[i].fn;
286
287 certs[i].fn = NULL;
288 free(ptr);
289 }
290 }
291 free(certs);
292}
293