summaryrefslogtreecommitdiffstats
path: root/tools/cert_create/src/cert.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tools/cert_create/src/cert.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c
new file mode 100644
index 0000000..2513213
--- /dev/null
+++ b/tools/cert_create/src/cert.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/opensslv.h>
+#include <openssl/pem.h>
+#include <openssl/sha.h>
+#include <openssl/x509v3.h>
+
+#include "cert.h"
+#include "cmd_opt.h"
+#include "debug.h"
+#include "key.h"
+#include "sha.h"
+
+#define SERIAL_RAND_BITS 64
+#define RSA_SALT_LEN 32
+
+cert_t *certs;
+unsigned int num_certs;
+
+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 USING_OPENSSL3
+ if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0))
+#else
+ if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0))
+#endif
+ goto error;
+ if (ai && !BN_to_ASN1_INTEGER(btmp, ai))
+ goto error;
+
+ ret = 1;
+
+error:
+
+ if (!b)
+ BN_free(btmp);
+
+ return ret;
+}
+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;
+ }
+}
+
+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;
+}
+
+int cert_new(
+ int md_alg,
+ cert_t *cert,
+ int days,
+ int ca,
+ STACK_OF(X509_EXTENSION) * sk)
+{
+ 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;
+ X509 *x;
+ X509_EXTENSION *ex;
+ X509_NAME *name;
+ ASN1_INTEGER *sno;
+ int i, num, rc = 0;
+ EVP_MD_CTX *mdCtx;
+ EVP_PKEY_CTX *pKeyCtx = NULL;
+
+ /* 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;
+ }
+
+ mdCtx = EVP_MD_CTX_create();
+ if (mdCtx == NULL) {
+ ERR_print_errors_fp(stdout);
+ goto END;
+ }
+
+ /* Sign the certificate with the issuer key */
+ if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) {
+ ERR_print_errors_fp(stdout);
+ goto END;
+ }
+
+ /*
+ * Set additional parameters if issuing public key algorithm is RSA.
+ * This is not required for ECDSA.
+ */
+ if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) {
+ 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;
+ }
+
+ if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) {
+ ERR_print_errors_fp(stdout);
+ goto END;
+ }
+ }
+
+ /* 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,
+ (const unsigned char *)issuer_cert->cn, -1, -1, 0);
+ 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);
+ }
+ }
+
+ if (!X509_sign_ctx(x, mdCtx)) {
+ ERR_print_errors_fp(stdout);
+ goto END;
+ }
+
+ /* X509 certificate signed successfully */
+ rc = 1;
+ cert->x = x;
+
+END:
+ EVP_MD_CTX_destroy(mdCtx);
+ return rc;
+}
+
+int cert_init(void)
+{
+ cmd_opt_t cmd_opt;
+ cert_t *cert;
+ unsigned int i;
+
+ 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
+
+ for (i = 0; i < num_certs; i++) {
+ cert = &certs[i];
+ 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);
+ }
+
+ return 0;
+}
+
+cert_t *cert_get_by_opt(const char *opt)
+{
+ cert_t *cert;
+ unsigned int i;
+
+ for (i = 0; i < num_certs; i++) {
+ cert = &certs[i];
+ if (0 == strcmp(cert->opt, opt)) {
+ return cert;
+ }
+ }
+
+ return NULL;
+}
+
+void cert_cleanup(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_certs; i++) {
+ if (certs[i].fn != NULL) {
+ void *ptr = (void *)certs[i].fn;
+
+ certs[i].fn = NULL;
+ free(ptr);
+ }
+ }
+ free(certs);
+}
+