1 /* 2 * Copyright (c) 2015-2021, 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/opensslv.h> 14 #include <openssl/pem.h> 15 #include <openssl/sha.h> 16 #include <openssl/x509v3.h> 17 18 #include "cert.h" 19 #include "cmd_opt.h" 20 #include "debug.h" 21 #include "key.h" 22 #include "sha.h" 23 24 #define SERIAL_RAND_BITS 64 25 #define RSA_SALT_LEN 32 26 27 cert_t *certs; 28 unsigned int num_certs; 29 30 int rand_serial(BIGNUM *b, ASN1_INTEGER *ai) 31 { 32 BIGNUM *btmp; 33 int ret = 0; 34 if (b) 35 btmp = b; 36 else 37 btmp = BN_new(); 38 39 if (!btmp) 40 return 0; 41 42 if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) 43 goto error; 44 if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) 45 goto error; 46 47 ret = 1; 48 49 error: 50 51 if (!b) 52 BN_free(btmp); 53 54 return ret; 55 } 56 const EVP_MD *get_digest(int alg) 57 { 58 switch (alg) { 59 case HASH_ALG_SHA256: 60 return EVP_sha256(); 61 case HASH_ALG_SHA384: 62 return EVP_sha384(); 63 case HASH_ALG_SHA512: 64 return EVP_sha512(); 65 default: 66 return NULL; 67 } 68 } 69 70 int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value) 71 { 72 X509_EXTENSION *ex; 73 X509V3_CTX ctx; 74 75 /* No configuration database */ 76 X509V3_set_ctx_nodb(&ctx); 77 78 /* Set issuer and subject certificates in the context */ 79 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0); 80 ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); 81 if (!ex) { 82 ERR_print_errors_fp(stdout); 83 return 0; 84 } 85 86 X509_add_ext(subject, ex, -1); 87 X509_EXTENSION_free(ex); 88 89 return 1; 90 } 91 92 int cert_new( 93 int md_alg, 94 cert_t *cert, 95 int days, 96 int ca, 97 STACK_OF(X509_EXTENSION) * sk) 98 { 99 EVP_PKEY *pkey = keys[cert->key].key; 100 cert_t *issuer_cert = &certs[cert->issuer]; 101 EVP_PKEY *ikey = keys[issuer_cert->key].key; 102 X509 *issuer = issuer_cert->x; 103 X509 *x; 104 X509_EXTENSION *ex; 105 X509_NAME *name; 106 ASN1_INTEGER *sno; 107 int i, num, rc = 0; 108 EVP_MD_CTX *mdCtx; 109 EVP_PKEY_CTX *pKeyCtx = NULL; 110 111 /* Create the certificate structure */ 112 x = X509_new(); 113 if (!x) { 114 return 0; 115 } 116 117 /* If we do not have a key, use the issuer key (the certificate will 118 * become self signed). This happens in content certificates. */ 119 if (!pkey) { 120 pkey = ikey; 121 } 122 123 /* If we do not have an issuer certificate, use our own (the certificate 124 * will become self signed) */ 125 if (!issuer) { 126 issuer = x; 127 } 128 129 mdCtx = EVP_MD_CTX_create(); 130 if (mdCtx == NULL) { 131 ERR_print_errors_fp(stdout); 132 goto END; 133 } 134 135 /* Sign the certificate with the issuer key */ 136 if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) { 137 ERR_print_errors_fp(stdout); 138 goto END; 139 } 140 141 /* 142 * Set additional parameters if issuing public key algorithm is RSA. 143 * This is not required for ECDSA. 144 */ 145 if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) { 146 if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) { 147 ERR_print_errors_fp(stdout); 148 goto END; 149 } 150 151 if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) { 152 ERR_print_errors_fp(stdout); 153 goto END; 154 } 155 156 if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) { 157 ERR_print_errors_fp(stdout); 158 goto END; 159 } 160 } 161 162 /* x509.v3 */ 163 X509_set_version(x, 2); 164 165 /* Random serial number */ 166 sno = ASN1_INTEGER_new(); 167 rand_serial(NULL, sno); 168 X509_set_serialNumber(x, sno); 169 ASN1_INTEGER_free(sno); 170 171 X509_gmtime_adj(X509_get_notBefore(x), 0); 172 X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); 173 X509_set_pubkey(x, pkey); 174 175 /* Subject name */ 176 name = X509_get_subject_name(x); 177 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, 178 (const unsigned char *)cert->cn, -1, -1, 0); 179 X509_set_subject_name(x, name); 180 181 /* Issuer name */ 182 name = X509_get_issuer_name(x); 183 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, 184 (const unsigned char *)issuer_cert->cn, -1, -1, 0); 185 X509_set_issuer_name(x, name); 186 187 /* Add various extensions: standard extensions */ 188 cert_add_ext(issuer, x, NID_subject_key_identifier, "hash"); 189 cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always"); 190 if (ca) { 191 cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE"); 192 cert_add_ext(issuer, x, NID_key_usage, "keyCertSign"); 193 } else { 194 cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE"); 195 } 196 197 /* Add custom extensions */ 198 if (sk != NULL) { 199 num = sk_X509_EXTENSION_num(sk); 200 for (i = 0; i < num; i++) { 201 ex = sk_X509_EXTENSION_value(sk, i); 202 X509_add_ext(x, ex, -1); 203 } 204 } 205 206 if (!X509_sign_ctx(x, mdCtx)) { 207 ERR_print_errors_fp(stdout); 208 goto END; 209 } 210 211 /* X509 certificate signed successfully */ 212 rc = 1; 213 cert->x = x; 214 215 END: 216 EVP_MD_CTX_destroy(mdCtx); 217 return rc; 218 } 219 220 int cert_init(void) 221 { 222 cmd_opt_t cmd_opt; 223 cert_t *cert; 224 unsigned int i; 225 226 certs = malloc((num_def_certs * sizeof(def_certs[0])) 227 #ifdef PDEF_CERTS 228 + (num_pdef_certs * sizeof(pdef_certs[0])) 229 #endif 230 ); 231 if (certs == NULL) { 232 ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__); 233 return 1; 234 } 235 236 memcpy(&certs[0], &def_certs[0], 237 (num_def_certs * sizeof(def_certs[0]))); 238 239 #ifdef PDEF_CERTS 240 memcpy(&certs[num_def_certs], &pdef_certs[0], 241 (num_pdef_certs * sizeof(pdef_certs[0]))); 242 243 num_certs = num_def_certs + num_pdef_certs; 244 #else 245 num_certs = num_def_certs; 246 #endif 247 248 for (i = 0; i < num_certs; i++) { 249 cert = &certs[i]; 250 cmd_opt.long_opt.name = cert->opt; 251 cmd_opt.long_opt.has_arg = required_argument; 252 cmd_opt.long_opt.flag = NULL; 253 cmd_opt.long_opt.val = CMD_OPT_CERT; 254 cmd_opt.help_msg = cert->help_msg; 255 cmd_opt_add(&cmd_opt); 256 } 257 258 return 0; 259 } 260 261 cert_t *cert_get_by_opt(const char *opt) 262 { 263 cert_t *cert; 264 unsigned int i; 265 266 for (i = 0; i < num_certs; i++) { 267 cert = &certs[i]; 268 if (0 == strcmp(cert->opt, opt)) { 269 return cert; 270 } 271 } 272 273 return NULL; 274 } 275