16f971622SJuan Castillo /* 26f971622SJuan Castillo * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 36f971622SJuan Castillo * 46f971622SJuan Castillo * Redistribution and use in source and binary forms, with or without 56f971622SJuan Castillo * modification, are permitted provided that the following conditions are met: 66f971622SJuan Castillo * 76f971622SJuan Castillo * Redistributions of source code must retain the above copyright notice, this 86f971622SJuan Castillo * list of conditions and the following disclaimer. 96f971622SJuan Castillo * 106f971622SJuan Castillo * Redistributions in binary form must reproduce the above copyright notice, 116f971622SJuan Castillo * this list of conditions and the following disclaimer in the documentation 126f971622SJuan Castillo * and/or other materials provided with the distribution. 136f971622SJuan Castillo * 146f971622SJuan Castillo * Neither the name of ARM nor the names of its contributors may be used 156f971622SJuan Castillo * to endorse or promote products derived from this software without specific 166f971622SJuan Castillo * prior written permission. 176f971622SJuan Castillo * 186f971622SJuan Castillo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 196f971622SJuan Castillo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 206f971622SJuan Castillo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 216f971622SJuan Castillo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 226f971622SJuan Castillo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 236f971622SJuan Castillo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 246f971622SJuan Castillo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 256f971622SJuan Castillo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 266f971622SJuan Castillo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 276f971622SJuan Castillo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 286f971622SJuan Castillo * POSSIBILITY OF SUCH DAMAGE. 296f971622SJuan Castillo */ 306f971622SJuan Castillo 316f971622SJuan Castillo #include <stddef.h> 326f971622SJuan Castillo #include <stdio.h> 336f971622SJuan Castillo #include <string.h> 34c3da66b1SJuan Castillo #include <openssl/asn1.h> 35c3da66b1SJuan Castillo #include <openssl/asn1t.h> 366f971622SJuan Castillo #include <openssl/err.h> 376f971622SJuan Castillo #include <openssl/x509v3.h> 38*ad2c1a9aSJuan Castillo 39*ad2c1a9aSJuan Castillo #include "cmd_opt.h" 406f971622SJuan Castillo #include "ext.h" 416f971622SJuan Castillo 426f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_INTEGER) 43c3da66b1SJuan Castillo DECLARE_ASN1_ITEM(X509_ALGOR) 446f971622SJuan Castillo DECLARE_ASN1_ITEM(ASN1_OCTET_STRING) 456f971622SJuan Castillo 46c3da66b1SJuan Castillo typedef struct { 47c3da66b1SJuan Castillo X509_ALGOR *hashAlgorithm; 48c3da66b1SJuan Castillo ASN1_OCTET_STRING *dataHash; 49c3da66b1SJuan Castillo } HASH; 50c3da66b1SJuan Castillo 51c3da66b1SJuan Castillo ASN1_SEQUENCE(HASH) = { 52c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR), 53c3da66b1SJuan Castillo ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING), 54c3da66b1SJuan Castillo } ASN1_SEQUENCE_END(HASH) 55c3da66b1SJuan Castillo 56c3da66b1SJuan Castillo DECLARE_ASN1_FUNCTIONS(HASH) 57c3da66b1SJuan Castillo IMPLEMENT_ASN1_FUNCTIONS(HASH) 58c3da66b1SJuan Castillo 596f971622SJuan Castillo /* 606f971622SJuan Castillo * This function adds the TBB extensions to the internal extension list 616f971622SJuan Castillo * maintained by OpenSSL so they can be used later. 626f971622SJuan Castillo * 636f971622SJuan Castillo * It also initializes the methods to print the contents of the extension. If an 646f971622SJuan Castillo * alias is specified in the TBB extension, we reuse the methods of the alias. 656f971622SJuan Castillo * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are 666f971622SJuan Castillo * provided. Any other type will be printed as a raw ascii string. 676f971622SJuan Castillo * 686f971622SJuan Castillo * Return: 0 = success, Otherwise: error 696f971622SJuan Castillo */ 70*ad2c1a9aSJuan Castillo int ext_init(void) 716f971622SJuan Castillo { 726f971622SJuan Castillo ext_t *ext; 736f971622SJuan Castillo X509V3_EXT_METHOD *m; 74*ad2c1a9aSJuan Castillo int nid, ret; 75*ad2c1a9aSJuan Castillo unsigned int i; 766f971622SJuan Castillo 77*ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) { 78*ad2c1a9aSJuan Castillo ext = &extensions[i]; 79*ad2c1a9aSJuan Castillo /* Register command line option */ 80*ad2c1a9aSJuan Castillo if (ext->opt) { 81*ad2c1a9aSJuan Castillo if (cmd_opt_add(ext->opt, required_argument, 82*ad2c1a9aSJuan Castillo CMD_OPT_EXT)) { 83*ad2c1a9aSJuan Castillo return 1; 84*ad2c1a9aSJuan Castillo } 85*ad2c1a9aSJuan Castillo } 86*ad2c1a9aSJuan Castillo /* Register the extension OID in OpenSSL */ 87*ad2c1a9aSJuan Castillo if (ext->oid == NULL) { 88*ad2c1a9aSJuan Castillo continue; 89*ad2c1a9aSJuan Castillo } 906f971622SJuan Castillo nid = OBJ_create(ext->oid, ext->sn, ext->ln); 916f971622SJuan Castillo if (ext->alias) { 926f971622SJuan Castillo X509V3_EXT_add_alias(nid, ext->alias); 936f971622SJuan Castillo } else { 946f971622SJuan Castillo m = &ext->method; 956f971622SJuan Castillo memset(m, 0x0, sizeof(X509V3_EXT_METHOD)); 9655e291a4SJuan Castillo switch (ext->asn1_type) { 976f971622SJuan Castillo case V_ASN1_INTEGER: 986f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_INTEGER); 996f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER; 1006f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER; 1016f971622SJuan Castillo break; 1026f971622SJuan Castillo case V_ASN1_OCTET_STRING: 1036f971622SJuan Castillo m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING); 1046f971622SJuan Castillo m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING; 1056f971622SJuan Castillo m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING; 1066f971622SJuan Castillo break; 1076f971622SJuan Castillo default: 1086f971622SJuan Castillo continue; 1096f971622SJuan Castillo } 1106f971622SJuan Castillo m->ext_nid = nid; 1116f971622SJuan Castillo ret = X509V3_EXT_add(m); 1126f971622SJuan Castillo if (!ret) { 1136f971622SJuan Castillo ERR_print_errors_fp(stdout); 1146f971622SJuan Castillo return 1; 1156f971622SJuan Castillo } 1166f971622SJuan Castillo } 1176f971622SJuan Castillo } 1186f971622SJuan Castillo return 0; 1196f971622SJuan Castillo } 1206f971622SJuan Castillo 1216f971622SJuan Castillo /* 1226f971622SJuan Castillo * Create a new extension 1236f971622SJuan Castillo * 1246f971622SJuan Castillo * Extension ::= SEQUENCE { 1256f971622SJuan Castillo * id OBJECT IDENTIFIER, 1266f971622SJuan Castillo * critical BOOLEAN DEFAULT FALSE, 1276f971622SJuan Castillo * value OCTET STRING } 1286f971622SJuan Castillo * 1296f971622SJuan Castillo * Parameters: 1306f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 1316f971622SJuan Castillo * nid: extension identifier 1326f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 1336f971622SJuan Castillo * data: extension data. This data will be encapsulated in an Octet String 1346f971622SJuan Castillo * 1356f971622SJuan Castillo * Return: Extension address, NULL if error 1366f971622SJuan Castillo */ 1376f971622SJuan Castillo static 1386f971622SJuan Castillo X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len) 1396f971622SJuan Castillo { 1406f971622SJuan Castillo X509_EXTENSION *ex; 1416f971622SJuan Castillo ASN1_OCTET_STRING *ext_data; 1426f971622SJuan Castillo 1436f971622SJuan Castillo /* Octet string containing the extension data */ 1446f971622SJuan Castillo ext_data = ASN1_OCTET_STRING_new(); 1456f971622SJuan Castillo ASN1_OCTET_STRING_set(ext_data, data, len); 1466f971622SJuan Castillo 1476f971622SJuan Castillo /* Create the extension */ 1486f971622SJuan Castillo ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data); 1496f971622SJuan Castillo 1506f971622SJuan Castillo /* The extension makes a copy of the data, so we can free this object */ 1516f971622SJuan Castillo ASN1_OCTET_STRING_free(ext_data); 1526f971622SJuan Castillo 1536f971622SJuan Castillo return ex; 1546f971622SJuan Castillo } 1556f971622SJuan Castillo 1566f971622SJuan Castillo /* 157c3da66b1SJuan Castillo * Creates a x509v3 extension containing a hash 158c3da66b1SJuan Castillo * 159c3da66b1SJuan Castillo * DigestInfo ::= SEQUENCE { 160c3da66b1SJuan Castillo * digestAlgorithm AlgorithmIdentifier, 161c3da66b1SJuan Castillo * digest OCTET STRING 162c3da66b1SJuan Castillo * } 163c3da66b1SJuan Castillo * 164c3da66b1SJuan Castillo * AlgorithmIdentifier ::= SEQUENCE { 165c3da66b1SJuan Castillo * algorithm OBJECT IDENTIFIER, 166c3da66b1SJuan Castillo * parameters ANY DEFINED BY algorithm OPTIONAL 167c3da66b1SJuan Castillo * } 1686f971622SJuan Castillo * 1696f971622SJuan Castillo * Parameters: 1706f971622SJuan Castillo * nid: extension identifier 1716f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 172c3da66b1SJuan Castillo * md: hash algorithm 1736f971622SJuan Castillo * buf: pointer to the buffer that contains the hash 1746f971622SJuan Castillo * len: size of the hash in bytes 1756f971622SJuan Castillo * 1766f971622SJuan Castillo * Return: Extension address, NULL if error 1776f971622SJuan Castillo */ 178c3da66b1SJuan Castillo X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, 179c3da66b1SJuan Castillo unsigned char *buf, size_t len) 1806f971622SJuan Castillo { 1816f971622SJuan Castillo X509_EXTENSION *ex = NULL; 182c3da66b1SJuan Castillo ASN1_OCTET_STRING *octet = NULL; 183c3da66b1SJuan Castillo HASH *hash = NULL; 184c3da66b1SJuan Castillo ASN1_OBJECT *algorithm = NULL; 185c3da66b1SJuan Castillo X509_ALGOR *x509_algor = NULL; 1866f971622SJuan Castillo unsigned char *p = NULL; 1876f971622SJuan Castillo int sz = -1; 1886f971622SJuan Castillo 189c3da66b1SJuan Castillo /* OBJECT_IDENTIFIER with hash algorithm */ 190c3da66b1SJuan Castillo algorithm = OBJ_nid2obj(md->type); 191c3da66b1SJuan Castillo if (algorithm == NULL) { 192c3da66b1SJuan Castillo return NULL; 193c3da66b1SJuan Castillo } 194c3da66b1SJuan Castillo 195c3da66b1SJuan Castillo /* Create X509_ALGOR */ 196c3da66b1SJuan Castillo x509_algor = X509_ALGOR_new(); 197c3da66b1SJuan Castillo if (x509_algor == NULL) { 198c3da66b1SJuan Castillo return NULL; 199c3da66b1SJuan Castillo } 200c3da66b1SJuan Castillo x509_algor->algorithm = algorithm; 201c3da66b1SJuan Castillo x509_algor->parameter = ASN1_TYPE_new(); 202c3da66b1SJuan Castillo ASN1_TYPE_set(x509_algor->parameter, V_ASN1_NULL, NULL); 203c3da66b1SJuan Castillo 204c3da66b1SJuan Castillo /* OCTET_STRING with the actual hash */ 205c3da66b1SJuan Castillo octet = ASN1_OCTET_STRING_new(); 206c3da66b1SJuan Castillo if (octet == NULL) { 207c3da66b1SJuan Castillo X509_ALGOR_free(x509_algor); 208c3da66b1SJuan Castillo return NULL; 209c3da66b1SJuan Castillo } 210c3da66b1SJuan Castillo ASN1_OCTET_STRING_set(octet, buf, len); 211c3da66b1SJuan Castillo 212c3da66b1SJuan Castillo /* HASH structure containing algorithm + hash */ 213c3da66b1SJuan Castillo hash = HASH_new(); 214c3da66b1SJuan Castillo if (hash == NULL) { 215c3da66b1SJuan Castillo ASN1_OCTET_STRING_free(octet); 216c3da66b1SJuan Castillo X509_ALGOR_free(x509_algor); 217c3da66b1SJuan Castillo return NULL; 218c3da66b1SJuan Castillo } 219c3da66b1SJuan Castillo hash->hashAlgorithm = x509_algor; 220c3da66b1SJuan Castillo hash->dataHash = octet; 221c3da66b1SJuan Castillo 222c3da66b1SJuan Castillo /* DER encoded HASH */ 223c3da66b1SJuan Castillo sz = i2d_HASH(hash, &p); 224c3da66b1SJuan Castillo if ((sz <= 0) || (p == NULL)) { 225c3da66b1SJuan Castillo HASH_free(hash); 226c3da66b1SJuan Castillo X509_ALGOR_free(x509_algor); 227c3da66b1SJuan Castillo return NULL; 228c3da66b1SJuan Castillo } 2296f971622SJuan Castillo 2306f971622SJuan Castillo /* Create the extension */ 2316f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 2326f971622SJuan Castillo 2336f971622SJuan Castillo /* Clean up */ 2346f971622SJuan Castillo OPENSSL_free(p); 235c3da66b1SJuan Castillo HASH_free(hash); 2366f971622SJuan Castillo 2376f971622SJuan Castillo return ex; 2386f971622SJuan Castillo } 2396f971622SJuan Castillo 2406f971622SJuan Castillo /* 2416f971622SJuan Castillo * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1 2426f971622SJuan Castillo * Integer 2436f971622SJuan Castillo * 2446f971622SJuan Castillo * Parameters: 2456f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 2466f971622SJuan Castillo * nid: extension identifier 2476f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 2486f971622SJuan Castillo * value: nvcounter value 2496f971622SJuan Castillo * 2506f971622SJuan Castillo * Return: Extension address, NULL if error 2516f971622SJuan Castillo */ 2526f971622SJuan Castillo X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value) 2536f971622SJuan Castillo { 2546f971622SJuan Castillo X509_EXTENSION *ex = NULL; 2556f971622SJuan Castillo ASN1_INTEGER *counter = NULL; 2566f971622SJuan Castillo unsigned char *p = NULL; 2576f971622SJuan Castillo int sz = -1; 2586f971622SJuan Castillo 2596f971622SJuan Castillo /* Encode counter */ 2606f971622SJuan Castillo counter = ASN1_INTEGER_new(); 2616f971622SJuan Castillo ASN1_INTEGER_set(counter, value); 2626f971622SJuan Castillo sz = i2d_ASN1_INTEGER(counter, NULL); 2636f971622SJuan Castillo i2d_ASN1_INTEGER(counter, &p); 2646f971622SJuan Castillo 2656f971622SJuan Castillo /* Create the extension */ 2666f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 2676f971622SJuan Castillo 2686f971622SJuan Castillo /* Free objects */ 2696f971622SJuan Castillo OPENSSL_free(p); 2706f971622SJuan Castillo ASN1_INTEGER_free(counter); 2716f971622SJuan Castillo 2726f971622SJuan Castillo return ex; 2736f971622SJuan Castillo } 2746f971622SJuan Castillo 2756f971622SJuan Castillo /* 2766f971622SJuan Castillo * Creates a x509v3 extension containing a public key in DER format: 2776f971622SJuan Castillo * 2786f971622SJuan Castillo * SubjectPublicKeyInfo ::= SEQUENCE { 2796f971622SJuan Castillo * algorithm AlgorithmIdentifier, 2806f971622SJuan Castillo * subjectPublicKey BIT STRING } 2816f971622SJuan Castillo * 2826f971622SJuan Castillo * Parameters: 2836f971622SJuan Castillo * pex: OpenSSL extension pointer (output parameter) 2846f971622SJuan Castillo * nid: extension identifier 2856f971622SJuan Castillo * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) 2866f971622SJuan Castillo * k: key 2876f971622SJuan Castillo * 2886f971622SJuan Castillo * Return: Extension address, NULL if error 2896f971622SJuan Castillo */ 2906f971622SJuan Castillo X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k) 2916f971622SJuan Castillo { 2926f971622SJuan Castillo X509_EXTENSION *ex = NULL; 2936f971622SJuan Castillo unsigned char *p = NULL; 2946f971622SJuan Castillo int sz = -1; 2956f971622SJuan Castillo 2966f971622SJuan Castillo /* Encode key */ 2976f971622SJuan Castillo BIO *mem = BIO_new(BIO_s_mem()); 2986f971622SJuan Castillo if (i2d_PUBKEY_bio(mem, k) <= 0) { 2996f971622SJuan Castillo ERR_print_errors_fp(stderr); 3006f971622SJuan Castillo return NULL; 3016f971622SJuan Castillo } 3026f971622SJuan Castillo p = (unsigned char *)OPENSSL_malloc(4096); 3036f971622SJuan Castillo sz = BIO_read(mem, p, 4096); 3046f971622SJuan Castillo 3056f971622SJuan Castillo /* Create the extension */ 3066f971622SJuan Castillo ex = ext_new(nid, crit, p, sz); 3076f971622SJuan Castillo 3086f971622SJuan Castillo /* Clean up */ 3096f971622SJuan Castillo OPENSSL_free(p); 3106f971622SJuan Castillo 3116f971622SJuan Castillo return ex; 3126f971622SJuan Castillo } 313*ad2c1a9aSJuan Castillo 314*ad2c1a9aSJuan Castillo ext_t *ext_get_by_opt(const char *opt) 315*ad2c1a9aSJuan Castillo { 316*ad2c1a9aSJuan Castillo ext_t *ext = NULL; 317*ad2c1a9aSJuan Castillo unsigned int i; 318*ad2c1a9aSJuan Castillo 319*ad2c1a9aSJuan Castillo /* Sequential search. This is not a performance concern since the number 320*ad2c1a9aSJuan Castillo * of extensions is bounded and the code runs on a host machine */ 321*ad2c1a9aSJuan Castillo for (i = 0; i < num_extensions; i++) { 322*ad2c1a9aSJuan Castillo ext = &extensions[i]; 323*ad2c1a9aSJuan Castillo if (ext->opt && !strcmp(ext->opt, opt)) { 324*ad2c1a9aSJuan Castillo return ext; 325*ad2c1a9aSJuan Castillo } 326*ad2c1a9aSJuan Castillo } 327*ad2c1a9aSJuan Castillo 328*ad2c1a9aSJuan Castillo return NULL; 329*ad2c1a9aSJuan Castillo } 330