xref: /rk3399_ARM-atf/tools/cert_create/src/cert.c (revision 4d2372e914a24d5a3c805352959a2fda287a44c6)
16f971622SJuan Castillo /*
2cf2dd17dSJuan 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
256f971622SJuan Castillo 
26b94bf967SPankaj Gupta cert_t *certs;
27b94bf967SPankaj Gupta unsigned int num_certs;
28b94bf967SPankaj Gupta 
rand_serial(BIGNUM * b,ASN1_INTEGER * ai)296f971622SJuan Castillo int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
306f971622SJuan Castillo {
316f971622SJuan Castillo 	BIGNUM *btmp;
326f971622SJuan Castillo 	int ret = 0;
336f971622SJuan Castillo 	if (b)
346f971622SJuan Castillo 		btmp = b;
356f971622SJuan Castillo 	else
366f971622SJuan Castillo 		btmp = BN_new();
376f971622SJuan Castillo 
386f971622SJuan Castillo 	if (!btmp)
396f971622SJuan Castillo 		return 0;
406f971622SJuan Castillo 
41cf2dd17dSJuan Pablo Conde #if USING_OPENSSL3
429bc52d33SJuan Pablo Conde 	if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
43cf2dd17dSJuan Pablo Conde #else
44cf2dd17dSJuan Pablo Conde 	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
45cf2dd17dSJuan Pablo Conde #endif
466f971622SJuan Castillo 		goto error;
476f971622SJuan Castillo 	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
486f971622SJuan Castillo 		goto error;
496f971622SJuan Castillo 
506f971622SJuan Castillo 	ret = 1;
516f971622SJuan Castillo 
526f971622SJuan Castillo error:
536f971622SJuan Castillo 
546f971622SJuan Castillo 	if (!b)
556f971622SJuan Castillo 		BN_free(btmp);
566f971622SJuan Castillo 
576f971622SJuan Castillo 	return ret;
586f971622SJuan Castillo }
get_digest(int alg)592972247cSQixiang Xu const EVP_MD *get_digest(int alg)
602972247cSQixiang Xu {
612972247cSQixiang Xu 	switch (alg) {
622972247cSQixiang Xu 	case HASH_ALG_SHA256:
632972247cSQixiang Xu 		return EVP_sha256();
642972247cSQixiang Xu 	case HASH_ALG_SHA384:
652972247cSQixiang Xu 		return EVP_sha384();
662972247cSQixiang Xu 	case HASH_ALG_SHA512:
672972247cSQixiang Xu 		return EVP_sha512();
682972247cSQixiang Xu 	default:
692972247cSQixiang Xu 		return NULL;
702972247cSQixiang Xu 	}
712972247cSQixiang Xu }
726f971622SJuan Castillo 
cert_add_ext(X509 * issuer,X509 * subject,int nid,char * value)736f971622SJuan Castillo int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
746f971622SJuan Castillo {
756f971622SJuan Castillo 	X509_EXTENSION *ex;
766f971622SJuan Castillo 	X509V3_CTX ctx;
776f971622SJuan Castillo 
786f971622SJuan Castillo 	/* No configuration database */
796f971622SJuan Castillo 	X509V3_set_ctx_nodb(&ctx);
806f971622SJuan Castillo 
816f971622SJuan Castillo 	/* Set issuer and subject certificates in the context */
826f971622SJuan Castillo 	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
836f971622SJuan Castillo 	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
846f971622SJuan Castillo 	if (!ex) {
856f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
866f971622SJuan Castillo 		return 0;
876f971622SJuan Castillo 	}
886f971622SJuan Castillo 
896f971622SJuan Castillo 	X509_add_ext(subject, ex, -1);
906f971622SJuan Castillo 	X509_EXTENSION_free(ex);
916f971622SJuan Castillo 
926f971622SJuan Castillo 	return 1;
936f971622SJuan Castillo }
946f971622SJuan Castillo 
cert_new(int md_alg,cert_t * cert,int days,int ca,STACK_OF (X509_EXTENSION)* sk)952972247cSQixiang Xu int cert_new(
962972247cSQixiang Xu 	int md_alg,
972972247cSQixiang Xu 	cert_t *cert,
982972247cSQixiang Xu 	int days,
992972247cSQixiang Xu 	int ca,
1002972247cSQixiang Xu 	STACK_OF(X509_EXTENSION) * sk)
1016f971622SJuan Castillo {
10255e291a4SJuan Castillo 	EVP_PKEY *pkey = keys[cert->key].key;
10355e291a4SJuan Castillo 	cert_t *issuer_cert = &certs[cert->issuer];
10455e291a4SJuan Castillo 	EVP_PKEY *ikey = keys[issuer_cert->key].key;
10555e291a4SJuan Castillo 	X509 *issuer = issuer_cert->x;
106c893c733SMasahiro Yamada 	X509 *x;
107c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
108c893c733SMasahiro Yamada 	X509_NAME *name;
109c893c733SMasahiro Yamada 	ASN1_INTEGER *sno;
1101f33ad4eSSoby Mathew 	int i, num, rc = 0;
111742c4e14SMichalis Pappas 	EVP_MD_CTX *mdCtx;
1121f33ad4eSSoby Mathew 	EVP_PKEY_CTX *pKeyCtx = NULL;
1136f971622SJuan Castillo 
1146f971622SJuan Castillo 	/* Create the certificate structure */
1156f971622SJuan Castillo 	x = X509_new();
1166f971622SJuan Castillo 	if (!x) {
1176f971622SJuan Castillo 		return 0;
1186f971622SJuan Castillo 	}
1196f971622SJuan Castillo 
1206f971622SJuan Castillo 	/* If we do not have a key, use the issuer key (the certificate will
1216f971622SJuan Castillo 	 * become self signed). This happens in content certificates. */
1226f971622SJuan Castillo 	if (!pkey) {
1236f971622SJuan Castillo 		pkey = ikey;
1246f971622SJuan Castillo 	}
1256f971622SJuan Castillo 
1266f971622SJuan Castillo 	/* If we do not have an issuer certificate, use our own (the certificate
1276f971622SJuan Castillo 	 * will become self signed) */
1286f971622SJuan Castillo 	if (!issuer) {
1296f971622SJuan Castillo 		issuer = x;
1306f971622SJuan Castillo 	}
1316f971622SJuan Castillo 
132742c4e14SMichalis Pappas 	mdCtx = EVP_MD_CTX_create();
133742c4e14SMichalis Pappas 	if (mdCtx == NULL) {
134742c4e14SMichalis Pappas 		ERR_print_errors_fp(stdout);
135742c4e14SMichalis Pappas 		goto END;
136742c4e14SMichalis Pappas 	}
137a8eb286aSSoby Mathew 
138a8eb286aSSoby Mathew 	/* Sign the certificate with the issuer key */
1392972247cSQixiang Xu 	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
1401f33ad4eSSoby Mathew 		ERR_print_errors_fp(stdout);
1411f33ad4eSSoby Mathew 		goto END;
1421f33ad4eSSoby Mathew 	}
1431f33ad4eSSoby Mathew 
144a8eb286aSSoby Mathew 	/*
1456a415a50SJustin Chadwell 	 * Set additional parameters if issuing public key algorithm is RSA.
1466a415a50SJustin Chadwell 	 * This is not required for ECDSA.
147a8eb286aSSoby Mathew 	 */
1486a415a50SJustin Chadwell 	if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
1491f33ad4eSSoby Mathew 		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
1501f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1511f33ad4eSSoby Mathew 			goto END;
1521f33ad4eSSoby Mathew 		}
1531f33ad4eSSoby Mathew 
154*e639ad23SDonald Chan 		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, EVP_MD_size(get_digest(md_alg)))) {
1551f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1561f33ad4eSSoby Mathew 			goto END;
1571f33ad4eSSoby Mathew 		}
1581f33ad4eSSoby Mathew 
1592972247cSQixiang Xu 		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
1601f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1611f33ad4eSSoby Mathew 			goto END;
1621f33ad4eSSoby Mathew 		}
163a8eb286aSSoby Mathew 	}
1641f33ad4eSSoby Mathew 
1656f971622SJuan Castillo 	/* x509.v3 */
1666f971622SJuan Castillo 	X509_set_version(x, 2);
1676f971622SJuan Castillo 
1686f971622SJuan Castillo 	/* Random serial number */
1696f971622SJuan Castillo 	sno = ASN1_INTEGER_new();
1706f971622SJuan Castillo 	rand_serial(NULL, sno);
1716f971622SJuan Castillo 	X509_set_serialNumber(x, sno);
1726f971622SJuan Castillo 	ASN1_INTEGER_free(sno);
1736f971622SJuan Castillo 
1746f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notBefore(x), 0);
1756f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
1766f971622SJuan Castillo 	X509_set_pubkey(x, pkey);
1776f971622SJuan Castillo 
1786f971622SJuan Castillo 	/* Subject name */
1796f971622SJuan Castillo 	name = X509_get_subject_name(x);
1806f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
1816f971622SJuan Castillo 			(const unsigned char *)cert->cn, -1, -1, 0);
1826f971622SJuan Castillo 	X509_set_subject_name(x, name);
1836f971622SJuan Castillo 
1846f971622SJuan Castillo 	/* Issuer name */
1856f971622SJuan Castillo 	name = X509_get_issuer_name(x);
1866f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
18755e291a4SJuan Castillo 			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
1886f971622SJuan Castillo 	X509_set_issuer_name(x, name);
1896f971622SJuan Castillo 
1906f971622SJuan Castillo 	/* Add various extensions: standard extensions */
1916f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
1926f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
1936f971622SJuan Castillo 	if (ca) {
1946f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
1956f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
1966f971622SJuan Castillo 	} else {
1976f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
1986f971622SJuan Castillo 	}
1996f971622SJuan Castillo 
2006f971622SJuan Castillo 	/* Add custom extensions */
2016f971622SJuan Castillo 	if (sk != NULL) {
2026f971622SJuan Castillo 		num = sk_X509_EXTENSION_num(sk);
2036f971622SJuan Castillo 		for (i = 0; i < num; i++) {
2046f971622SJuan Castillo 			ex = sk_X509_EXTENSION_value(sk, i);
2056f971622SJuan Castillo 			X509_add_ext(x, ex, -1);
2066f971622SJuan Castillo 		}
2076f971622SJuan Castillo 	}
2086f971622SJuan Castillo 
209742c4e14SMichalis Pappas 	if (!X509_sign_ctx(x, mdCtx)) {
2106f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
2111f33ad4eSSoby Mathew 		goto END;
2126f971622SJuan Castillo 	}
2136f971622SJuan Castillo 
2141f33ad4eSSoby Mathew 	/* X509 certificate signed successfully */
2151f33ad4eSSoby Mathew 	rc = 1;
2166f971622SJuan Castillo 	cert->x = x;
2171f33ad4eSSoby Mathew 
2181f33ad4eSSoby Mathew END:
219742c4e14SMichalis Pappas 	EVP_MD_CTX_destroy(mdCtx);
2201f33ad4eSSoby Mathew 	return rc;
2216f971622SJuan Castillo }
222ad2c1a9aSJuan Castillo 
cert_init(void)223ad2c1a9aSJuan Castillo int cert_init(void)
224ad2c1a9aSJuan Castillo {
225159807e2SJuan Castillo 	cmd_opt_t cmd_opt;
226ad2c1a9aSJuan Castillo 	cert_t *cert;
227ad2c1a9aSJuan Castillo 	unsigned int i;
228ad2c1a9aSJuan Castillo 
229b94bf967SPankaj Gupta 	certs = malloc((num_def_certs * sizeof(def_certs[0]))
230b94bf967SPankaj Gupta #ifdef PDEF_CERTS
231b94bf967SPankaj Gupta 		       + (num_pdef_certs * sizeof(pdef_certs[0]))
232b94bf967SPankaj Gupta #endif
233b94bf967SPankaj Gupta 		       );
234b94bf967SPankaj Gupta 	if (certs == NULL) {
235b94bf967SPankaj Gupta 		ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
236b94bf967SPankaj Gupta 		return 1;
237b94bf967SPankaj Gupta 	}
238b94bf967SPankaj Gupta 
239b94bf967SPankaj Gupta 	memcpy(&certs[0], &def_certs[0],
240b94bf967SPankaj Gupta 	       (num_def_certs * sizeof(def_certs[0])));
241b94bf967SPankaj Gupta 
242b94bf967SPankaj Gupta #ifdef PDEF_CERTS
243b94bf967SPankaj Gupta 	memcpy(&certs[num_def_certs], &pdef_certs[0],
244b94bf967SPankaj Gupta 	       (num_pdef_certs * sizeof(pdef_certs[0])));
245b94bf967SPankaj Gupta 
246b94bf967SPankaj Gupta 	num_certs = num_def_certs + num_pdef_certs;
247b94bf967SPankaj Gupta #else
248b94bf967SPankaj Gupta 	num_certs = num_def_certs;
249b94bf967SPankaj Gupta #endif
250b94bf967SPankaj Gupta 
251ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
252ad2c1a9aSJuan Castillo 		cert = &certs[i];
253159807e2SJuan Castillo 		cmd_opt.long_opt.name = cert->opt;
254159807e2SJuan Castillo 		cmd_opt.long_opt.has_arg = required_argument;
255159807e2SJuan Castillo 		cmd_opt.long_opt.flag = NULL;
256159807e2SJuan Castillo 		cmd_opt.long_opt.val = CMD_OPT_CERT;
257159807e2SJuan Castillo 		cmd_opt.help_msg = cert->help_msg;
258159807e2SJuan Castillo 		cmd_opt_add(&cmd_opt);
259ad2c1a9aSJuan Castillo 	}
260ad2c1a9aSJuan Castillo 
261159807e2SJuan Castillo 	return 0;
262ad2c1a9aSJuan Castillo }
263ad2c1a9aSJuan Castillo 
cert_get_by_opt(const char * opt)264ad2c1a9aSJuan Castillo cert_t *cert_get_by_opt(const char *opt)
265ad2c1a9aSJuan Castillo {
266c893c733SMasahiro Yamada 	cert_t *cert;
267ad2c1a9aSJuan Castillo 	unsigned int i;
268ad2c1a9aSJuan Castillo 
269ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
270ad2c1a9aSJuan Castillo 		cert = &certs[i];
271ad2c1a9aSJuan Castillo 		if (0 == strcmp(cert->opt, opt)) {
272ad2c1a9aSJuan Castillo 			return cert;
273ad2c1a9aSJuan Castillo 		}
274ad2c1a9aSJuan Castillo 	}
275ad2c1a9aSJuan Castillo 
276ad2c1a9aSJuan Castillo 	return NULL;
277ad2c1a9aSJuan Castillo }
278cf2dd17dSJuan Pablo Conde 
cert_cleanup(void)279cf2dd17dSJuan Pablo Conde void cert_cleanup(void)
280cf2dd17dSJuan Pablo Conde {
281cf2dd17dSJuan Pablo Conde 	unsigned int i;
282cf2dd17dSJuan Pablo Conde 
283cf2dd17dSJuan Pablo Conde 	for (i = 0; i < num_certs; i++) {
284cf2dd17dSJuan Pablo Conde 		if (certs[i].fn != NULL) {
285cf2dd17dSJuan Pablo Conde 			void *ptr = (void *)certs[i].fn;
286cf2dd17dSJuan Pablo Conde 
287cf2dd17dSJuan Pablo Conde 			certs[i].fn = NULL;
288cf2dd17dSJuan Pablo Conde 			free(ptr);
289cf2dd17dSJuan Pablo Conde 		}
290cf2dd17dSJuan Pablo Conde 	}
291cf2dd17dSJuan Pablo Conde 	free(certs);
292cf2dd17dSJuan Pablo Conde }
293cf2dd17dSJuan Pablo Conde 
294