xref: /rk3399_ARM-atf/tools/cert_create/src/cert.c (revision cf2dd17ddda2f44f5dedddcaf48300d16358597a)
16f971622SJuan Castillo /*
2*cf2dd17dSJuan Pablo Conde  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
36f971622SJuan Castillo  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
56f971622SJuan Castillo  */
66f971622SJuan Castillo 
76f971622SJuan Castillo #include <stdio.h>
86f971622SJuan Castillo #include <stdlib.h>
96f971622SJuan Castillo #include <string.h>
106f971622SJuan Castillo 
116f971622SJuan Castillo #include <openssl/conf.h>
126f971622SJuan Castillo #include <openssl/err.h>
131f33ad4eSSoby Mathew #include <openssl/opensslv.h>
146f971622SJuan Castillo #include <openssl/pem.h>
156f971622SJuan Castillo #include <openssl/sha.h>
166f971622SJuan Castillo #include <openssl/x509v3.h>
176f971622SJuan Castillo 
186f971622SJuan Castillo #include "cert.h"
19ad2c1a9aSJuan Castillo #include "cmd_opt.h"
206f971622SJuan Castillo #include "debug.h"
216f971622SJuan Castillo #include "key.h"
226f971622SJuan Castillo #include "sha.h"
236f971622SJuan Castillo 
246f971622SJuan Castillo #define SERIAL_RAND_BITS	64
251f33ad4eSSoby Mathew #define RSA_SALT_LEN		32
266f971622SJuan Castillo 
27b94bf967SPankaj Gupta cert_t *certs;
28b94bf967SPankaj Gupta unsigned int num_certs;
29b94bf967SPankaj Gupta 
306f971622SJuan Castillo int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
316f971622SJuan Castillo {
326f971622SJuan Castillo 	BIGNUM *btmp;
336f971622SJuan Castillo 	int ret = 0;
346f971622SJuan Castillo 	if (b)
356f971622SJuan Castillo 		btmp = b;
366f971622SJuan Castillo 	else
376f971622SJuan Castillo 		btmp = BN_new();
386f971622SJuan Castillo 
396f971622SJuan Castillo 	if (!btmp)
406f971622SJuan Castillo 		return 0;
416f971622SJuan Castillo 
42*cf2dd17dSJuan Pablo Conde #if USING_OPENSSL3
439bc52d33SJuan Pablo Conde 	if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
44*cf2dd17dSJuan Pablo Conde #else
45*cf2dd17dSJuan Pablo Conde 	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
46*cf2dd17dSJuan Pablo Conde #endif
476f971622SJuan Castillo 		goto error;
486f971622SJuan Castillo 	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
496f971622SJuan Castillo 		goto error;
506f971622SJuan Castillo 
516f971622SJuan Castillo 	ret = 1;
526f971622SJuan Castillo 
536f971622SJuan Castillo error:
546f971622SJuan Castillo 
556f971622SJuan Castillo 	if (!b)
566f971622SJuan Castillo 		BN_free(btmp);
576f971622SJuan Castillo 
586f971622SJuan Castillo 	return ret;
596f971622SJuan Castillo }
602972247cSQixiang Xu const EVP_MD *get_digest(int alg)
612972247cSQixiang Xu {
622972247cSQixiang Xu 	switch (alg) {
632972247cSQixiang Xu 	case HASH_ALG_SHA256:
642972247cSQixiang Xu 		return EVP_sha256();
652972247cSQixiang Xu 	case HASH_ALG_SHA384:
662972247cSQixiang Xu 		return EVP_sha384();
672972247cSQixiang Xu 	case HASH_ALG_SHA512:
682972247cSQixiang Xu 		return EVP_sha512();
692972247cSQixiang Xu 	default:
702972247cSQixiang Xu 		return NULL;
712972247cSQixiang Xu 	}
722972247cSQixiang Xu }
736f971622SJuan Castillo 
746f971622SJuan Castillo int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
756f971622SJuan Castillo {
766f971622SJuan Castillo 	X509_EXTENSION *ex;
776f971622SJuan Castillo 	X509V3_CTX ctx;
786f971622SJuan Castillo 
796f971622SJuan Castillo 	/* No configuration database */
806f971622SJuan Castillo 	X509V3_set_ctx_nodb(&ctx);
816f971622SJuan Castillo 
826f971622SJuan Castillo 	/* Set issuer and subject certificates in the context */
836f971622SJuan Castillo 	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
846f971622SJuan Castillo 	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
856f971622SJuan Castillo 	if (!ex) {
866f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
876f971622SJuan Castillo 		return 0;
886f971622SJuan Castillo 	}
896f971622SJuan Castillo 
906f971622SJuan Castillo 	X509_add_ext(subject, ex, -1);
916f971622SJuan Castillo 	X509_EXTENSION_free(ex);
926f971622SJuan Castillo 
936f971622SJuan Castillo 	return 1;
946f971622SJuan Castillo }
956f971622SJuan Castillo 
962972247cSQixiang Xu int cert_new(
972972247cSQixiang Xu 	int md_alg,
982972247cSQixiang Xu 	cert_t *cert,
992972247cSQixiang Xu 	int days,
1002972247cSQixiang Xu 	int ca,
1012972247cSQixiang Xu 	STACK_OF(X509_EXTENSION) * sk)
1026f971622SJuan Castillo {
10355e291a4SJuan Castillo 	EVP_PKEY *pkey = keys[cert->key].key;
10455e291a4SJuan Castillo 	cert_t *issuer_cert = &certs[cert->issuer];
10555e291a4SJuan Castillo 	EVP_PKEY *ikey = keys[issuer_cert->key].key;
10655e291a4SJuan Castillo 	X509 *issuer = issuer_cert->x;
107c893c733SMasahiro Yamada 	X509 *x;
108c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
109c893c733SMasahiro Yamada 	X509_NAME *name;
110c893c733SMasahiro Yamada 	ASN1_INTEGER *sno;
1111f33ad4eSSoby Mathew 	int i, num, rc = 0;
112742c4e14SMichalis Pappas 	EVP_MD_CTX *mdCtx;
1131f33ad4eSSoby Mathew 	EVP_PKEY_CTX *pKeyCtx = NULL;
1146f971622SJuan Castillo 
1156f971622SJuan Castillo 	/* Create the certificate structure */
1166f971622SJuan Castillo 	x = X509_new();
1176f971622SJuan Castillo 	if (!x) {
1186f971622SJuan Castillo 		return 0;
1196f971622SJuan Castillo 	}
1206f971622SJuan Castillo 
1216f971622SJuan Castillo 	/* If we do not have a key, use the issuer key (the certificate will
1226f971622SJuan Castillo 	 * become self signed). This happens in content certificates. */
1236f971622SJuan Castillo 	if (!pkey) {
1246f971622SJuan Castillo 		pkey = ikey;
1256f971622SJuan Castillo 	}
1266f971622SJuan Castillo 
1276f971622SJuan Castillo 	/* If we do not have an issuer certificate, use our own (the certificate
1286f971622SJuan Castillo 	 * will become self signed) */
1296f971622SJuan Castillo 	if (!issuer) {
1306f971622SJuan Castillo 		issuer = x;
1316f971622SJuan Castillo 	}
1326f971622SJuan Castillo 
133742c4e14SMichalis Pappas 	mdCtx = EVP_MD_CTX_create();
134742c4e14SMichalis Pappas 	if (mdCtx == NULL) {
135742c4e14SMichalis Pappas 		ERR_print_errors_fp(stdout);
136742c4e14SMichalis Pappas 		goto END;
137742c4e14SMichalis Pappas 	}
138a8eb286aSSoby Mathew 
139a8eb286aSSoby Mathew 	/* Sign the certificate with the issuer key */
1402972247cSQixiang Xu 	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
1411f33ad4eSSoby Mathew 		ERR_print_errors_fp(stdout);
1421f33ad4eSSoby Mathew 		goto END;
1431f33ad4eSSoby Mathew 	}
1441f33ad4eSSoby Mathew 
145a8eb286aSSoby Mathew 	/*
1466a415a50SJustin Chadwell 	 * Set additional parameters if issuing public key algorithm is RSA.
1476a415a50SJustin Chadwell 	 * This is not required for ECDSA.
148a8eb286aSSoby Mathew 	 */
1496a415a50SJustin Chadwell 	if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
1501f33ad4eSSoby Mathew 		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
1511f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1521f33ad4eSSoby Mathew 			goto END;
1531f33ad4eSSoby Mathew 		}
1541f33ad4eSSoby Mathew 
1551f33ad4eSSoby Mathew 		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
1561f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1571f33ad4eSSoby Mathew 			goto END;
1581f33ad4eSSoby Mathew 		}
1591f33ad4eSSoby Mathew 
1602972247cSQixiang Xu 		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
1611f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1621f33ad4eSSoby Mathew 			goto END;
1631f33ad4eSSoby Mathew 		}
164a8eb286aSSoby Mathew 	}
1651f33ad4eSSoby Mathew 
1666f971622SJuan Castillo 	/* x509.v3 */
1676f971622SJuan Castillo 	X509_set_version(x, 2);
1686f971622SJuan Castillo 
1696f971622SJuan Castillo 	/* Random serial number */
1706f971622SJuan Castillo 	sno = ASN1_INTEGER_new();
1716f971622SJuan Castillo 	rand_serial(NULL, sno);
1726f971622SJuan Castillo 	X509_set_serialNumber(x, sno);
1736f971622SJuan Castillo 	ASN1_INTEGER_free(sno);
1746f971622SJuan Castillo 
1756f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notBefore(x), 0);
1766f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
1776f971622SJuan Castillo 	X509_set_pubkey(x, pkey);
1786f971622SJuan Castillo 
1796f971622SJuan Castillo 	/* Subject name */
1806f971622SJuan Castillo 	name = X509_get_subject_name(x);
1816f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
1826f971622SJuan Castillo 			(const unsigned char *)cert->cn, -1, -1, 0);
1836f971622SJuan Castillo 	X509_set_subject_name(x, name);
1846f971622SJuan Castillo 
1856f971622SJuan Castillo 	/* Issuer name */
1866f971622SJuan Castillo 	name = X509_get_issuer_name(x);
1876f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
18855e291a4SJuan Castillo 			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
1896f971622SJuan Castillo 	X509_set_issuer_name(x, name);
1906f971622SJuan Castillo 
1916f971622SJuan Castillo 	/* Add various extensions: standard extensions */
1926f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
1936f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
1946f971622SJuan Castillo 	if (ca) {
1956f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
1966f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
1976f971622SJuan Castillo 	} else {
1986f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
1996f971622SJuan Castillo 	}
2006f971622SJuan Castillo 
2016f971622SJuan Castillo 	/* Add custom extensions */
2026f971622SJuan Castillo 	if (sk != NULL) {
2036f971622SJuan Castillo 		num = sk_X509_EXTENSION_num(sk);
2046f971622SJuan Castillo 		for (i = 0; i < num; i++) {
2056f971622SJuan Castillo 			ex = sk_X509_EXTENSION_value(sk, i);
2066f971622SJuan Castillo 			X509_add_ext(x, ex, -1);
2076f971622SJuan Castillo 		}
2086f971622SJuan Castillo 	}
2096f971622SJuan Castillo 
210742c4e14SMichalis Pappas 	if (!X509_sign_ctx(x, mdCtx)) {
2116f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
2121f33ad4eSSoby Mathew 		goto END;
2136f971622SJuan Castillo 	}
2146f971622SJuan Castillo 
2151f33ad4eSSoby Mathew 	/* X509 certificate signed successfully */
2161f33ad4eSSoby Mathew 	rc = 1;
2176f971622SJuan Castillo 	cert->x = x;
2181f33ad4eSSoby Mathew 
2191f33ad4eSSoby Mathew END:
220742c4e14SMichalis Pappas 	EVP_MD_CTX_destroy(mdCtx);
2211f33ad4eSSoby Mathew 	return rc;
2226f971622SJuan Castillo }
223ad2c1a9aSJuan Castillo 
224ad2c1a9aSJuan Castillo int cert_init(void)
225ad2c1a9aSJuan Castillo {
226159807e2SJuan Castillo 	cmd_opt_t cmd_opt;
227ad2c1a9aSJuan Castillo 	cert_t *cert;
228ad2c1a9aSJuan Castillo 	unsigned int i;
229ad2c1a9aSJuan Castillo 
230b94bf967SPankaj Gupta 	certs = malloc((num_def_certs * sizeof(def_certs[0]))
231b94bf967SPankaj Gupta #ifdef PDEF_CERTS
232b94bf967SPankaj Gupta 		       + (num_pdef_certs * sizeof(pdef_certs[0]))
233b94bf967SPankaj Gupta #endif
234b94bf967SPankaj Gupta 		       );
235b94bf967SPankaj Gupta 	if (certs == NULL) {
236b94bf967SPankaj Gupta 		ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
237b94bf967SPankaj Gupta 		return 1;
238b94bf967SPankaj Gupta 	}
239b94bf967SPankaj Gupta 
240b94bf967SPankaj Gupta 	memcpy(&certs[0], &def_certs[0],
241b94bf967SPankaj Gupta 	       (num_def_certs * sizeof(def_certs[0])));
242b94bf967SPankaj Gupta 
243b94bf967SPankaj Gupta #ifdef PDEF_CERTS
244b94bf967SPankaj Gupta 	memcpy(&certs[num_def_certs], &pdef_certs[0],
245b94bf967SPankaj Gupta 	       (num_pdef_certs * sizeof(pdef_certs[0])));
246b94bf967SPankaj Gupta 
247b94bf967SPankaj Gupta 	num_certs = num_def_certs + num_pdef_certs;
248b94bf967SPankaj Gupta #else
249b94bf967SPankaj Gupta 	num_certs = num_def_certs;
250b94bf967SPankaj Gupta #endif
251b94bf967SPankaj Gupta 
252ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
253ad2c1a9aSJuan Castillo 		cert = &certs[i];
254159807e2SJuan Castillo 		cmd_opt.long_opt.name = cert->opt;
255159807e2SJuan Castillo 		cmd_opt.long_opt.has_arg = required_argument;
256159807e2SJuan Castillo 		cmd_opt.long_opt.flag = NULL;
257159807e2SJuan Castillo 		cmd_opt.long_opt.val = CMD_OPT_CERT;
258159807e2SJuan Castillo 		cmd_opt.help_msg = cert->help_msg;
259159807e2SJuan Castillo 		cmd_opt_add(&cmd_opt);
260ad2c1a9aSJuan Castillo 	}
261ad2c1a9aSJuan Castillo 
262159807e2SJuan Castillo 	return 0;
263ad2c1a9aSJuan Castillo }
264ad2c1a9aSJuan Castillo 
265ad2c1a9aSJuan Castillo cert_t *cert_get_by_opt(const char *opt)
266ad2c1a9aSJuan Castillo {
267c893c733SMasahiro Yamada 	cert_t *cert;
268ad2c1a9aSJuan Castillo 	unsigned int i;
269ad2c1a9aSJuan Castillo 
270ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
271ad2c1a9aSJuan Castillo 		cert = &certs[i];
272ad2c1a9aSJuan Castillo 		if (0 == strcmp(cert->opt, opt)) {
273ad2c1a9aSJuan Castillo 			return cert;
274ad2c1a9aSJuan Castillo 		}
275ad2c1a9aSJuan Castillo 	}
276ad2c1a9aSJuan Castillo 
277ad2c1a9aSJuan Castillo 	return NULL;
278ad2c1a9aSJuan Castillo }
279*cf2dd17dSJuan Pablo Conde 
280*cf2dd17dSJuan Pablo Conde void cert_cleanup(void)
281*cf2dd17dSJuan Pablo Conde {
282*cf2dd17dSJuan Pablo Conde 	unsigned int i;
283*cf2dd17dSJuan Pablo Conde 
284*cf2dd17dSJuan Pablo Conde 	for (i = 0; i < num_certs; i++) {
285*cf2dd17dSJuan Pablo Conde 		if (certs[i].fn != NULL) {
286*cf2dd17dSJuan Pablo Conde 			void *ptr = (void *)certs[i].fn;
287*cf2dd17dSJuan Pablo Conde 
288*cf2dd17dSJuan Pablo Conde 			certs[i].fn = NULL;
289*cf2dd17dSJuan Pablo Conde 			free(ptr);
290*cf2dd17dSJuan Pablo Conde 		}
291*cf2dd17dSJuan Pablo Conde 	}
292*cf2dd17dSJuan Pablo Conde 	free(certs);
293*cf2dd17dSJuan Pablo Conde }
294*cf2dd17dSJuan Pablo Conde 
295