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