Coverage Report

Created: 2026-05-30 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/p11-kit/common/asn1.c
Line
Count
Source
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
0
#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
50
free_asn1_def (void *data)
51
5.18k
{
52
5.18k
  asn1_node def = data;
53
5.18k
  asn1_delete_structure (&def);
54
5.18k
}
55
56
struct {
57
  const asn1_static_node *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 *
67
p11_asn1_defs_load (void)
68
2.59k
{
69
2.59k
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
70
2.59k
  asn1_node def;
71
2.59k
  p11_dict *defs;
72
2.59k
  int ret;
73
2.59k
  int i;
74
75
2.59k
  defs = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, free_asn1_def);
76
2.59k
  return_val_if_fail (defs != NULL, NULL);
77
78
7.77k
  for (i = 0; asn1_tabs[i].tab != NULL; i++) {
79
5.18k
    def = NULL;
80
5.18k
    ret = asn1_array2tree (asn1_tabs[i].tab, &def, message);
81
5.18k
    if (ret != ASN1_SUCCESS) {
82
0
      p11_debug_precond ("failed to load %s* definitions: %s: %s\n",
83
0
                         asn1_tabs[i].prefix, asn1_strerror (ret), message);
84
0
      p11_dict_free (defs);
85
0
      return NULL;
86
0
    }
87
88
5.18k
    if (!p11_dict_set (defs, (void *)asn1_tabs[i].prefix, def)) {
89
0
      asn1_delete_structure (&def);
90
0
      p11_dict_free (defs);
91
0
      return_val_if_reached (NULL);
92
0
    }
93
5.18k
  }
94
95
2.59k
  return defs;
96
2.59k
}
97
98
static asn1_node
99
lookup_def (p11_dict *asn1_defs,
100
            const char *struct_name)
101
19.0k
{
102
19.0k
  int i;
103
104
22.1k
  for (i = 0; asn1_tabs[i].tab != NULL; i++) {
105
22.1k
    if (strncmp (struct_name, asn1_tabs[i].prefix, asn1_tabs[i].prefix_len) == 0)
106
19.0k
      return p11_dict_get (asn1_defs, asn1_tabs[i].prefix);
107
22.1k
  }
108
109
0
  p11_debug_precond ("unknown prefix for element: %s\n", struct_name);
110
0
  return NULL;
111
19.0k
}
112
113
asn1_node
114
p11_asn1_create (p11_dict *asn1_defs,
115
                 const char *struct_name)
116
19.0k
{
117
19.0k
  asn1_node def;
118
19.0k
  asn1_node asn;
119
19.0k
  int ret;
120
121
19.0k
  return_val_if_fail (asn1_defs != NULL, NULL);
122
123
19.0k
  def = lookup_def (asn1_defs, struct_name);
124
19.0k
  return_val_if_fail (def != NULL, NULL);
125
126
19.0k
  ret = asn1_create_element (def, struct_name, &asn);
127
19.0k
  if (ret != ASN1_SUCCESS) {
128
0
    p11_debug_precond ("failed to create element %s: %s\n",
129
0
                       struct_name, asn1_strerror (ret));
130
0
    return NULL;
131
0
  }
132
133
19.0k
  return asn;
134
19.0k
}
135
136
asn1_node
137
p11_asn1_decode (p11_dict *asn1_defs,
138
                 const char *struct_name,
139
                 const unsigned char *der,
140
                 size_t der_len,
141
                 char *message)
142
10.1k
{
143
10.1k
  char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
144
10.1k
  asn1_node asn = NULL;
145
10.1k
  int ret;
146
147
10.1k
  return_val_if_fail (asn1_defs != NULL, NULL);
148
149
10.1k
  asn = p11_asn1_create (asn1_defs, struct_name);
150
10.1k
  return_val_if_fail (asn != NULL, NULL);
151
152
  /* asn1_der_decoding destroys the element if fails */
153
10.1k
  ret = asn1_der_decoding (&asn, der, der_len, message ? message : msg);
154
10.1k
  if (ret != ASN1_SUCCESS) {
155
    /* If caller passed in a message buffer, assume they're logging */
156
3.50k
    if (!message)
157
0
      p11_debug ("couldn't parse %s: %s: %s",
158
3.50k
                 struct_name, asn1_strerror (ret), msg);
159
3.50k
    return NULL;
160
3.50k
  }
161
162
6.60k
  return asn;
163
10.1k
}
164
165
unsigned char *
166
p11_asn1_encode (asn1_node asn,
167
                 size_t *der_len)
