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