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