16f971622SJuan Castillo /* 2067f7e9cSSandrine Bailleux * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. 36f971622SJuan Castillo * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 56f971622SJuan Castillo */ 66f971622SJuan Castillo 76f971622SJuan Castillo #include <stddef.h> 86f971622SJuan Castillo #include <stdio.h> 96f971622SJuan Castillo #include <string.h> 10c3da66b1SJuan Castillo #include <openssl/asn1.h> 11c3da66b1SJuan Castillo #include <openssl/asn1t.h> 126f971622SJuan Castillo #include <openssl/err.h> 136f971622SJuan Castillo #include <openssl/x509v3.h> 14ad2c1a9aSJuan Castillo 15ad2c1a9aSJuan Castillo #include "cmd_opt.h" 166f971622SJuan Castillo #include "ext.h" 176f971622SJuan Castillo 186f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_INTEGER) 19c3da66b1SJuan Castillo DECLARE_ASN1_ITEM(X509_ALGOR) 206f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_OCTET_STRING) 216f971622SJuan Castillo 22c3da66b1SJuan Castillo typedef struct { 23c3da66b1SJuan Castillo X509_ALGOR *hashAlgorithm; 24c3da66b1SJuan Castillo ASN1_OCTET_STRING *dataHash; 25c3da66b1SJuan Castillo } HASH; 26c3da66b1SJuan Castillo 27c3da66b1SJuan Castillo ASN1_SEQUENCE(HASH) = { 28c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR), 29c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING), 30c3da66b1SJuan Castillo } ASN1_SEQUENCE_END(HASH) 31c3da66b1SJuan Castillo 32c3da66b1SJuan Castillo DECLARE_ASN1_FUNCTIONS(HASH) 33c3da66b1SJuan Castillo IMPLEMENT_ASN1_FUNCTIONS(HASH) 34c3da66b1SJuan Castillo 356f971622SJuan Castillo /* 36067f7e9cSSandrine Bailleux * This function adds the CoT extensions to the internal extension list 376f971622SJuan Castillo * maintained by OpenSSL so they can be used later. 386f971622SJuan Castillo * 396f971622SJuan Castillo * It also initializes the methods to print the contents of the extension. If an 40067f7e9cSSandrine Bailleux * alias is specified in the CoT extension, we reuse the methods of the alias. 416f971622SJuan Castillo * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are 426f971622SJuan Castillo * provided. Any other type will be printed as a raw ascii string. 436f971622SJuan Castillo * 446f971622SJuan Castillo * Return: 0 = success, Otherwise: error 456f971622SJuan Castillo */ 46ad2c1a9aSJuan Castillo int ext_init(void) 476f971622SJuan Castillo { 48159807e2SJuan Castillo cmd_opt_t cmd_opt; 496f971622SJuan Castillo ext_t *ext; 506f971622SJuan Castillo X509V3_EXT_METHOD *m; 51ad2c1a9aSJuan Castillo int nid, ret; 52ad2c1a9aSJuan Castillo unsigned int i; 536f971622SJuan Castillo 54ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) { 55ad2c1a9aSJuan Castillo ext = &extensions[i]; 56ad2c1a9aSJuan Castillo /* Register command line option */ 57ad2c1a9aSJuan Castillo if (ext->opt) { 58159807e2SJuan Castillo cmd_opt.long_opt.name = ext->opt; 59159807e2SJuan Castillo cmd_opt.long_opt.has_arg = required_argument; 60159807e2SJuan Castillo cmd_opt.long_opt.flag = NULL; 61159807e2SJuan Castillo cmd_opt.long_opt.val = CMD_OPT_EXT; 62159807e2SJuan Castillo cmd_opt.help_msg = ext->help_msg; 63159807e2SJuan Castillo cmd_opt_add(&cmd_opt); 64ad2c1a9aSJuan Castillo } 65ad2c1a9aSJuan Castillo /* Register the extension OID in OpenSSL */ 66ad2c1a9aSJuan Castillo if (ext->oid == NULL) { 67ad2c1a9aSJuan Castillo continue; 68ad2c1a9aSJuan Castillo } 696f971622SJuan Castillo nid = OBJ_create(ext->oid, ext->sn, ext->ln); 706f971622SJuan Castillo if (ext->alias) { 716f971622SJuan Castillo X509V3_EXT_add_alias(nid, ext->alias); 726f971622SJuan Castillo } else { 736f971622SJuan Castillo m = &ext->method; 746f971622SJuan Castillo memset(m, 0x0, sizeof(X509V3_EXT_METHOD)); 7555e291a4SJuan Castillo switch (ext->asn1_type) { 766f971622SJuan Castillo case V_ASN1_INTEGER: 776f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_INTEGER); 786f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER; 796f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER; 806f971622SJuan Castillo break; 816f971622SJuan Castillo case V_ASN1_OCTET_STRING: 826f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING); 836f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING; 846f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING; 856f971622SJuan Castillo break; 866f971622SJuan Castillo default: 876f971622SJuan Castillo continue; 886f971622SJuan Castillo } 896f971622SJuan Castillo m->ext_nid = nid; 906f971622SJuan Castillo ret = X509V3_EXT_add(m); 916f971622SJuan Castillo if (!ret) { 926f971622SJuan Castillo ERR_print_errors_fp(stdout); 936f971622SJuan Castillo return 1; 946f971622SJuan Castillo } 956f971622SJuan Castillo } 966f971622SJuan Castillo } 976f971622SJuan Castillo return 0; 986f971622SJuan Castillo } 996f971622SJuan Castillo 1006f971622SJuan Castillo /* 1016f971622SJuan Castillo * Create a new extension 1026f971622SJuan Castillo * 1036f971622SJuan Castillo * Extension ::= SEQUENCE { 1046f971622SJuan Castillo * id OBJECT IDENTIFIER, 1056f971622SJuan Castillo * critical BOOLEAN DEFAULT FALSE, 1066f971622SJuan Castillo * value OCTET STRING } 1076f971622SJuan Castillo * 1086f971622SJuan Castillo * Parameters: 1096f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 1106f971622SJuan Castillo * nid: extension identifier 1116f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 1126f971622SJuan Castillo * data: extension data. This data will be encapsulated in an Octet String 1136f971622SJuan Castillo * 1146f971622SJuan Castillo * Return: Extension address, NULL if error 1156f971622SJuan Castillo */ 1166f971622SJuan Castillo static 1176f971622SJuan Castillo X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len) 1186f971622SJuan Castillo { 1196f971622SJuan Castillo X509_EXTENSION *ex; 1206f971622SJuan Castillo ASN1_OCTET_STRING *ext_data; 1216f971622SJuan Castillo 1226f971622SJuan Castillo /* Octet string containing the extension data */ 1236f971622SJuan Castillo ext_data = ASN1_OCTET_STRING_new(); 1246f971622SJuan Castillo ASN1_OCTET_STRING_set(ext_data, data, len); 1256f971622SJuan Castillo 1266f971622SJuan Castillo /* Create the extension */ 1276f971622SJuan Castillo ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data); 1286f971622SJuan Castillo 1296f971622SJuan Castillo /* The extension makes a copy of the data, so we can free this object */ 1306f971622SJuan Castillo ASN1_OCTET_STRING_free(ext_data); 1316f971622SJuan Castillo 1326f971622SJuan Castillo return ex; 1336f971622SJuan Castillo } 1346f971622SJuan Castillo 1356f971622SJuan Castillo /* 136c3da66b1SJuan Castillo * Creates a x509v3 extension containing a hash 137c3da66b1SJuan Castillo * 138c3da66b1SJuan Castillo * DigestInfo ::= SEQUENCE { 139c3da66b1SJuan Castillo * digestAlgorithm AlgorithmIdentifier, 140c3da66b1SJuan Castillo * digest OCTET STRING 141c3da66b1SJuan Castillo * } 142c3da66b1SJuan Castillo * 143c3da66b1SJuan Castillo * AlgorithmIdentifier ::= SEQUENCE { 144c3da66b1SJuan Castillo * algorithm OBJECT IDENTIFIER, 145c3da66b1SJuan Castillo * parameters ANY DEFINED BY algorithm OPTIONAL 146c3da66b1SJuan Castillo * } 1476f971622SJuan Castillo * 1486f971622SJuan Castillo * Parameters: 1496f971622SJuan Castillo * nid: extension identifier 1506f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 151c3da66b1SJuan Castillo * md: hash algorithm 1526f971622SJuan Castillo * buf: pointer to the buffer that contains the hash 1536f971622SJuan Castillo * len: size of the hash in bytes 1546f971622SJuan Castillo * 1556f971622SJuan Castillo * Return: Extension address, NULL if error 1566f971622SJuan Castillo */ 157c3da66b1SJuan Castillo X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, 158c3da66b1SJuan Castillo unsigned char *buf, size_t len) 1596f971622SJuan Castillo { 160c893c733SMasahiro Yamada X509_EXTENSION *ex; 161c893c733SMasahiro Yamada HASH *hash; 162c893c733SMasahiro Yamada ASN1_OBJECT *algorithm; 1636f971622SJuan Castillo unsigned char *p = NULL; 164c893c733SMasahiro Yamada int sz; 1656f971622SJuan Castillo 166c3da66b1SJuan Castillo /* HASH structure containing algorithm + hash */ 167c3da66b1SJuan Castillo hash = HASH_new(); 168c3da66b1SJuan Castillo if (hash == NULL) { 169c3da66b1SJuan Castillo return NULL; 170c3da66b1SJuan Castillo } 171*bcad2030SJimmy Brisson 172*bcad2030SJimmy Brisson /* OBJECT_IDENTIFIER with hash algorithm */ 173*bcad2030SJimmy Brisson algorithm = OBJ_nid2obj(EVP_MD_type(md)); 174*bcad2030SJimmy Brisson if (algorithm == NULL) { 175*bcad2030SJimmy Brisson HASH_free(hash); 176*bcad2030SJimmy Brisson return NULL; 177*bcad2030SJimmy Brisson } 178*bcad2030SJimmy Brisson 179*bcad2030SJimmy Brisson /* Create X509_ALGOR */ 180*bcad2030SJimmy Brisson hash->hashAlgorithm->algorithm = algorithm; 181*bcad2030SJimmy Brisson hash->hashAlgorithm->parameter = ASN1_TYPE_new(); 182*bcad2030SJimmy Brisson ASN1_TYPE_set(hash->hashAlgorithm->parameter, V_ASN1_NULL, NULL); 183*bcad2030SJimmy Brisson 184*bcad2030SJimmy Brisson /* OCTET_STRING with the actual hash */ 185*bcad2030SJimmy Brisson ASN1_OCTET_STRING_set(hash->dataHash, buf, len); 186c3da66b1SJuan Castillo 187c3da66b1SJuan Castillo /* DER encoded HASH */ 188c3da66b1SJuan Castillo sz = i2d_HASH(hash, &p); 189c3da66b1SJuan Castillo if ((sz <= 0) || (p == NULL)) { 190c3da66b1SJuan Castillo HASH_free(hash); 191c3da66b1SJuan Castillo return NULL; 192c3da66b1SJuan Castillo } 1936f971622SJuan Castillo 1946f971622SJuan Castillo /* Create the extension */ 1956f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 1966f971622SJuan Castillo 1976f971622SJuan Castillo /* Clean up */ 1986f971622SJuan Castillo OPENSSL_free(p); 199c3da66b1SJuan Castillo HASH_free(hash); 2006f971622SJuan Castillo 2016f971622SJuan Castillo return ex; 2026f971622SJuan Castillo } 2036f971622SJuan Castillo 2046f971622SJuan Castillo /* 2056f971622SJuan Castillo * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1 2066f971622SJuan Castillo * Integer 2076f971622SJuan Castillo * 2086f971622SJuan Castillo * Parameters: 2096f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 2106f971622SJuan Castillo * nid: extension identifier 2116f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 2126f971622SJuan Castillo * value: nvcounter value 2136f971622SJuan Castillo * 2146f971622SJuan Castillo * Return: Extension address, NULL if error 2156f971622SJuan Castillo */ 2166f971622SJuan Castillo X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value) 2176f971622SJuan Castillo { 218c893c733SMasahiro Yamada X509_EXTENSION *ex; 219c893c733SMasahiro Yamada ASN1_INTEGER *counter; 2206f971622SJuan Castillo unsigned char *p = NULL; 221c893c733SMasahiro Yamada int sz; 2226f971622SJuan Castillo 2236f971622SJuan Castillo /* Encode counter */ 2246f971622SJuan Castillo counter = ASN1_INTEGER_new(); 2256f971622SJuan Castillo ASN1_INTEGER_set(counter, value); 226559eb8b7SMasahiro Yamada sz = i2d_ASN1_INTEGER(counter, &p); 2276f971622SJuan Castillo 2286f971622SJuan Castillo /* Create the extension */ 2296f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 2306f971622SJuan Castillo 2316f971622SJuan Castillo /* Free objects */ 2326f971622SJuan Castillo OPENSSL_free(p); 2336f971622SJuan Castillo ASN1_INTEGER_free(counter); 2346f971622SJuan Castillo 2356f971622SJuan Castillo return ex; 2366f971622SJuan Castillo } 2376f971622SJuan Castillo 2386f971622SJuan Castillo /* 2396f971622SJuan Castillo * Creates a x509v3 extension containing a public key in DER format: 2406f971622SJuan Castillo * 2416f971622SJuan Castillo * SubjectPublicKeyInfo ::= SEQUENCE { 2426f971622SJuan Castillo * algorithm AlgorithmIdentifier, 2436f971622SJuan Castillo * subjectPublicKey BIT STRING } 2446f971622SJuan Castillo * 2456f971622SJuan Castillo * Parameters: 2466f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 2476f971622SJuan Castillo * nid: extension identifier 2486f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 2496f971622SJuan Castillo * k: key 2506f971622SJuan Castillo * 2516f971622SJuan Castillo * Return: Extension address, NULL if error 2526f971622SJuan Castillo */ 2536f971622SJuan Castillo X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k) 2546f971622SJuan Castillo { 255c893c733SMasahiro Yamada X509_EXTENSION *ex; 256c893c733SMasahiro Yamada unsigned char *p; 257c893c733SMasahiro Yamada int sz; 2586f971622SJuan Castillo 2596f971622SJuan Castillo /* Encode key */ 2606f971622SJuan Castillo BIO *mem = BIO_new(BIO_s_mem()); 2616f971622SJuan Castillo if (i2d_PUBKEY_bio(mem, k) <= 0) { 2626f971622SJuan Castillo ERR_print_errors_fp(stderr); 2636f971622SJuan Castillo return NULL; 2646f971622SJuan Castillo } 2656f971622SJuan Castillo p = (unsigned char *)OPENSSL_malloc(4096); 2666f971622SJuan Castillo sz = BIO_read(mem, p, 4096); 2676f971622SJuan Castillo 2686f971622SJuan Castillo /* Create the extension */ 2696f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 2706f971622SJuan Castillo 2716f971622SJuan Castillo /* Clean up */ 27265ec13bcSJustin Chadwell BIO_free(mem); 2736f971622SJuan Castillo OPENSSL_free(p); 2746f971622SJuan Castillo 2756f971622SJuan Castillo return ex; 2766f971622SJuan Castillo } 277ad2c1a9aSJuan Castillo 278ad2c1a9aSJuan Castillo ext_t *ext_get_by_opt(const char *opt) 279ad2c1a9aSJuan Castillo { 280c893c733SMasahiro Yamada ext_t *ext; 281ad2c1a9aSJuan Castillo unsigned int i; 282ad2c1a9aSJuan Castillo 283ad2c1a9aSJuan Castillo /* Sequential search. This is not a performance concern since the number 284ad2c1a9aSJuan Castillo * of extensions is bounded and the code runs on a host machine */ 285ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) { 286ad2c1a9aSJuan Castillo ext = &extensions[i]; 287ad2c1a9aSJuan Castillo if (ext->opt && !strcmp(ext->opt, opt)) { 288ad2c1a9aSJuan Castillo return ext; 289ad2c1a9aSJuan Castillo } 290ad2c1a9aSJuan Castillo } 291ad2c1a9aSJuan Castillo 292ad2c1a9aSJuan Castillo return NULL; 293ad2c1a9aSJuan Castillo } 294