blob: 153f5557df276b4921ad6a800c20ab96a105b2f7 [file] [log] [blame]
Juan Castillo11abdcd2014-10-21 11:30:42 +01001/*
Sandrine Bailleux0b144832020-01-07 15:12:08 +01002 * Copyright (c) 2015-2020, 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
27int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
28{
29 BIGNUM *btmp;
30 int ret = 0;
31 if (b)
32 btmp = b;
33 else
34 btmp = BN_new();
35
36 if (!btmp)
37 return 0;
38
39 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
40 goto error;
41 if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
42 goto error;
43
44 ret = 1;
45
46error:
47
48 if (!b)
49 BN_free(btmp);
50
51 return ret;
52}
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080053const EVP_MD *get_digest(int alg)
54{
55 switch (alg) {
56 case HASH_ALG_SHA256:
57 return EVP_sha256();
58 case HASH_ALG_SHA384:
59 return EVP_sha384();
60 case HASH_ALG_SHA512:
61 return EVP_sha512();
62 default:
63 return NULL;
64 }
65}
Juan Castillo11abdcd2014-10-21 11:30:42 +010066
67int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
68{
69 X509_EXTENSION *ex;
70 X509V3_CTX ctx;
71
72 /* No configuration database */
73 X509V3_set_ctx_nodb(&ctx);
74
75 /* Set issuer and subject certificates in the context */
76 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
77 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
78 if (!ex) {
79 ERR_print_errors_fp(stdout);
80 return 0;
81 }
82
83 X509_add_ext(subject, ex, -1);
84 X509_EXTENSION_free(ex);
85
86 return 1;
87}
88
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080089int cert_new(
Qixiang Xu76a5a9b2017-11-09 13:51:58 +080090 int md_alg,
91 cert_t *cert,
92 int days,
93 int ca,
94 STACK_OF(X509_EXTENSION) * sk)
Juan Castillo11abdcd2014-10-21 11:30:42 +010095{
Juan Castilloe6d30e92015-06-12 11:27:59 +010096 EVP_PKEY *pkey = keys[cert->key].key;
97 cert_t *issuer_cert = &certs[cert->issuer];
98 EVP_PKEY *ikey = keys[issuer_cert->key].key;
99 X509 *issuer = issuer_cert->x;
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900100 X509 *x;
101 X509_EXTENSION *ex;
102 X509_NAME *name;
103 ASN1_INTEGER *sno;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100104 int i, num, rc = 0;
Michalis Pappas38628942017-10-06 16:11:44 +0800105 EVP_MD_CTX *mdCtx;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100106 EVP_PKEY_CTX *pKeyCtx = NULL;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100107
108 /* Create the certificate structure */
109 x = X509_new();
110 if (!x) {
111 return 0;
112 }
113
114 /* If we do not have a key, use the issuer key (the certificate will
115 * become self signed). This happens in content certificates. */
116 if (!pkey) {
117 pkey = ikey;
118 }
119
120 /* If we do not have an issuer certificate, use our own (the certificate
121 * will become self signed) */
122 if (!issuer) {
123 issuer = x;
124 }
125
Michalis Pappas38628942017-10-06 16:11:44 +0800126 mdCtx = EVP_MD_CTX_create();
127 if (mdCtx == NULL) {
128 ERR_print_errors_fp(stdout);
129 goto END;
130 }
Soby Mathew2fd70f62017-08-31 11:50:29 +0100131
132 /* Sign the certificate with the issuer key */
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800133 if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
Soby Mathewd5b22d32017-05-22 16:12:33 +0100134 ERR_print_errors_fp(stdout);
135 goto END;
136 }
137
Soby Mathew2fd70f62017-08-31 11:50:29 +0100138 /*
Justin Chadwell3168a202019-09-09 15:24:31 +0100139 * Set additional parameters if issuing public key algorithm is RSA.
140 * This is not required for ECDSA.
Soby Mathew2fd70f62017-08-31 11:50:29 +0100141 */
Justin Chadwell3168a202019-09-09 15:24:31 +0100142 if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100143 if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
144 ERR_print_errors_fp(stdout);
145 goto END;
146 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100147
Soby Mathew2fd70f62017-08-31 11:50:29 +0100148 if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
149 ERR_print_errors_fp(stdout);
150 goto END;
151 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100152
Qixiang Xu76a5a9b2017-11-09 13:51:58 +0800153 if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
Soby Mathew2fd70f62017-08-31 11:50:29 +0100154 ERR_print_errors_fp(stdout);
155 goto END;
156 }
Soby Mathewd5b22d32017-05-22 16:12:33 +0100157 }
158
Juan Castillo11abdcd2014-10-21 11:30:42 +0100159 /* x509.v3 */
160 X509_set_version(x, 2);
161
162 /* Random serial number */
163 sno = ASN1_INTEGER_new();
164 rand_serial(NULL, sno);
165 X509_set_serialNumber(x, sno);
166 ASN1_INTEGER_free(sno);
167
168 X509_gmtime_adj(X509_get_notBefore(x), 0);
169 X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
170 X509_set_pubkey(x, pkey);
171
172 /* Subject name */
173 name = X509_get_subject_name(x);
174 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
175 (const unsigned char *)cert->cn, -1, -1, 0);
176 X509_set_subject_name(x, name);
177
178 /* Issuer name */
179 name = X509_get_issuer_name(x);
180 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
Juan Castilloe6d30e92015-06-12 11:27:59 +0100181 (const unsigned char *)issuer_cert->cn, -1, -1, 0);
Juan Castillo11abdcd2014-10-21 11:30:42 +0100182 X509_set_issuer_name(x, name);
183
184 /* Add various extensions: standard extensions */
185 cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
186 cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
187 if (ca) {
188 cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
189 cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
190 } else {
191 cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
192 }
193
194 /* Add custom extensions */
195 if (sk != NULL) {
196 num = sk_X509_EXTENSION_num(sk);
197 for (i = 0; i < num; i++) {
198 ex = sk_X509_EXTENSION_value(sk, i);
199 X509_add_ext(x, ex, -1);
200 }
201 }
202
Michalis Pappas38628942017-10-06 16:11:44 +0800203 if (!X509_sign_ctx(x, mdCtx)) {
Juan Castillo11abdcd2014-10-21 11:30:42 +0100204 ERR_print_errors_fp(stdout);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100205 goto END;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100206 }
207
Soby Mathewd5b22d32017-05-22 16:12:33 +0100208 /* X509 certificate signed successfully */
209 rc = 1;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100210 cert->x = x;
Soby Mathewd5b22d32017-05-22 16:12:33 +0100211
212END:
Michalis Pappas38628942017-10-06 16:11:44 +0800213 EVP_MD_CTX_destroy(mdCtx);
Soby Mathewd5b22d32017-05-22 16:12:33 +0100214 return rc;
Juan Castillo11abdcd2014-10-21 11:30:42 +0100215}
Juan Castillo1218dd52015-07-03 16:23:16 +0100216
217int cert_init(void)
218{
Juan Castillo212f7382015-12-15 16:37:57 +0000219 cmd_opt_t cmd_opt;
Juan Castillo1218dd52015-07-03 16:23:16 +0100220 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100221 unsigned int i;
222
223 for (i = 0; i < num_certs; i++) {
224 cert = &certs[i];
Juan Castillo212f7382015-12-15 16:37:57 +0000225 cmd_opt.long_opt.name = cert->opt;
226 cmd_opt.long_opt.has_arg = required_argument;
227 cmd_opt.long_opt.flag = NULL;
228 cmd_opt.long_opt.val = CMD_OPT_CERT;
229 cmd_opt.help_msg = cert->help_msg;
230 cmd_opt_add(&cmd_opt);
Juan Castillo1218dd52015-07-03 16:23:16 +0100231 }
232
Juan Castillo212f7382015-12-15 16:37:57 +0000233 return 0;
Juan Castillo1218dd52015-07-03 16:23:16 +0100234}
235
236cert_t *cert_get_by_opt(const char *opt)
237{
Masahiro Yamada48cb5e52017-02-06 19:47:44 +0900238 cert_t *cert;
Juan Castillo1218dd52015-07-03 16:23:16 +0100239 unsigned int i;
240
241 for (i = 0; i < num_certs; i++) {
242 cert = &certs[i];
243 if (0 == strcmp(cert->opt, opt)) {
244 return cert;
245 }
246 }
247
248 return NULL;
249}