1 /*
2 * Copyright (C) 2012 Red Hat Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 * * Redistributions in binary form must reproduce the
12 * above copyright notice, this list of conditions and
13 * the following disclaimer in the documentation and/or
14 * other materials provided with the distribution.
15 * * The names of contributors to this software may not be
16 * used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30 * DAMAGE.
31 *
32 * Author: Stef Walter <stefw@redhat.com>
33 */
34
35 #include "config.h"
36
37 #include "asn1.h"
38 #define P11_DEBUG_FLAG P11_DEBUG_TRUST
39 #include "debug.h"
40 #include "oid.h"
41
42 #include "openssl.asn.h"
43 #include "pkix.asn.h"
44
45 #include <assert.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 static void
free_asn1_def(void * data)50 free_asn1_def (void *data)
51 {
52 node_asn *def = data;
53 asn1_delete_structure (&def);
54 }
55
56 struct {
57 const ASN1_ARRAY_TYPE* tab;
58 const char *prefix;
59 int prefix_len;
60 } asn1_tabs[] = {
61 { pkix_asn1_tab, "PKIX1.", 6 },
62 { openssl_asn1_tab, "OPENSSL.", 8 },
63 { NULL, },
64 };
65
66 p11_dict *
p11_asn1_defs_load(void)67 p11_asn1_defs_load (void)
68 {
69 char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
70 node_asn *def;
71 p11_dict *defs;
72 int ret;
73 int i;
74
75 defs = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, free_asn1_def);
76
77 for (i = 0; asn1_tabs[i].tab != NULL; i++) {
78
79 def = NULL;
80 ret = asn1_array2tree (asn1_tabs[i].tab, &def, message);
81 if (ret != ASN1_SUCCESS) {
82 p11_debug_precond ("failed to load %s* definitions: %s: %s\n",
83 asn1_tabs[i].prefix, asn1_strerror (ret), message);
84 return NULL;
85 }
86
87 if (!p11_dict_set (defs, (void *)asn1_tabs[i].prefix, def))
88 return_val_if_reached (NULL);
89 }
90
91 return defs;
92 }
93
94 static node_asn *
lookup_def(p11_dict * asn1_defs,const char * struct_name)95 lookup_def (p11_dict *asn1_defs,
96 const char *struct_name)
97 {
98 int i;
99
100 for (i = 0; asn1_tabs[i].tab != NULL; i++) {
101 if (strncmp (struct_name, asn1_tabs[i].prefix, asn1_tabs[i].prefix_len) == 0)
102 return p11_dict_get (asn1_defs, asn1_tabs[i].prefix);
103 }
104
105 p11_debug_precond ("unknown prefix for element: %s\n", struct_name);
106 return NULL;
107 }
108
109 node_asn *
p11_asn1_create(p11_dict * asn1_defs,const char * struct_name)110 p11_asn1_create (p11_dict *asn1_defs,
111 const char *struct_name)
112 {
113 node_asn *def;
114 node_asn *asn;
115 int ret;
116
117 return_val_if_fail (asn1_defs != NULL, NULL);
118
119 def = lookup_def (asn1_defs, struct_name);
120 return_val_if_fail (def != NULL, NULL);
121
122 ret = asn1_create_element (def, struct_name, &asn);
123 if (ret != ASN1_SUCCESS) {
124 p11_debug_precond ("failed to create element %s: %s\n",
125 struct_name, asn1_strerror (ret));
126 return NULL;
127 }
128
129 return asn;
130 }
131
132 node_asn *
p11_asn1_decode(p11_dict * asn1_defs,const char * struct_name,const unsigned char * der,size_t der_len,char * message)133 p11_asn1_decode (p11_dict *asn1_defs,
134 const char *struct_name,
135 const unsigned char *der,
136 size_t der_len,
137 char *message)
138 {
139 char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
140 node_asn *asn = NULL;
141 int ret;
142
143 return_val_if_fail (asn1_defs != NULL, NULL);
144
145 asn = p11_asn1_create (asn1_defs, struct_name);
146 return_val_if_fail (asn != NULL, NULL);
147
148 /* asn1_der_decoding destroys the element if fails */
149 ret = asn1_der_decoding (&asn, der, der_len, message ? message : msg);
150
151 if (ret != ASN1_SUCCESS) {
152 /* If caller passed in a message buffer, assume they're logging */
153 if (!message) {
154 p11_debug ("couldn't parse %s: %s: %s",
155 struct_name, asn1_strerror (ret), msg);
156 }
157 return NULL;
158 }
159
160 return asn;
161 }
162
163 unsigned char *
p11_asn1_encode(node_asn * asn,size_t * der_len)164 p11_asn1_encode (node_asn *asn,
165 size_t *der_len)
166 {
167 char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
168 unsigned char *der;
169 int len;
170 int ret;
171
172 return_val_if_fail (der_len != NULL, NULL);
173
174 len = 0;
175 ret = asn1_der_coding (asn, "", NULL, &len, message);
176 return_val_if_fail (ret != ASN1_SUCCESS, NULL);
177
178 if (ret == ASN1_MEM_ERROR) {
179 der = malloc (len);
180 return_val_if_fail (der != NULL, NULL);
181
182 ret = asn1_der_coding (asn, "", der, &len, message);
183 }
184
185 if (ret != ASN1_SUCCESS) {
186 p11_debug_precond ("failed to encode: %s\n", message);
187 return NULL;
188 }
189
190 if (der_len)
191 *der_len = len;
192 return der;
193 }
194
195 void *
p11_asn1_read(node_asn * asn,const char * field,size_t * length)196 p11_asn1_read (node_asn *asn,
197 const char *field,
198 size_t *length)
199 {
200 unsigned char *value;
201 int len;
202 int ret;
203
204 return_val_if_fail (asn != NULL, NULL);
205 return_val_if_fail (field != NULL, NULL);
206 return_val_if_fail (length != NULL, NULL);
207
208 len = 0;
209 ret = asn1_read_value (asn, field, NULL, &len);
210 if (ret == ASN1_ELEMENT_NOT_FOUND)
211 return NULL;
212
213 return_val_if_fail (ret == ASN1_MEM_ERROR, NULL);
214
215 value = malloc (len + 1);
216 return_val_if_fail (value != NULL, NULL);
217
218 ret = asn1_read_value (asn, field, value, &len);
219 return_val_if_fail (ret == ASN1_SUCCESS, NULL);
220
221 /* Courtesy zero terminated */
222 value[len] = '\0';
223
224 *length = len;
225 return value;
226 }
227
228 void
p11_asn1_free(void * asn)229 p11_asn1_free (void *asn)
230 {
231 node_asn *node = asn;
232 if (node != NULL)
233 asn1_delete_structure (&node);
234 }
235
236 ssize_t
p11_asn1_tlv_length(const unsigned char * data,size_t length)237 p11_asn1_tlv_length (const unsigned char *data,
238 size_t length)
239 {
240 unsigned char cls;
241 int counter = 0;
242 int cb, len;
243 unsigned long tag;
244
245 if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) {
246 counter += cb;
247 len = asn1_get_length_der (data + cb, length - cb, &cb);
248 counter += cb;
249 if (len >= 0) {
250 len += counter;
251 if (length >= len)
252 return len;
253 }
254 }
255
256 return -1;
257 }
258
259 typedef struct {
260 node_asn *node;
261 char *struct_name;
262 size_t length;
263 } asn1_item;
264
265 static void
free_asn1_item(void * data)266 free_asn1_item (void *data)
267 {
268 asn1_item *item = data;
269 free (item->struct_name);
270 asn1_delete_structure (&item->node);
271 free (item);
272 }
273
274 struct _p11_asn1_cache {
275 p11_dict *defs;
276 p11_dict *items;
277 };
278
279 p11_asn1_cache *
p11_asn1_cache_new(void)280 p11_asn1_cache_new (void)
281 {
282 p11_asn1_cache *cache;
283
284 cache = calloc (1, sizeof (p11_asn1_cache));
285 return_val_if_fail (cache != NULL, NULL);
286
287 cache->defs = p11_asn1_defs_load ();
288 if (cache->defs == NULL) {
289 p11_asn1_cache_free (cache);
290 return_val_if_reached (NULL);
291 }
292
293 cache->items = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal,
294 NULL, free_asn1_item);
295 if (cache->items == NULL) {
296 p11_asn1_cache_free (cache);
297 return_val_if_reached (NULL);
298 }
299
300 return cache;
301 }
302
303 node_asn *
p11_asn1_cache_get(p11_asn1_cache * cache,const char * struct_name,const unsigned char * der,size_t der_len)304 p11_asn1_cache_get (p11_asn1_cache *cache,
305 const char *struct_name,
306 const unsigned char *der,
307 size_t der_len)
308 {
309 asn1_item *item;
310
311 if (cache == NULL)
312 return NULL;
313
314 return_val_if_fail (struct_name != NULL, NULL);
315 return_val_if_fail (der != NULL, NULL);
316
317 item = p11_dict_get (cache->items, der);
318 if (item != NULL) {
319 return_val_if_fail (item->length == der_len, NULL);
320 return_val_if_fail (strcmp (item->struct_name, struct_name) == 0, NULL);
321 return item->node;
322 }
323
324 return NULL;
325 }
326
327 void
p11_asn1_cache_take(p11_asn1_cache * cache,node_asn * node,const char * struct_name,const unsigned char * der,size_t der_len)328 p11_asn1_cache_take (p11_asn1_cache *cache,
329 node_asn *node,
330 const char *struct_name,
331 const unsigned char *der,
332 size_t der_len)
333 {
334 asn1_item *item;
335
336 if (cache == NULL) {
337 asn1_delete_structure (&node);
338 return;
339 }
340
341 return_if_fail (struct_name != NULL);
342 return_if_fail (der != NULL);
343 return_if_fail (der_len != 0);
344
345 item = calloc (1, sizeof (asn1_item));
346 return_if_fail (item != NULL);
347
348 item->length = der_len;
349 item->node = node;
350 item->struct_name = strdup (struct_name);
351 if (item->struct_name == NULL) {
352 free_asn1_item (item);
353 return_if_reached ();
354 }
355
356 if (!p11_dict_set (cache->items, (void *)der, item))
357 return_if_reached ();
358 }
359
360 void
p11_asn1_cache_flush(p11_asn1_cache * cache)361 p11_asn1_cache_flush (p11_asn1_cache *cache)
362 {
363 if (cache == NULL)
364 return;
365 p11_dict_clear (cache->items);
366 }
367
368 p11_dict *
p11_asn1_cache_defs(p11_asn1_cache * cache)369 p11_asn1_cache_defs (p11_asn1_cache *cache)
370 {
371 return_val_if_fail (cache != NULL, NULL);
372 return cache->defs;
373 }
374
375 void
p11_asn1_cache_free(p11_asn1_cache * cache)376 p11_asn1_cache_free (p11_asn1_cache *cache)
377 {
378 if (!cache)
379 return;
380 p11_dict_free (cache->items);
381 p11_dict_free (cache->defs);
382 free (cache);
383 }
384