xref: /rk3399_ARM-atf/tools/cert_create/src/cert.c (revision b94bf967e62b23a376a5026de69d06a0e8d6bf78)
16f971622SJuan Castillo /*
2*b94bf967SPankaj Gupta  * Copyright (c) 2015-2021, 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 
27*b94bf967SPankaj Gupta cert_t *certs;
28*b94bf967SPankaj Gupta unsigned int num_certs;
29*b94bf967SPankaj 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 
426f971622SJuan Castillo 	if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
436f971622SJuan Castillo 		goto error;
446f971622SJuan Castillo 	if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
456f971622SJuan Castillo 		goto error;
466f971622SJuan Castillo 
476f971622SJuan Castillo 	ret = 1;
486f971622SJuan Castillo 
496f971622SJuan Castillo error:
506f971622SJuan Castillo 
516f971622SJuan Castillo 	if (!b)
526f971622SJuan Castillo 		BN_free(btmp);
536f971622SJuan Castillo 
546f971622SJuan Castillo 	return ret;
556f971622SJuan Castillo }
562972247cSQixiang Xu const EVP_MD *get_digest(int alg)
572972247cSQixiang Xu {
582972247cSQixiang Xu 	switch (alg) {
592972247cSQixiang Xu 	case HASH_ALG_SHA256:
602972247cSQixiang Xu 		return EVP_sha256();
612972247cSQixiang Xu 	case HASH_ALG_SHA384:
622972247cSQixiang Xu 		return EVP_sha384();
632972247cSQixiang Xu 	case HASH_ALG_SHA512:
642972247cSQixiang Xu 		return EVP_sha512();
652972247cSQixiang Xu 	default:
662972247cSQixiang Xu 		return NULL;
672972247cSQixiang Xu 	}
682972247cSQixiang Xu }
696f971622SJuan Castillo 
706f971622SJuan Castillo int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value)
716f971622SJuan Castillo {
726f971622SJuan Castillo 	X509_EXTENSION *ex;
736f971622SJuan Castillo 	X509V3_CTX ctx;
746f971622SJuan Castillo 
756f971622SJuan Castillo 	/* No configuration database */
766f971622SJuan Castillo 	X509V3_set_ctx_nodb(&ctx);
776f971622SJuan Castillo 
786f971622SJuan Castillo 	/* Set issuer and subject certificates in the context */
796f971622SJuan Castillo 	X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
806f971622SJuan Castillo 	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
816f971622SJuan Castillo 	if (!ex) {
826f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
836f971622SJuan Castillo 		return 0;
846f971622SJuan Castillo 	}
856f971622SJuan Castillo 
866f971622SJuan Castillo 	X509_add_ext(subject, ex, -1);
876f971622SJuan Castillo 	X509_EXTENSION_free(ex);
886f971622SJuan Castillo 
896f971622SJuan Castillo 	return 1;
906f971622SJuan Castillo }
916f971622SJuan Castillo 
922972247cSQixiang Xu int cert_new(
932972247cSQixiang Xu 	int md_alg,
942972247cSQixiang Xu 	cert_t *cert,
952972247cSQixiang Xu 	int days,
962972247cSQixiang Xu 	int ca,
972972247cSQixiang Xu 	STACK_OF(X509_EXTENSION) * sk)
986f971622SJuan Castillo {
9955e291a4SJuan Castillo 	EVP_PKEY *pkey = keys[cert->key].key;
10055e291a4SJuan Castillo 	cert_t *issuer_cert = &certs[cert->issuer];
10155e291a4SJuan Castillo 	EVP_PKEY *ikey = keys[issuer_cert->key].key;
10255e291a4SJuan Castillo 	X509 *issuer = issuer_cert->x;
103c893c733SMasahiro Yamada 	X509 *x;
104c893c733SMasahiro Yamada 	X509_EXTENSION *ex;
105c893c733SMasahiro Yamada 	X509_NAME *name;
106c893c733SMasahiro Yamada 	ASN1_INTEGER *sno;
1071f33ad4eSSoby Mathew 	int i, num, rc = 0;
108742c4e14SMichalis Pappas 	EVP_MD_CTX *mdCtx;
1091f33ad4eSSoby Mathew 	EVP_PKEY_CTX *pKeyCtx = NULL;
1106f971622SJuan Castillo 
1116f971622SJuan Castillo 	/* Create the certificate structure */
1126f971622SJuan Castillo 	x = X509_new();
1136f971622SJuan Castillo 	if (!x) {
1146f971622SJuan Castillo 		return 0;
1156f971622SJuan Castillo 	}
1166f971622SJuan Castillo 
1176f971622SJuan Castillo 	/* If we do not have a key, use the issuer key (the certificate will
1186f971622SJuan Castillo 	 * become self signed). This happens in content certificates. */
1196f971622SJuan Castillo 	if (!pkey) {
1206f971622SJuan Castillo 		pkey = ikey;
1216f971622SJuan Castillo 	}
1226f971622SJuan Castillo 
1236f971622SJuan Castillo 	/* If we do not have an issuer certificate, use our own (the certificate
1246f971622SJuan Castillo 	 * will become self signed) */
1256f971622SJuan Castillo 	if (!issuer) {
1266f971622SJuan Castillo 		issuer = x;
1276f971622SJuan Castillo 	}
1286f971622SJuan Castillo 
129742c4e14SMichalis Pappas 	mdCtx = EVP_MD_CTX_create();
130742c4e14SMichalis Pappas 	if (mdCtx == NULL) {
131742c4e14SMichalis Pappas 		ERR_print_errors_fp(stdout);
132742c4e14SMichalis Pappas 		goto END;
133742c4e14SMichalis Pappas 	}
134a8eb286aSSoby Mathew 
135a8eb286aSSoby Mathew 	/* Sign the certificate with the issuer key */
1362972247cSQixiang Xu 	if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
1371f33ad4eSSoby Mathew 		ERR_print_errors_fp(stdout);
1381f33ad4eSSoby Mathew 		goto END;
1391f33ad4eSSoby Mathew 	}
1401f33ad4eSSoby Mathew 
141a8eb286aSSoby Mathew 	/*
1426a415a50SJustin Chadwell 	 * Set additional parameters if issuing public key algorithm is RSA.
1436a415a50SJustin Chadwell 	 * This is not required for ECDSA.
144a8eb286aSSoby Mathew 	 */
1456a415a50SJustin Chadwell 	if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
1461f33ad4eSSoby Mathew 		if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) {
1471f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1481f33ad4eSSoby Mathew 			goto END;
1491f33ad4eSSoby Mathew 		}
1501f33ad4eSSoby Mathew 
1511f33ad4eSSoby Mathew 		if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) {
1521f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1531f33ad4eSSoby Mathew 			goto END;
1541f33ad4eSSoby Mathew 		}
1551f33ad4eSSoby Mathew 
1562972247cSQixiang Xu 		if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
1571f33ad4eSSoby Mathew 			ERR_print_errors_fp(stdout);
1581f33ad4eSSoby Mathew 			goto END;
1591f33ad4eSSoby Mathew 		}
160a8eb286aSSoby Mathew 	}
1611f33ad4eSSoby Mathew 
1626f971622SJuan Castillo 	/* x509.v3 */
1636f971622SJuan Castillo 	X509_set_version(x, 2);
1646f971622SJuan Castillo 
1656f971622SJuan Castillo 	/* Random serial number */
1666f971622SJuan Castillo 	sno = ASN1_INTEGER_new();
1676f971622SJuan Castillo 	rand_serial(NULL, sno);
1686f971622SJuan Castillo 	X509_set_serialNumber(x, sno);
1696f971622SJuan Castillo 	ASN1_INTEGER_free(sno);
1706f971622SJuan Castillo 
1716f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notBefore(x), 0);
1726f971622SJuan Castillo 	X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days);
1736f971622SJuan Castillo 	X509_set_pubkey(x, pkey);
1746f971622SJuan Castillo 
1756f971622SJuan Castillo 	/* Subject name */
1766f971622SJuan Castillo 	name = X509_get_subject_name(x);
1776f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
1786f971622SJuan Castillo 			(const unsigned char *)cert->cn, -1, -1, 0);
1796f971622SJuan Castillo 	X509_set_subject_name(x, name);
1806f971622SJuan Castillo 
1816f971622SJuan Castillo 	/* Issuer name */
1826f971622SJuan Castillo 	name = X509_get_issuer_name(x);
1836f971622SJuan Castillo 	X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
18455e291a4SJuan Castillo 			(const unsigned char *)issuer_cert->cn, -1, -1, 0);
1856f971622SJuan Castillo 	X509_set_issuer_name(x, name);
1866f971622SJuan Castillo 
1876f971622SJuan Castillo 	/* Add various extensions: standard extensions */
1886f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_subject_key_identifier, "hash");
1896f971622SJuan Castillo 	cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always");
1906f971622SJuan Castillo 	if (ca) {
1916f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE");
1926f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_key_usage, "keyCertSign");
1936f971622SJuan Castillo 	} else {
1946f971622SJuan Castillo 		cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE");
1956f971622SJuan Castillo 	}
1966f971622SJuan Castillo 
1976f971622SJuan Castillo 	/* Add custom extensions */
1986f971622SJuan Castillo 	if (sk != NULL) {
1996f971622SJuan Castillo 		num = sk_X509_EXTENSION_num(sk);
2006f971622SJuan Castillo 		for (i = 0; i < num; i++) {
2016f971622SJuan Castillo 			ex = sk_X509_EXTENSION_value(sk, i);
2026f971622SJuan Castillo 			X509_add_ext(x, ex, -1);
2036f971622SJuan Castillo 		}
2046f971622SJuan Castillo 	}
2056f971622SJuan Castillo 
206742c4e14SMichalis Pappas 	if (!X509_sign_ctx(x, mdCtx)) {
2076f971622SJuan Castillo 		ERR_print_errors_fp(stdout);
2081f33ad4eSSoby Mathew 		goto END;
2096f971622SJuan Castillo 	}
2106f971622SJuan Castillo 
2111f33ad4eSSoby Mathew 	/* X509 certificate signed successfully */
2121f33ad4eSSoby Mathew 	rc = 1;
2136f971622SJuan Castillo 	cert->x = x;
2141f33ad4eSSoby Mathew 
2151f33ad4eSSoby Mathew END:
216742c4e14SMichalis Pappas 	EVP_MD_CTX_destroy(mdCtx);
2171f33ad4eSSoby Mathew 	return rc;
2186f971622SJuan Castillo }
219ad2c1a9aSJuan Castillo 
220ad2c1a9aSJuan Castillo int cert_init(void)
221ad2c1a9aSJuan Castillo {
222159807e2SJuan Castillo 	cmd_opt_t cmd_opt;
223ad2c1a9aSJuan Castillo 	cert_t *cert;
224ad2c1a9aSJuan Castillo 	unsigned int i;
225ad2c1a9aSJuan Castillo 
226*b94bf967SPankaj Gupta 	certs = malloc((num_def_certs * sizeof(def_certs[0]))
227*b94bf967SPankaj Gupta #ifdef PDEF_CERTS
228*b94bf967SPankaj Gupta 		       + (num_pdef_certs * sizeof(pdef_certs[0]))
229*b94bf967SPankaj Gupta #endif
230*b94bf967SPankaj Gupta 		       );
231*b94bf967SPankaj Gupta 	if (certs == NULL) {
232*b94bf967SPankaj Gupta 		ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__);
233*b94bf967SPankaj Gupta 		return 1;
234*b94bf967SPankaj Gupta 	}
235*b94bf967SPankaj Gupta 
236*b94bf967SPankaj Gupta 	memcpy(&certs[0], &def_certs[0],
237*b94bf967SPankaj Gupta 	       (num_def_certs * sizeof(def_certs[0])));
238*b94bf967SPankaj Gupta 
239*b94bf967SPankaj Gupta #ifdef PDEF_CERTS
240*b94bf967SPankaj Gupta 	memcpy(&certs[num_def_certs], &pdef_certs[0],
241*b94bf967SPankaj Gupta 	       (num_pdef_certs * sizeof(pdef_certs[0])));
242*b94bf967SPankaj Gupta 
243*b94bf967SPankaj Gupta 	num_certs = num_def_certs + num_pdef_certs;
244*b94bf967SPankaj Gupta #else
245*b94bf967SPankaj Gupta 	num_certs = num_def_certs;
246*b94bf967SPankaj Gupta #endif
247*b94bf967SPankaj Gupta 
248ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
249ad2c1a9aSJuan Castillo 		cert = &certs[i];
250159807e2SJuan Castillo 		cmd_opt.long_opt.name = cert->opt;
251159807e2SJuan Castillo 		cmd_opt.long_opt.has_arg = required_argument;
252159807e2SJuan Castillo 		cmd_opt.long_opt.flag = NULL;
253159807e2SJuan Castillo 		cmd_opt.long_opt.val = CMD_OPT_CERT;
254159807e2SJuan Castillo 		cmd_opt.help_msg = cert->help_msg;
255159807e2SJuan Castillo 		cmd_opt_add(&cmd_opt);
256ad2c1a9aSJuan Castillo 	}
257ad2c1a9aSJuan Castillo 
258159807e2SJuan Castillo 	return 0;
259ad2c1a9aSJuan Castillo }
260ad2c1a9aSJuan Castillo 
261ad2c1a9aSJuan Castillo cert_t *cert_get_by_opt(const char *opt)
262ad2c1a9aSJuan Castillo {
263c893c733SMasahiro Yamada 	cert_t *cert;
264ad2c1a9aSJuan Castillo 	unsigned int i;
265ad2c1a9aSJuan Castillo 
266ad2c1a9aSJuan Castillo 	for (i = 0; i < num_certs; i++) {
267ad2c1a9aSJuan Castillo 		cert = &certs[i];
268ad2c1a9aSJuan Castillo 		if (0 == strcmp(cert->opt, opt)) {
269ad2c1a9aSJuan Castillo 			return cert;
270ad2c1a9aSJuan Castillo 		}
271ad2c1a9aSJuan Castillo 	}
272ad2c1a9aSJuan Castillo 
273ad2c1a9aSJuan Castillo 	return NULL;
274ad2c1a9aSJuan Castillo }
275