1 /* 2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <openssl/conf.h> 12 #include <openssl/err.h> 13 #include <openssl/pem.h> 14 #include <openssl/sha.h> 15 #include <openssl/x509v3.h> 16 17 #include "cert.h" 18 #include "cmd_opt.h" 19 #include "debug.h" 20 #include "key.h" 21 #include "platform_oid.h" 22 #include "sha.h" 23 24 #define SERIAL_RAND_BITS 64 25 26 int rand_serial(BIGNUM *b, ASN1_INTEGER *ai) 27 { 28 BIGNUM *btmp; 29 int ret = 0; 30 if (b) 31 btmp = b; 32 else 33 btmp = BN_new(); 34 35 if (!btmp) 36 return 0; 37 38 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) 39 goto error; 40 if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) 41 goto error; 42 43 ret = 1; 44 45 error: 46 47 if (!b) 48 BN_free(btmp); 49 50 return ret; 51 } 52 53 int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value) 54 { 55 X509_EXTENSION *ex; 56 X509V3_CTX ctx; 57 58 /* No configuration database */ 59 X509V3_set_ctx_nodb(&ctx); 60 61 /* Set issuer and subject certificates in the context */ 62 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0); 63 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); 64 if (!ex) { 65 ERR_print_errors_fp(stdout); 66 return 0; 67 } 68 69 X509_add_ext(subject, ex, -1); 70 X509_EXTENSION_free(ex); 71 72 return 1; 73 } 74 75 76 int cert_new(cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk) 77 { 78 EVP_PKEY *pkey = keys[cert->key].key; 79 cert_t *issuer_cert = &certs[cert->issuer]; 80 EVP_PKEY *ikey = keys[issuer_cert->key].key; 81 X509 *issuer = issuer_cert->x; 82 X509 *x; 83 X509_EXTENSION *ex; 84 X509_NAME *name; 85 ASN1_INTEGER *sno; 86 int i, num; 87 88 /* Create the certificate structure */ 89 x = X509_new(); 90 if (!x) { 91 return 0; 92 } 93 94 /* If we do not have a key, use the issuer key (the certificate will 95 * become self signed). This happens in content certificates. */ 96 if (!pkey) { 97 pkey = ikey; 98 } 99 100 /* If we do not have an issuer certificate, use our own (the certificate 101 * will become self signed) */ 102 if (!issuer) { 103 issuer = x; 104 } 105 106 /* x509.v3 */ 107 X509_set_version(x, 2); 108 109 /* Random serial number */ 110 sno = ASN1_INTEGER_new(); 111 rand_serial(NULL, sno); 112 X509_set_serialNumber(x, sno); 113 ASN1_INTEGER_free(sno); 114 115 X509_gmtime_adj(X509_get_notBefore(x), 0); 116 X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); 117 X509_set_pubkey(x, pkey); 118 119 /* Subject name */ 120 name = X509_get_subject_name(x); 121 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, 122 (const unsigned char *)cert->cn, -1, -1, 0); 123 X509_set_subject_name(x, name); 124 125 /* Issuer name */ 126 name = X509_get_issuer_name(x); 127 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, 128 (const unsigned char *)issuer_cert->cn, -1, -1, 0); 129 X509_set_issuer_name(x, name); 130 131 /* Add various extensions: standard extensions */ 132 cert_add_ext(issuer, x, NID_subject_key_identifier, "hash"); 133 cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always"); 134 if (ca) { 135 cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE"); 136 cert_add_ext(issuer, x, NID_key_usage, "keyCertSign"); 137 } else { 138 cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE"); 139 } 140 141 /* Add custom extensions */ 142 if (sk != NULL) { 143 num = sk_X509_EXTENSION_num(sk); 144 for (i = 0; i < num; i++) { 145 ex = sk_X509_EXTENSION_value(sk, i); 146 X509_add_ext(x, ex, -1); 147 } 148 } 149 150 /* Sign the certificate with the issuer key */ 151 if (!X509_sign(x, ikey, EVP_sha256())) { 152 ERR_print_errors_fp(stdout); 153 return 0; 154 } 155 156 cert->x = x; 157 return 1; 158 } 159 160 int cert_init(void) 161 { 162 cmd_opt_t cmd_opt; 163 cert_t *cert; 164 unsigned int i; 165 166 for (i = 0; i < num_certs; i++) { 167 cert = &certs[i]; 168 cmd_opt.long_opt.name = cert->opt; 169 cmd_opt.long_opt.has_arg = required_argument; 170 cmd_opt.long_opt.flag = NULL; 171 cmd_opt.long_opt.val = CMD_OPT_CERT; 172 cmd_opt.help_msg = cert->help_msg; 173 cmd_opt_add(&cmd_opt); 174 } 175 176 return 0; 177 } 178 179 cert_t *cert_get_by_opt(const char *opt) 180 { 181 cert_t *cert; 182 unsigned int i; 183 184 for (i = 0; i < num_certs; i++) { 185 cert = &certs[i]; 186 if (0 == strcmp(cert->opt, opt)) { 187 return cert; 188 } 189 } 190 191 return NULL; 192 } 193