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 <stddef.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <openssl/asn1.h> 11 #include <openssl/asn1t.h> 12 #include <openssl/err.h> 13 #include <openssl/x509v3.h> 14 15 #include "cmd_opt.h" 16 #include "debug.h" 17 #include "ext.h" 18 19 ext_t *extensions; 20 unsigned int num_extensions; 21 22 DECLARE_ASN1_ITEM(ASN1_INTEGER) 23 DECLARE_ASN1_ITEM(X509_ALGOR) 24 DECLARE_ASN1_ITEM(ASN1_OCTET_STRING) 25 26 typedef struct { 27 X509_ALGOR *hashAlgorithm; 28 ASN1_OCTET_STRING *dataHash; 29 } HASH; 30 31 ASN1_SEQUENCE(HASH) = { 32 ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR), 33 ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING), 34 } ASN1_SEQUENCE_END(HASH) 35 36 DECLARE_ASN1_FUNCTIONS(HASH) 37 IMPLEMENT_ASN1_FUNCTIONS(HASH) 38 39 /* 40 * This function adds the CoT extensions to the internal extension list 41 * maintained by OpenSSL so they can be used later. 42 * 43 * It also initializes the methods to print the contents of the extension. If an 44 * alias is specified in the CoT extension, we reuse the methods of the alias. 45 * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are 46 * provided. Any other type will be printed as a raw ascii string. 47 * 48 * Return: 0 = success, Otherwise: error 49 */ 50 int ext_init(void) 51 { 52 cmd_opt_t cmd_opt; 53 ext_t *ext; 54 X509V3_EXT_METHOD *m; 55 int nid, ret; 56 unsigned int i; 57 58 extensions = malloc((num_def_extensions * sizeof(def_extensions[0])) 59 #ifdef PDEF_EXTS 60 + (num_pdef_extensions * sizeof(pdef_extensions[0])) 61 #endif 62 ); 63 if (extensions == NULL) { 64 ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__); 65 return 1; 66 } 67 68 memcpy(&extensions[0], &def_extensions[0], 69 (num_def_extensions * sizeof(def_extensions[0]))); 70 #ifdef PDEF_EXTS 71 memcpy(&extensions[num_def_extensions], &pdef_extensions[0], 72 (num_pdef_extensions * sizeof(pdef_extensions[0]))); 73 num_extensions = num_def_extensions + num_pdef_extensions; 74 #else 75 num_extensions = num_def_extensions; 76 #endif 77 78 for (i = 0; i < num_extensions; i++) { 79 ext = &extensions[i]; 80 /* Register command line option */ 81 if (ext->opt) { 82 cmd_opt.long_opt.name = ext->opt; 83 cmd_opt.long_opt.has_arg = required_argument; 84 cmd_opt.long_opt.flag = NULL; 85 cmd_opt.long_opt.val = CMD_OPT_EXT; 86 cmd_opt.help_msg = ext->help_msg; 87 cmd_opt_add(&cmd_opt); 88 } 89 /* Register the extension OID in OpenSSL */ 90 if (ext->oid == NULL) { 91 continue; 92 } 93 nid = OBJ_create(ext->oid, ext->sn, ext->ln); 94 if (ext->alias) { 95 X509V3_EXT_add_alias(nid, ext->alias); 96 } else { 97 m = &ext->method; 98 memset(m, 0x0, sizeof(X509V3_EXT_METHOD)); 99 switch (ext->asn1_type) { 100 case V_ASN1_INTEGER: 101 m->it = ASN1_ITEM_ref(ASN1_INTEGER); 102 m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER; 103 m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER; 104 break; 105 case V_ASN1_OCTET_STRING: 106 m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING); 107 m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING; 108 m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING; 109 break; 110 default: 111 continue; 112 } 113 m->ext_nid = nid; 114 ret = X509V3_EXT_add(m); 115 if (!ret) { 116 ERR_print_errors_fp(stdout); 117 return 1; 118 } 119 } 120 } 121 return 0; 122 } 123 124 /* 125 * Create a new extension 126 * 127 * Extension ::= SEQUENCE { 128 * id OBJECT IDENTIFIER, 129 * critical BOOLEAN DEFAULT FALSE, 130 * value OCTET STRING } 131 * 132 * Parameters: 133 * pex: OpenSSL extension pointer (output parameter) 134 * nid: extension identifier 135 * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 136 * data: extension data. This data will be encapsulated in an Octet String 137 * 138 * Return: Extension address, NULL if error 139 */ 140 static 141 X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len) 142 { 143 X509_EXTENSION *ex; 144 ASN1_OCTET_STRING *ext_data; 145 146 /* Octet string containing the extension data */ 147 ext_data = ASN1_OCTET_STRING_new(); 148 ASN1_OCTET_STRING_set(ext_data, data, len); 149 150 /* Create the extension */ 151 ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data); 152 153 /* The extension makes a copy of the data, so we can free this object */ 154 ASN1_OCTET_STRING_free(ext_data); 155 156 return ex; 157 } 158 159 /* 160 * Creates a x509v3 extension containing a hash 161 * 162 * DigestInfo ::= SEQUENCE { 163 * digestAlgorithm AlgorithmIdentifier, 164 * digest OCTET STRING 165 * } 166 * 167 * AlgorithmIdentifier ::= SEQUENCE { 168 * algorithm OBJECT IDENTIFIER, 169 * parameters ANY DEFINED BY algorithm OPTIONAL 170 * } 171 * 172 * Parameters: 173 * nid: extension identifier 174 * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 175 * md: hash algorithm 176 * buf: pointer to the buffer that contains the hash 177 * len: size of the hash in bytes 178 * 179 * Return: Extension address, NULL if error 180 */ 181 X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, 182 unsigned char *buf, size_t len) 183 { 184 X509_EXTENSION *ex; 185 HASH *hash; 186 ASN1_OBJECT *algorithm; 187 unsigned char *p = NULL; 188 int sz; 189 190 /* HASH structure containing algorithm + hash */ 191 hash = HASH_new(); 192 if (hash == NULL) { 193 return NULL; 194 } 195 196 /* OBJECT_IDENTIFIER with hash algorithm */ 197 algorithm = OBJ_nid2obj(EVP_MD_type(md)); 198 if (algorithm == NULL) { 199 HASH_free(hash); 200 return NULL; 201 } 202 203 /* Create X509_ALGOR */ 204 hash->hashAlgorithm->algorithm = algorithm; 205 hash->hashAlgorithm->parameter = ASN1_TYPE_new(); 206 ASN1_TYPE_set(hash->hashAlgorithm->parameter, V_ASN1_NULL, NULL); 207 208 /* OCTET_STRING with the actual hash */ 209 ASN1_OCTET_STRING_set(hash->dataHash, buf, len); 210 211 /* DER encoded HASH */ 212 sz = i2d_HASH(hash, &p); 213 if ((sz <= 0) || (p == NULL)) { 214 HASH_free(hash); 215 return NULL; 216 } 217 218 /* Create the extension */ 219 ex = ext_new(nid, crit, p, sz); 220 221 /* Clean up */ 222 OPENSSL_free(p); 223 HASH_free(hash); 224 225 return ex; 226 } 227 228 /* 229 * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1 230 * Integer 231 * 232 * Parameters: 233 * pex: OpenSSL extension pointer (output parameter) 234 * nid: extension identifier 235 * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 236 * value: nvcounter value 237 * 238 * Return: Extension address, NULL if error 239 */ 240 X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value) 241 { 242 X509_EXTENSION *ex; 243 ASN1_INTEGER *counter; 244 unsigned char *p = NULL; 245 int sz; 246 247 /* Encode counter */ 248 counter = ASN1_INTEGER_new(); 249 ASN1_INTEGER_set(counter, value); 250 sz = i2d_ASN1_INTEGER(counter, &p); 251 252 /* Create the extension */ 253 ex = ext_new(nid, crit, p, sz); 254 255 /* Free objects */ 256 OPENSSL_free(p); 257 ASN1_INTEGER_free(counter); 258 259 return ex; 260 } 261 262 /* 263 * Creates a x509v3 extension containing a public key in DER format: 264 * 265 * SubjectPublicKeyInfo ::= SEQUENCE { 266 * algorithm AlgorithmIdentifier, 267 * subjectPublicKey BIT STRING } 268 * 269 * Parameters: 270 * pex: OpenSSL extension pointer (output parameter) 271 * nid: extension identifier 272 * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 273 * k: key 274 * 275 * Return: Extension address, NULL if error 276 */ 277 X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k) 278 { 279 X509_EXTENSION *ex; 280 unsigned char *p; 281 int sz; 282 283 /* Encode key */ 284 BIO *mem = BIO_new(BIO_s_mem()); 285 if (i2d_PUBKEY_bio(mem, k) <= 0) { 286 ERR_print_errors_fp(stderr); 287 return NULL; 288 } 289 p = (unsigned char *)OPENSSL_malloc(4096); 290 sz = BIO_read(mem, p, 4096); 291 292 /* Create the extension */ 293 ex = ext_new(nid, crit, p, sz); 294 295 /* Clean up */ 296 BIO_free(mem); 297 OPENSSL_free(p); 298 299 return ex; 300 } 301 302 ext_t *ext_get_by_opt(const char *opt) 303 { 304 ext_t *ext; 305 unsigned int i; 306 307 /* Sequential search. This is not a performance concern since the number 308 * of extensions is bounded and the code runs on a host machine */ 309 for (i = 0; i < num_extensions; i++) { 310 ext = &extensions[i]; 311 if (ext->opt && !strcmp(ext->opt, opt)) { 312 return ext; 313 } 314 } 315 316 return NULL; 317 } 318