Coverage Report

Created: 2026-08-08 07:17

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
6.70k
{
52
6.70k
  asn1_node def = data;
53
6.70k
  asn1_delete_structure (&def);
54
6.70k
}
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
3.35k
{
69
3.35k
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
70
3.35k
  asn1_node def;
71
3.35k
  p11_dict *defs;
72
3.35k
  int ret;
73
3.35k
  int i;
74
75
3.35k
  defs = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, free_asn1_def);
76
3.35k
  return_val_if_fail (defs != NULL, NULL);
77
78
10.0k
  for (i = 0; asn1_tabs[i].tab != NULL; i++) {
79
6.70k
    def = NULL;
80
6.70k
    ret = asn1_array2tree (asn1_tabs[i].tab, &def, message);
81
6.70k
    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
6.70k
    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
6.70k
  }
94
95
3.35k
  return defs;
96
3.35k
}
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.6k
{
143
10.6k
  char msg[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
144
10.6k
  asn1_node asn = NULL;
145
10.6k
  int ret;
146
147
10.6k
  return_val_if_fail (asn1_defs != NULL, NULL);
148
149
10.6k
  asn = p11_asn1_create (asn1_defs, struct_name);
150
10.6k
  return_val_if_fail (asn != NULL, NULL);
151
152
  /* asn1_der_decoding destroys the element if fails */
153
10.6k
  ret = asn1_der_decoding (&asn, der, der_len, message ? message : msg);
154
10.6k
  if (ret != ASN1_SUCCESS) {
155
    /* If caller passed in a message buffer, assume they're logging */
156
4.22k
    if (!message)
157
0
      p11_debug ("couldn't parse %s: %s: %s",
158
4.22k
                 struct_name, asn1_strerror (ret), msg);
159
4.22k
    return NULL;
160
4.22k
  }
161
162
6.38k
  return asn;
163
10.6k
}
164
165
unsigned char *
166
p11_asn1_encode (asn1_node asn,
167
                 size_t *der_len)
168
8.58k
{
169
8.58k
  char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
170
8.58k
  unsigned char *der = NULL;
171
8.58k
  int len;
172
8.58k
  int ret;
173
174
8.58k
  return_val_if_fail (der_len != NULL, NULL);
175
176
8.58k
  len = 0;
177
8.58k
  ret = asn1_der_coding (asn, "", NULL, &len, message);
178
8.58k
  return_val_if_fail (ret != ASN1_SUCCESS, NULL);
179
180
8.58k
  if (ret == ASN1_MEM_ERROR) {
181
8.57k
    der = malloc (len);
182
8.57k
    return_val_if_fail (der != NULL, NULL);
183
184
8.57k
    ret = asn1_der_coding (asn, "", der, &len, message);
185
8.57k
  }
186
187
8.58k
  if (ret != ASN1_SUCCESS) {
188
3
    p11_debug_precond ("failed to encode: %s\n", message);
189
3
    free (der);
190
3
    return NULL;
191
3
  }
192
193
8.57k
  if (der_len)
194
8.57k
    *der_len = len;
195
8.57k
  return der;
196
8.58k
}
197
198
void *
199
p11_asn1_read (asn1_node asn,
200
               const char *field,
201
               size_t *length)
202
12.3k
{
203
12.3k
  unsigned char *value;
204
12.3k
  int len;
205
12.3k
  int ret;
206
207
12.3k
  return_val_if_fail (asn != NULL, NULL);
208
12.3k
  return_val_if_fail (field != NULL, NULL);
209
12.3k
  return_val_if_fail (length != NULL, NULL);
210
211
12.3k
  len = 0;
212
12.3k
  ret = asn1_read_value (asn, field, NULL, &len);
213
12.3k
  if (ret == ASN1_ELEMENT_NOT_FOUND)
214
5.73k
    return NULL;
215
216
6.56k
  return_val_if_fail (ret == ASN1_MEM_ERROR, NULL);
217
218
6.37k
  value = malloc (len + 1);
219
6.37k
  return_val_if_fail (value != NULL, NULL);
220
221
6.37k
  ret = asn1_read_value (asn, field, value, &len);
222
6.37k
  if (ret != ASN1_SUCCESS) {
223
0
    free (value);
224
0
    return_val_if_reached (NULL);
225
0
  }
226
227
  /* Courtesy zero terminated */
228
6.37k
  value[len] = '\0';
229
230
6.37k
  *length = len;
231
6.37k
  return value;
232
6.37k
}
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
4.36k
{
246
4.36k
  unsigned char cls;
247
4.36k
  int counter = 0;
248
4.36k
  int cb, len;
249
4.36k
  unsigned long tag;
250
251
4.36k
  if (asn1_get_tag_der (data, length, &cls, &cb, &tag) == ASN1_SUCCESS) {
252
4.17k
    counter += cb;
253
4.17k
    len = asn1_get_length_der (data + cb, length - cb, &cb);
254
4.17k
    counter += cb;
255
4.17k
    if (len >= 0) {
256
3.71k
      len += counter;
257
3.71k
      if (length >= len)
258
3.71k
        return len;
259
3.71k
    }
260
4.17k
  }
261
262
647
  return -1;
263
4.36k
}
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
7.34k
{
340
7.34k
  asn1_item *item;
341
342
7.34k
  if (cache == NULL) {
343
7.34k
    asn1_delete_structure (&node);
344
7.34k
    return;
345
7.34k
  }
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
3.35k
{
374
3.35k
  if (cache == NULL)
375
3.35k
    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
}