Coverage Report

Created: 2025-11-09 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/plugins/pkcs7/pkcs7_attributes.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012 Tobias Brunner
3
 * Copyright (C) 2008 Andreas Steffen
4
 *
5
 * Copyright (C) secunet Security Networks AG
6
 *
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License as published by the
9
 * Free Software Foundation; either version 2 of the License, or (at your
10
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
11
 *
12
 * This program is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
 * for more details.
16
 */
17
18
#include <library.h>
19
#include <utils/debug.h>
20
21
#include <asn1/oid.h>
22
#include <asn1/asn1.h>
23
#include <asn1/asn1_parser.h>
24
#include <collections/array.h>
25
#include <collections/linked_list.h>
26
27
#include "pkcs7_attributes.h"
28
29
typedef struct private_pkcs7_attributes_t private_pkcs7_attributes_t;
30
typedef struct attribute_t attribute_t;
31
32
/**
33
 * Private data of a pkcs7_attributes_t attribute list.
34
 */
35
struct private_pkcs7_attributes_t {
36
  /**
37
   * Public interface
38
   */
39
  pkcs7_attributes_t public;
40
41
  /**
42
   * DER encoding of PKCS#9 attributes
43
   */
44
  chunk_t encoding;
45
46
  /**
47
   * Linked list of PKCS#9 attributes
48
   */
49
  linked_list_t *attributes;
50
};
51
52
/**
53
 * Definition of an attribute_t object.
54
 */
55
struct attribute_t {
56
57
  /**
58
   * Object Identifier (OID)
59
   */
60
  int oid;
61
62
  /**
63
   * Attribute value
64
   */
65
  chunk_t value;
66
67
  /**
68
   * ASN.1 encoding
69
   */
70
  chunk_t encoding;
71
};
72
73
/**
74
 * Destroy an attribute_t object.
75
 */
76
static void attribute_destroy(attribute_t *this)
77
0
{
78
0
  free(this->value.ptr);
79
0
  free(this);
80
0
}
81
82
/**
83
 * Create an attribute_t object.
84
 */
85
static attribute_t *attribute_create(int oid, chunk_t value)
86
0
{
87
0
  attribute_t *this;
88
89
0
  INIT(this,
90
0
    .oid = oid,
91
0
    .value = chunk_clone(value),
92
0
  );
93
94
0
  return this;
95
0
}
96
97
/**
98
 * Compare two encoded attributes
99
 */
100
static int cmp_attributes(const chunk_t *a, const chunk_t *b, void *unused)
101
0
{
102
0
  return chunk_compare(*a, *b);
103
0
}
104
105
/**
106
 * Build encoding of the attribute list
107
 */
108
static void build_encoding(private_pkcs7_attributes_t *this)
109
0
{
110
0
  enumerator_t *enumerator;
111
0
  attribute_t *attribute;
112
0
  u_int len = 0, count, i = 0;
113
0
  array_t *chunks;
114
0
  chunk_t chunk;
115
0
  u_char *pos;
116
117
0
  count = this->attributes->get_count(this->attributes);
118
0
  chunks = array_create(sizeof(chunk_t), count);
119
120
0
  enumerator = this->attributes->create_enumerator(this->attributes);
121
0
  while (enumerator->enumerate(enumerator, &attribute))
122
0
  {
123
0
    chunk = asn1_wrap(ASN1_SEQUENCE, "mm",
124
0
              asn1_build_known_oid(attribute->oid),
125
0
              asn1_wrap(ASN1_SET, "c", attribute->value));
126
0
    array_insert(chunks, ARRAY_TAIL, &chunk);
127
0
    len += chunk.len;
128
0
  }
129
0
  enumerator->destroy(enumerator);
130
131
0
  array_sort(chunks, (void*)cmp_attributes, NULL);
132
133
0
  pos = asn1_build_object(&this->encoding, ASN1_SET, len);
134
0
  for (i = 0; i < count; i++)
135
0
  {
136
0
    array_get(chunks, i, &chunk);
137
0
    memcpy(pos, chunk.ptr, chunk.len);
138
0
    pos += chunk.len;
139
0
    free(chunk.ptr);
140
0
  }
141
0
  array_destroy(chunks);
142
0
}
143
144
METHOD(pkcs7_attributes_t, get_encoding, chunk_t,
145
  private_pkcs7_attributes_t *this)
146
0
{
147
0
  if (!this->encoding.len)
148
0
  {
149
0
    build_encoding(this);
150
0
  }
151
0
  return this->encoding;
152
0
}
153
154
METHOD(pkcs7_attributes_t, get_attribute, chunk_t,
155
  private_pkcs7_attributes_t *this, int oid)
156
0
{
157
0
  enumerator_t *enumerator;
158
0
  chunk_t value = chunk_empty;
159
0
  attribute_t *attribute;
160
161
0
  enumerator = this->attributes->create_enumerator(this->attributes);
162
0
  while (enumerator->enumerate(enumerator, &attribute))
163
0
  {
164
0
    if (attribute->oid == oid)
165
0
    {
166
0
      value = attribute->value;
167
0
      break;
168
0
    }
169
0
  }
170
0
  enumerator->destroy(enumerator);
171
0
  if (value.len && asn1_unwrap(&value, &value) != ASN1_INVALID)
172
0
  {
173
0
    return value;
174
0
  }
175
0
  return chunk_empty;
176
0
}
177
178
METHOD(pkcs7_attributes_t, add_attribute, void,
179
  private_pkcs7_attributes_t *this, int oid, chunk_t value)
180
0
{
181
0
  this->attributes->insert_last(this->attributes,
182
0
                  attribute_create(oid, value));
183
0
  chunk_free(&value);
184
185
  /* rebuild encoding when adding attributes */
186
0
  chunk_free(&this->encoding);
187
0
}
188
189
METHOD(pkcs7_attributes_t, destroy, void,
190
  private_pkcs7_attributes_t *this)
191
0
{
192
0
  this->attributes->destroy_function(this->attributes,
193
0
                     (void*)attribute_destroy);
194
0
  free(this->encoding.ptr);
195
0
  free(this);
196
0
}
197
198
/*
199
 * Described in header.
200
 */
201
pkcs7_attributes_t *pkcs7_attributes_create(void)
202
0
{
203
0
  private_pkcs7_attributes_t *this;
204
205
0
  INIT(this,
206
0
    .public = {
207
0
      .get_encoding = _get_encoding,
208
0
      .get_attribute = _get_attribute,
209
0
      .add_attribute = _add_attribute,
210
0
      .destroy = _destroy,
211
0
    },
212
0
    .attributes = linked_list_create(),
213
0
  );
214
215
0
  return &this->public;
216
0
}
217
218
/**
219
 * ASN.1 definition of the X.501 attribute type
220
 */
221
static const asn1Object_t attributesObjects[] = {
222
  { 0, "attributes",    ASN1_SET,   ASN1_LOOP }, /* 0 */
223
  { 1,   "attribute",   ASN1_SEQUENCE,  ASN1_NONE }, /* 1 */
224
  { 2,     "type",    ASN1_OID,   ASN1_BODY }, /* 2 */
225
  { 2,     "values",    ASN1_SET,   ASN1_LOOP }, /* 3 */
226
  { 3,       "value",   ASN1_EOC,   ASN1_RAW  }, /* 4 */
227
  { 2,     "end loop",  ASN1_EOC,   ASN1_END  }, /* 5 */
228
  { 0, "end loop",    ASN1_EOC,   ASN1_END  }, /* 6 */
229
  { 0, "exit",      ASN1_EOC,   ASN1_EXIT }
230
};
231
0
#define ATTRIBUTE_OBJ_TYPE  2
232
0
#define ATTRIBUTE_OBJ_VALUE 4
233
234
/**
235
 * Parse a PKCS#9 attribute list
236
 */
237
static bool parse_attributes(chunk_t chunk, int level0,
238
               private_pkcs7_attributes_t* this)
239
0
{
240
0
  asn1_parser_t *parser;
241
0
  chunk_t object;
242
0
  int objectID;
243
0
  int oid = OID_UNKNOWN;
244
0
  bool success = FALSE;
245
246
0
  parser = asn1_parser_create(attributesObjects, chunk);
247
0
  parser->set_top_level(parser, level0);
248
249
0
  while (parser->iterate(parser, &objectID, &object))
250
0
  {
251
0
    switch (objectID)
252
0
    {
253
0
      case ATTRIBUTE_OBJ_TYPE:
254
0
        oid = asn1_known_oid(object);
255
0
        break;
256
0
      case ATTRIBUTE_OBJ_VALUE:
257
0
        if (oid != OID_UNKNOWN)
258
0
        {
259
0
          this->attributes->insert_last(this->attributes,
260
0
                          attribute_create(oid, object));
261
0
        }
262
0
        break;
263
0
    }
264
0
  }
265
0
  success = parser->success(parser);
266
267
0
  parser->destroy(parser);
268
0
  return success;
269
0
}
270
271
 /*
272
 * Described in header.
273
 */
274
pkcs7_attributes_t *pkcs7_attributes_create_from_chunk(chunk_t chunk,
275
                             u_int level)
276
0
{
277
0
  private_pkcs7_attributes_t *this;
278
279
0
  this = (private_pkcs7_attributes_t*)pkcs7_attributes_create();
280
0
  this->encoding = chunk_clone(chunk);
281
0
  if (!parse_attributes(chunk, level, this))
282
0
  {
283
0
    destroy(this);
284
0
    return NULL;
285
0
  }
286
0
  return &this->public;
287
0
}