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