• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include <openssl/conf.h>
12 #include <openssl/err.h>
13 #include <openssl/opensslv.h>
14 #include <openssl/pem.h>
15 #include <openssl/sha.h>
16 #include <openssl/x509v3.h>
17 
18 #include "cert.h"
19 #include "cmd_opt.h"
20 #include "debug.h"
21 #include "key.h"
22 #include "sha.h"
23 
24 #define SERIAL_RAND_BITS	64
25 #define RSA_SALT_LEN		32
26 
rand_serial(BIGNUM * b,ASN1_INTEGER * ai)27 int 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 
46 error:
47 
48 	if (!b)
49 		BN_free(btmp);
50 
51 	return ret;
52 }
get_digest(int alg)53 const 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 }
66 
cert_add_ext(X509 * issuer,X509 * subject,int nid,char * value)67 int 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 
cert_new(int md_alg,cert_t * cert,int days,int ca,STACK_OF (X509_EXTENSION)* sk)89 int cert_new(
90 	int md_alg,
91 	cert_t *cert,
92 	int days,
93 	int ca,
94 	STACK_OF(X509_EXTENSION) * sk)
95 {
96 	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;
100 	X509 *x;
101 	X509_EXTENSION *ex;
102 	X509_NAME *name;
103 	ASN1_INTEGER *sno;
104 	int i, num, rc = 0;
105 	EVP_MD_CTX *mdCtx;
106 	EVP_PKEY_CTX *pKeyCtx = NULL;
107 
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 
126 	mdCtx = EVP_MD_CTX_create();
127 	if (mdCtx == NULL) {
128 		ERR_print_errors_fp(stdout);
129 		goto END;
130 	}
131 
132 	/* Sign the certificate with the issuer key */
133 	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
134 		ERR_print_errors_fp(stdout);
135 		goto END;
136 	}
137 
138 	/*
139 	 * Set additional parameters if issuing public key algorithm is RSA.
140 	 * This is not required for ECDSA.
141 	 */
142 	if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
143 		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
144 			ERR_print_errors_fp(stdout);
145 			goto END;
146 		}
147 
148 		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
149 			ERR_print_errors_fp(stdout);
150 			goto END;
151 		}
152 
153 		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
154 			ERR_print_errors_fp(stdout);
155 			goto END;
156 		}
157 	}
158 
159 	/* 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,
181 			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
182 	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 
203 	if (!X509_sign_ctx(x, mdCtx)) {
204 		ERR_print_errors_fp(stdout);
205 		goto END;
206 	}
207 
208 	/* X509 certificate signed successfully */
209 	rc = 1;
210 	cert->x = x;
211 
212 END:
213 	EVP_MD_CTX_destroy(mdCtx);
214 	return rc;
215 }
216 
cert_init(void)217 int cert_init(void)
218 {
219 	cmd_opt_t cmd_opt;
220 	cert_t *cert;
221 	unsigned int i;
222 
223 	for (i = 0; i < num_certs; i++) {
224 		cert = &certs[i];
225 		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);
231 	}
232 
233 	return 0;
234 }
235 
cert_get_by_opt(const char * opt)236 cert_t *cert_get_by_opt(const char *opt)
237 {
238 	cert_t *cert;
239 	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 }
250