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