168
9.32k
{
169
9.32k
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
170
9.32k
  unsigned char *der = NULL;
171
9.32k
  int len;
172
9.32k
  int ret;
173
174
9.32k
  return_val_if_fail (der_len != NULL, NULL);
175
176
9.32k
  len = 0;
177
9.32k
  ret = asn1_der_coding (asn, "", NULL, &len, message);
178
9.32k
  return_val_if_fail (ret != ASN1_SUCCESS, NULL);
179
180
9.32k
  if (ret == ASN1_MEM_ERROR) {
181
9.32k
    der = malloc (len);
182
9.32k
    return_val_if_fail (der != NULL, NULL);
183
184
9.32k
    ret = asn1_der_coding (asn, "", der, &len, message);
185
9.32k
  }
186
187
9.32k
  if (ret != ASN1_SUCCESS) {
188
2
    p11_debug_precond ("failed to encode: %s\n", message);
189
2
    free (der);
190
2
    return NULL;
191
2
  }
192
193
9.32k
  if (der_len)
194
9.32k
    *der_len = len;
195
9.32k
  return der;
196
9.32k
}
197
198
void *
199
p11_asn1_read (asn1_node asn,
200
               const char *field,
201
               size_t *length)
202
9.90k
{
203
9.90k
  unsigned char *value;
204
9.90k
  int len;
205
9.90k
  int ret;
206
207
9.90k
  return_val_if_fail (asn != NULL, NULL);
208
9.90k
  return_val_if_fail (field != NULL, NULL);
209
9.90k
  return_val_if_fail (length != NULL, NULL);
210
211
9.90k
  len = 0;
212
9.90k
  ret = asn1_read_value (asn, field, NULL, &len);
213
9.90k
  if (ret == ASN1_ELEMENT_NOT_FOUND)
214
6.09k
    return NULL;
215
216
3.81k
  return_val_if_fail (ret == ASN1_MEM_ERROR, NULL);
217
218
3.80k
  value = malloc (len + 1);
219
3.80k
  return_val_if_fail (value != NULL, NULL);
220
221
3.80k
  ret = asn1_read_value (asn, field, value, &len);
222
3.80k
  if (ret != ASN1_SUCCESS) {
223
0
    free (value);
224
0
    return_val_if_reached (NULL);
225
0
  }
226
227
  /* Courtesy zero terminated */
228
3.80k
  value[len] = '\0';
229
230
3.80k
  *length = len;
231
3.80k
  return value;
232
3.80k
}
233
234
void
235
p11_asn1_free (void *asn)
236
0
{
237
0
  asn1_node node = asn;
238
0
  if (node != NULL)
239
0
    asn1_delete_structure (&node);
240
0
}
241
242
ssize_t
243
p11_asn1_tlv_length (const unsigned char *data,
244
                     size_t length)
245
5.17k
{
246
5.17k
  unsigned char cls;
247
5.17k
  int counter = 0;
248
5.17k
  int cb, len;
249
5.17k
  unsigned long tag;
250
251
5.17k
  if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) {
252
4.71k
    counter += cb;
253
4.71k
    len = asn1_get_length_der (data + cb, length - cb, &cb);
254
4.71k
    counter += cb;
255
4.71k
    if (len >= 0) {
256
4.16k
      len += counter;
257
4.16k
      if (length >= len)
258
4.16k
        return len;
259
4.16k
    }
260
4.71k
  }
261
262
1.00k
  return -1;
