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
ext_new(int nid,int crit,unsigned char * data,int len)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  */
ext_new_hash(int nid,int crit,const EVP_MD * md,unsigned char * buf,size_t len)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  */
ext_new_nvcounter(int nid,int crit,int value)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  */
ext_new_key(int nid,int crit,EVP_PKEY * k)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 
ext_get_by_opt(const char * opt)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