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