263
5.17k
}
264
265
typedef struct {
266
  asn1_node node;
267
  char *struct_name;
268
  size_t length;
269
} asn1_item;
270
271
static void
272
free_asn1_item (void *data)
273
0
{
274
0
  asn1_item *item = data;
275
0
  free (item->struct_name);
276
0
  asn1_delete_structure (&item->node);
277
0
  free (item);
278
0
}
279
280
struct _p11_asn1_cache {
281
  p11_dict *defs;
282
  p11_dict *items;
283
};
284
285
p11_asn1_cache *
286
p11_asn1_cache_new (void)
287
0
{
288
0
  p11_asn1_cache *cache;
289
290
0
  cache = calloc (1, sizeof (p11_asn1_cache));
291
0
  return_val_if_fail (cache != NULL, NULL);
292
293
0
  cache->defs = p11_asn1_defs_load ();
294
0
  if (cache->defs == NULL) {
295
0
    p11_asn1_cache_free (cache);
296
0
    return_val_if_reached (NULL);
297
0
  }
298
299
0
  cache->items = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal,
300
0
                               NULL, free_asn1_item);
301
0
  if (cache->items == NULL) {
302
0
    p11_asn1_cache_free (cache);
303
0
    return_val_if_reached (NULL);
304
0
  }
305
306
0
  return cache;
307
0
}
308
309
asn1_node
310
p11_asn1_cache_get (p11_asn1_cache *cache,
311
                    const char *struct_name,
312
                    const unsigned char *der,
313
                    size_t der_len)
314
0
{
315
0
  asn1_item *item;
316
317
0
  if (cache == NULL)
318
0
    return NULL;
319
320
0
  return_val_if_fail (struct_name != NULL, NULL);
321
0
  return_val_if_fail (der != NULL, NULL);
322
323
0
  item = p11_dict_get (cache->items, der);
324
0
  if (item != NULL) {
325
0
    return_val_if_fail (item->length == der_len, NULL);
326
0
    return_val_if_fail (strcmp (item->struct_name, struct_name) == 0, NULL);
327
0
    return item->node;
328
0
  }
329
330
0
  return NULL;
331
0
}
332
333
void
334
p11_asn1_cache_take (p11_asn1_cache *cache,
335
                     asn1_node node,
336
                     const char *struct_name,
337
                     const unsigned char *der,
338
                     size_t der_len)
339
8.61k
{
340
8.61k
  asn1_item *item;
341
342
8.61k
  if (cache == NULL) {
343
8.61k
    asn1_delete_structure (&node);
344
8.61k
    return;
345
8.61k
  }
346
347
0
  return_if_fail (struct_name != NULL);
348
0
  return_if_fail (der != NULL);
349
0
  return_if_fail (der_len != 0);
350
351
0
  item = calloc (1, sizeof (asn1_item));
352
0
  if (item == NULL) {
353
0
    asn1_delete_structure (&node);
354
0
    return_if_reached ();
355
0
  }
356
357
0
  item->length = der_len;
358
0
  item->node = node;
359
0
  item->struct_name = strdup (struct_name);
360
0
  if (item->struct_name == NULL) {
361
0
    free_asn1_item (item);
362
0
    return_if_reached ();
363
0
  }
364
365
0
  if (!p11_dict_set (cache->items, (void *)der, item)) {
366
0
    free_asn1_item (item);
367
0
    return_if_reached ();
368
0
  }
369
0
}
370
371
void
372
p11_asn1_cache_flush (p11_asn1_cache *cache)
373
2.59k
{
374
2.59k
  if (cache == NULL)
375
2.59k
    return;
376
0
  p11_dict_clear (cache->items);
377
0
}
378
379
p11_dict *
380
p11_asn1_cache_defs (p11_asn1_cache *cache)
381
0
{
382
0
  return_val_if_fail (cache != NULL, NULL);
383
0
  return cache->defs;
384
0
}
385
386
void
387
p11_asn1_cache_free (p11_asn1_cache *cache)
388
0
{
389
0
  if (cache == NULL)
390
0
    return;
391
0
  p11_dict_free (cache->items);
392
0
  p11_dict_free (cache->defs);
393
0
  free (cache);
394
0
}