blob: 4b35d735aa782e70dead05c7e24f2862ce3138b7 [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
Pankaj Guptadd906e62020-12-09 14:02:38 +05302 * Copyright (c) 2015-2021, 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
Soby Mathewd5b22d32017-05-22 16:12:33 +010025#define RSA_SALT_LEN 32
Juan Castillo11abdcd2014-10-21 11:30:42 +010026
Pankaj Guptadd906e62020-12-09 14:02:38 +053027cert_t *certs;
28unsigned int num_certs;
29
Juan Castillo11abdcd2014-10-21 11:30:42 +010030int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
31{
32 BIGNUM *btmp;
33 int ret = 0;
34 if (b)
35 btmp = b;
36 else
37 btmp = BN_new();
38
39 if (!btmp)
40 return 0;
41
42 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
43 goto error;
44 if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
45 goto error;
46
47 ret = 1;
48
49error:
50
51 if (!b)
52 BN_free(btmp);
53
54 return ret;
55}
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080056const EVP_MD *get_digest(int alg)
57{
58 switch (alg) {
59 case HASH_ALG_SHA256:
60 return EVP_sha256();
61 case HASH_ALG_SHA384:
62 return EVP_sha384();
63 case HASH_ALG_SHA512:
64 return EVP_sha512();
65 default:
66 return NULL;
67 }
68}
Juan Castillo11abdcd2014-10-21 11:30:42 +010069
70int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
71{
72 X509_EXTENSION *ex;
73 X509V3_CTX ctx;
74
75 /* No configuration database */
76 X509V3_set_ctx_nodb(&ctx);
77
78 /* Set issuer and subject certificates in the context */
79 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
80 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
81 if (!ex) {
82 ERR_print_errors_fp(stdout);
83 return 0;
84 }
85
86 X509_add_ext(subject, ex, -1);
87 X509_EXTENSION_free(ex);
88
89 return 1;
90}
91
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080092int cert_new(
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080093 int md_alg,
94 cert_t *cert,
95 int days,
96 int ca,
97 STACK_OF(X509_EXTENSION) * sk)
Juan Castillo11abdcd2014-10-21 11:30:42 +010098{
Juan Castilloe6d30e92015-06-12 11:27:59 +010099 EVP_PKEY *pkey = keys[cert->key].key;
100 cert_t *issuer_cert = &certs[cert->issuer];
101 EVP_PKEY *ikey = keys[issuer_cert->key].key;
102 X509 *issuer = issuer_cert->x;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900103 X509 *x;
104 X509_EXTENSION *ex;
105 X509_NAME *name;
106 ASN1_INTEGER *sno;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100107 int i, num, rc = 0;
Michalis Pappas38628942017-10-06 16:11:44 +0800108 EVP_MD_CTX *mdCtx;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100109 EVP_PKEY_CTX *pKeyCtx = NULL;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100110
111 /* Create the certificate structure */
112 x = X509_new();
113 if (!x) {
114 return 0;
115 }
116
117 /* If we do not have a key, use the issuer key (the certificate will
118 * become self signed). This happens in content certificates. */
119 if (!pkey) {
120 pkey = ikey;
121 }
122
123 /* If we do not have an issuer certificate, use our own (the certificate
124 * will become self signed) */
125 if (!issuer) {
126 issuer = x;
127 }
128
Michalis Pappas38628942017-10-06 16:11:44 +0800129 mdCtx = EVP_MD_CTX_create();
130 if (mdCtx == NULL) {
131 ERR_print_errors_fp(stdout);
132 goto END;
133 }
Soby Mathew2fd70f62017-08-31 11:50:29 +0100134
135 /* Sign the certificate with the issuer key */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800136 if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
Soby Mathewd5b22d32017-05-22 16:12:33 +0100137 ERR_print_errors_fp(stdout);
138 goto END;
139 }
140
Soby Mathew2fd70f62017-08-31 11:50:29 +0100141 /*
Justin Chadwell3168a202019-09-09 15:24:31 +0100142 * Set additional parameters if issuing public key algorithm is RSA.
143 * This is not required for ECDSA.
Soby Mathew2fd70f62017-08-31 11:50:29 +0100144 */
Justin Chadwell3168a202019-09-09 15:24:31 +0100145 if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100146 if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
147 ERR_print_errors_fp(stdout);
148 goto END;
149 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100150
Soby Mathew2fd70f62017-08-31 11:50:29 +0100151 if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
152 ERR_print_errors_fp(stdout);
153 goto END;
154 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100155
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800156 if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100157 ERR_print_errors_fp(stdout);
158 goto END;
159 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100160 }
161
Juan Castillo11abdcd2014-10-21 11:30:42 +0100162 /* x509.v3 */
163 X509_set_version(x, 2);
164
165 /* Random serial number */
166 sno = ASN1_INTEGER_new();
167 rand_serial(NULL, sno);
168 X509_set_serialNumber(x, sno);
169 ASN1_INTEGER_free(sno);
170
171 X509_gmtime_adj(X509_get_notBefore(x), 0);
172 X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
173 X509_set_pubkey(x, pkey);
174
175 /* Subject name */
176 name = X509_get_subject_name(x);
177 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
178 (const unsigned char *)cert->cn, -1, -1, 0);
179 X509_set_subject_name(x, name);
180
181 /* Issuer name */
182 name = X509_get_issuer_name(x);
183 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
Juan Castilloe6d30e92015-06-12 11:27:59 +0100184 (const unsigned char *)issuer_cert->cn, -1, -1, 0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100185 X509_set_issuer_name(x, name);
186
187 /* Add various extensions: standard extensions */
188 cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
189 cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
190 if (ca) {
191 cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
192 cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
193 } else {
194 cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
195 }
196
197 /* Add custom extensions */
198 if (sk != NULL) {
199 num = sk_X509_EXTENSION_num(sk);
200 for (i = 0; i < num; i++) {
201 ex = sk_X509_EXTENSION_value(sk, i);
202 X509_add_ext(x, ex, -1);
203 }
204 }
205
Michalis Pappas38628942017-10-06 16:11:44 +0800206 if (!X509_sign_ctx(x, mdCtx)) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100207 ERR_print_errors_fp(stdout);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100208 goto END;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100209 }
210
Soby Mathewd5b22d32017-05-22 16:12:33 +0100211 /* X509 certificate signed successfully */
212 rc = 1;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100213 cert->x = x;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100214
215END:
Michalis Pappas38628942017-10-06 16:11:44 +0800216 EVP_MD_CTX_destroy(mdCtx);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100217 return rc;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100218}
Juan Castillo1218dd52015-07-03 16:23:16 +0100219
220int cert_init(void)
221{
Juan Castillo212f7382015-12-15 16:37:57 +0000222 cmd_opt_t cmd_opt;
Juan Castillo1218dd52015-07-03 16:23:16 +0100223 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100224 unsigned int i;
225
Pankaj Guptadd906e62020-12-09 14:02:38 +0530226 certs = malloc((num_def_certs * sizeof(def_certs[0]))
227#ifdef PDEF_CERTS
228 + (num_pdef_certs * sizeof(pdef_certs[0]))
229#endif
230 );
231 if (certs == NULL) {
232 ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
233 return 1;
234 }
235
236 memcpy(&certs[0], &def_certs[0],
237 (num_def_certs * sizeof(def_certs[0])));
238
239#ifdef PDEF_CERTS
240 memcpy(&certs[num_def_certs], &pdef_certs[0],
241 (num_pdef_certs * sizeof(pdef_certs[0])));
242
243 num_certs = num_def_certs + num_pdef_certs;
244#else
245 num_certs = num_def_certs;
246#endif
247
Juan Castillo1218dd52015-07-03 16:23:16 +0100248 for (i = 0; i < num_certs; i++) {
249 cert = &certs[i];
Juan Castillo212f7382015-12-15 16:37:57 +0000250 cmd_opt.long_opt.name = cert->opt;
251 cmd_opt.long_opt.has_arg = required_argument;
252 cmd_opt.long_opt.flag = NULL;
253 cmd_opt.long_opt.val = CMD_OPT_CERT;
254 cmd_opt.help_msg = cert->help_msg;
255 cmd_opt_add(&cmd_opt);
Juan Castillo1218dd52015-07-03 16:23:16 +0100256 }
257
Juan Castillo212f7382015-12-15 16:37:57 +0000258 return 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100259}
260
261cert_t *cert_get_by_opt(const char *opt)
262{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900263 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100264 unsigned int i;
265
266 for (i = 0; i < num_certs; i++) {
267 cert = &certs[i];
268 if (0 == strcmp(cert->opt, opt)) {
269 return cert;
270 }
271 }
272
273 return NULL;
274}