cert.c 5.59 KB
Newer Older
1
/*
2
 * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
7
8
9
10
11
12
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/conf.h>
#include <openssl/err.h>
13
#include <openssl/opensslv.h>
14
15
16
17
18
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/x509v3.h>

#include "cert.h"
19
#include "cmd_opt.h"
20
21
22
23
24
#include "debug.h"
#include "key.h"
#include "sha.h"

#define SERIAL_RAND_BITS	64
25
#define RSA_SALT_LEN		32
26

27
28
29
cert_t *certs;
unsigned int num_certs;

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
{
	BIGNUM *btmp;
	int ret = 0;
	if (b)
		btmp = b;
	else
		btmp = BN_new();

	if (!btmp)
		return 0;

	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
		goto error;
	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
		goto error;

	ret = 1;

error:

	if (!b)
		BN_free(btmp);

	return ret;
}
56
57
58
59
60
61
62
63
64
65
66
67
68
const EVP_MD *get_digest(int alg)
{
	switch (alg) {
	case HASH_ALG_SHA256:
		return EVP_sha256();
	case HASH_ALG_SHA384:
		return EVP_sha384();
	case HASH_ALG_SHA512:
		return EVP_sha512();
	default:
		return NULL;
	}
}
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
{
	X509_EXTENSION *ex;
	X509V3_CTX ctx;

	/* No configuration database */
	X509V3_set_ctx_nodb(&ctx);

	/* Set issuer and subject certificates in the context */
	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
	if (!ex) {
		ERR_print_errors_fp(stdout);
		return 0;
	}

	X509_add_ext(subject, ex, -1);
	X509_EXTENSION_free(ex);

	return 1;
}

92
93
94
95
96
97
int cert_new(
	int md_alg,
	cert_t *cert,
	int days,
	int ca,
	STACK_OF(X509_EXTENSION) * sk)
98
{
99
100
101
102
	EVP_PKEY *pkey = keys[cert->key].key;
	cert_t *issuer_cert = &certs[cert->issuer];
	EVP_PKEY *ikey = keys[issuer_cert->key].key;
	X509 *issuer = issuer_cert->x;
103
104
105
106
	X509 *x;
	X509_EXTENSION *ex;
	X509_NAME *name;
	ASN1_INTEGER *sno;
107
	int i, num, rc = 0;
108
	EVP_MD_CTX *mdCtx;
109
	EVP_PKEY_CTX *pKeyCtx = NULL;
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

	/* Create the certificate structure */
	x = X509_new();
	if (!x) {
		return 0;
	}

	/* If we do not have a key, use the issuer key (the certificate will
	 * become self signed). This happens in content certificates. */
	if (!pkey) {
		pkey = ikey;
	}

	/* If we do not have an issuer certificate, use our own (the certificate
	 * will become self signed) */
	if (!issuer) {
		issuer = x;
	}

129
130
131
132
133
	mdCtx = EVP_MD_CTX_create();
	if (mdCtx == NULL) {
		ERR_print_errors_fp(stdout);
		goto END;
	}
134

135
	/* Sign the certificate with the issuer key */
136
	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
137
138
139
140
		ERR_print_errors_fp(stdout);
		goto END;
	}

141
	/*
142
143
	 * Set additional parameters if issuing public key algorithm is RSA.
	 * This is not required for ECDSA.
144
	 */
145
	if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
146
147
148
149
150
151
152
153
154
155
		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
			ERR_print_errors_fp(stdout);
			goto END;
		}

		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
			ERR_print_errors_fp(stdout);
			goto END;
		}

156
		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
157
158
159
			ERR_print_errors_fp(stdout);
			goto END;
		}
160
161
	}

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
	/* x509.v3 */
	X509_set_version(x, 2);

	/* Random serial number */
	sno = ASN1_INTEGER_new();
	rand_serial(NULL, sno);
	X509_set_serialNumber(x, sno);
	ASN1_INTEGER_free(sno);

	X509_gmtime_adj(X509_get_notBefore(x), 0);
	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
	X509_set_pubkey(x, pkey);

	/* Subject name */
	name = X509_get_subject_name(x);
	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
			(const unsigned char *)cert->cn, -1, -1, 0);
	X509_set_subject_name(x, name);

	/* Issuer name */
	name = X509_get_issuer_name(x);
	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
184
			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
	X509_set_issuer_name(x, name);

	/* Add various extensions: standard extensions */
	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
	if (ca) {
		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
	} else {
		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
	}

	/* Add custom extensions */
	if (sk != NULL) {
		num = sk_X509_EXTENSION_num(sk);
		for (i = 0; i < num; i++) {
			ex = sk_X509_EXTENSION_value(sk, i);
			X509_add_ext(x, ex, -1);
		}
	}

206
	if (!X509_sign_ctx(x, mdCtx)) {
207
		ERR_print_errors_fp(stdout);
208
		goto END;
209
210
	}

211
212
	/* X509 certificate signed successfully */
	rc = 1;
213
	cert->x = x;
214
215

END:
216
	EVP_MD_CTX_destroy(mdCtx);
217
	return rc;
218
}
219
220
221

int cert_init(void)
{
222
	cmd_opt_t cmd_opt;
223
224
225
	cert_t *cert;
	unsigned int i;

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
	certs = malloc((num_def_certs * sizeof(def_certs[0]))
#ifdef PDEF_CERTS
		       + (num_pdef_certs * sizeof(pdef_certs[0]))
#endif
		       );
	if (certs == NULL) {
		ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
		return 1;
	}

	memcpy(&certs[0], &def_certs[0],
	       (num_def_certs * sizeof(def_certs[0])));

#ifdef PDEF_CERTS
	memcpy(&certs[num_def_certs], &pdef_certs[0],
	       (num_pdef_certs * sizeof(pdef_certs[0])));

	num_certs = num_def_certs + num_pdef_certs;
#else
	num_certs = num_def_certs;
#endif

248
249
	for (i = 0; i < num_certs; i++) {
		cert = &certs[i];
250
251
252
253
254
255
		cmd_opt.long_opt.name = cert->opt;
		cmd_opt.long_opt.has_arg = required_argument;
		cmd_opt.long_opt.flag = NULL;
		cmd_opt.long_opt.val = CMD_OPT_CERT;
		cmd_opt.help_msg = cert->help_msg;
		cmd_opt_add(&cmd_opt);
256
257
	}

258
	return 0;
259
260
261
262
}

cert_t *cert_get_by_opt(const char *opt)
{
263
	cert_t *cert;
264
265
266
267
268
269
270
271
272
273
274
	unsigned int i;

	for (i = 0; i < num_certs; i++) {
		cert = &certs[i];
		if (0 == strcmp(cert->opt, opt)) {
			return cert;
		}
	}

	return NULL;
}