Removed len argument from proposal_get_token()
[strongswan.git] / src / libstrongswan / crypto / pkcs9.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 <debug.h>
19
20 #include <asn1/oid.h>
21 #include <asn1/asn1.h>
22 #include <asn1/asn1_parser.h>
23 #include <utils/linked_list.h>
24
25 #include "pkcs9.h"
26
27 typedef struct private_pkcs9_t private_pkcs9_t;
28
29 /**
30 * Private data of a pkcs9_t attribute list.
31 */
32 struct private_pkcs9_t {
33 /**
34 * Public interface
35 */
36 pkcs9_t public;
37
38 /**
39 * DER encoding of PKCS#9 attributes
40 */
41 chunk_t encoding;
42
43 /**
44 * Linked list of PKCS#9 attributes
45 */
46 linked_list_t *attributes;
47 };
48
49 typedef struct attribute_t attribute_t;
50
51 /**
52 * Definition of an attribute_t object.
53 */
54 struct attribute_t {
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 * Destroys the attribute.
72 */
73 void (*destroy) (attribute_t *this);
74
75 };
76
77 /**
78 * return the ASN.1 encoding of a PKCS#9 attribute
79 */
80 static asn1_t asn1_attributeType(int oid)
81 {
82 asn1_t type;
83
84 switch (oid)
85 {
86 case OID_PKCS9_CONTENT_TYPE:
87 type = ASN1_OID;
88 break;
89 case OID_PKCS9_SIGNING_TIME:
90 type = ASN1_UTCTIME;
91 break;
92 case OID_PKCS9_MESSAGE_DIGEST:
93 type = ASN1_OCTET_STRING;
94 break;
95 case OID_PKI_MESSAGE_TYPE:
96 type = ASN1_PRINTABLESTRING;
97 break;
98 case OID_PKI_STATUS:
99 type = ASN1_PRINTABLESTRING;
100 break;
101 case OID_PKI_FAIL_INFO:
102 type = ASN1_PRINTABLESTRING;
103 break;
104 case OID_PKI_SENDER_NONCE:
105 type = ASN1_OCTET_STRING;
106 break;
107 case OID_PKI_RECIPIENT_NONCE:
108 type = ASN1_OCTET_STRING;
109 break;
110 case OID_PKI_TRANS_ID:
111 type = ASN1_PRINTABLESTRING;
112 break;
113 default:
114 type = ASN1_EOC;
115 }
116 return type;
117 }
118
119 /**
120 * Destroy an attribute_t object.
121 */
122 static void attribute_destroy(attribute_t *this)
123 {
124 free(this->value.ptr);
125 free(this->encoding.ptr);
126 free(this);
127 }
128
129 /**
130 * Create an attribute_t object.
131 */
132 static attribute_t *attribute_create(int oid, chunk_t value)
133 {
134 attribute_t *this;
135
136 INIT(this,
137 .destroy = attribute_destroy,
138 .oid = oid,
139 .value = chunk_clone(value),
140 .encoding = asn1_wrap(ASN1_SEQUENCE, "mm",
141 asn1_build_known_oid(oid),
142 asn1_simple_object(ASN1_SET, value)),
143 );
144
145 return this;
146 }
147
148 METHOD(pkcs9_t, build_encoding, void,
149 private_pkcs9_t *this)
150 {
151 enumerator_t *enumerator;
152 attribute_t *attribute;
153 u_int attributes_len = 0;
154
155 if (this->encoding.ptr)
156 {
157 chunk_free(&this->encoding);
158 }
159 if (this->attributes->get_count(this->attributes) == 0)
160 {
161 return;
162 }
163
164 /* compute the total length of the encoded attributes */
165 enumerator = this->attributes->create_enumerator(this->attributes);
166
167 while (enumerator->enumerate(enumerator, (void**)&attribute))
168 {
169 attributes_len += attribute->encoding.len;
170 }
171 enumerator->destroy(enumerator);
172
173 /* allocate memory for the attributes and build the encoding */
174 {
175 u_char *pos = asn1_build_object(&this->encoding, ASN1_SET, attributes_len);
176
177 enumerator = this->attributes->create_enumerator(this->attributes);
178
179 while (enumerator->enumerate(enumerator, (void**)&attribute))
180 {
181 memcpy(pos, attribute->encoding.ptr, attribute->encoding.len);
182 pos += attribute->encoding.len;
183 }
184 enumerator->destroy(enumerator);
185 }
186 }
187
188 METHOD(pkcs9_t, get_encoding, chunk_t,
189 private_pkcs9_t *this)
190 {
191 if (this->encoding.ptr == NULL)
192 {
193 build_encoding(this);
194 }
195 return this->encoding;
196 }
197
198 METHOD(pkcs9_t, get_attribute, chunk_t,
199 private_pkcs9_t *this, int oid)
200 {
201 enumerator_t *enumerator;
202 chunk_t value = chunk_empty;
203 attribute_t *attribute;
204
205 enumerator = this->attributes->create_enumerator(this->attributes);
206 while (enumerator->enumerate(enumerator, (void**)&attribute))
207 {
208 if (attribute->oid == oid)
209 {
210 value = attribute->value;
211 break;
212 }
213 }
214 enumerator->destroy(enumerator);
215 if (value.ptr &&
216 !asn1_parse_simple_object(&value, asn1_attributeType(oid), 0,
217 oid_names[oid].name))
218 {
219 return chunk_empty;
220 }
221 return value;
222 }
223
224 METHOD(pkcs9_t, set_attribute_raw, void,
225 private_pkcs9_t *this, int oid, chunk_t value)
226 {
227 attribute_t *attribute = attribute_create(oid, value);
228
229 this->attributes->insert_last(this->attributes, attribute);
230 chunk_free(&value);
231 }
232
233 METHOD(pkcs9_t, set_attribute, void,
234 private_pkcs9_t *this, int oid, chunk_t value)
235 {
236 chunk_t attr = asn1_simple_object(asn1_attributeType(oid), value);
237
238 set_attribute_raw(this, oid, attr);
239 }
240
241 METHOD(pkcs9_t, destroy, void,
242 private_pkcs9_t *this)
243 {
244 this->attributes->destroy_offset(this->attributes, offsetof(attribute_t, destroy));
245 free(this->encoding.ptr);
246 free(this);
247 }
248
249 /**
250 * Generic private constructor
251 */
252 static private_pkcs9_t *pkcs9_create_empty(void)
253 {
254 private_pkcs9_t *this;
255
256 INIT(this,
257 .public = {
258 .build_encoding = _build_encoding,
259 .get_encoding = _get_encoding,
260 .get_attribute = _get_attribute,
261 .set_attribute = _set_attribute,
262 .set_attribute_raw = _set_attribute_raw,
263 .destroy = _destroy,
264 },
265 .attributes = linked_list_create(),
266 );
267
268 return this;
269 }
270
271 /*
272 * Described in header.
273 */
274 pkcs9_t *pkcs9_create(void)
275 {
276 private_pkcs9_t *this = pkcs9_create_empty();
277
278 return &this->public;
279 }
280
281 /**
282 * ASN.1 definition of the X.501 atttribute type
283 */
284 static const asn1Object_t attributesObjects[] = {
285 { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
286 { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
287 { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
288 { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
289 { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
290 { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
291 { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
292 { 0, "exit", ASN1_EOC, ASN1_EXIT }
293 };
294 #define ATTRIBUTE_OBJ_TYPE 2
295 #define ATTRIBUTE_OBJ_VALUE 4
296
297 /**
298 * Parse a PKCS#9 attribute list
299 */
300 static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this)
301 {
302 asn1_parser_t *parser;
303 chunk_t object;
304 int objectID;
305 int oid = OID_UNKNOWN;
306 bool success = FALSE;
307
308 parser = asn1_parser_create(attributesObjects, chunk);
309 parser->set_top_level(parser, level0);
310
311 while (parser->iterate(parser, &objectID, &object))
312 {
313 switch (objectID)
314 {
315 case ATTRIBUTE_OBJ_TYPE:
316 oid = asn1_known_oid(object);
317 break;
318 case ATTRIBUTE_OBJ_VALUE:
319 if (oid == OID_UNKNOWN)
320 {
321 break;
322 }
323 /* add the attribute to a linked list */
324 {
325 attribute_t *attribute = attribute_create(oid, object);
326
327 this->attributes->insert_last(this->attributes,
328 (void*)attribute);
329 }
330 /* parse known attributes */
331 {
332 asn1_t type = asn1_attributeType(oid);
333
334 if (type != ASN1_EOC)
335 {
336 if (!asn1_parse_simple_object(&object, type,
337 parser->get_level(parser)+1,
338 oid_names[oid].name))
339 {
340 goto end;
341 }
342 }
343 }
344 }
345 }
346 success = parser->success(parser);
347
348 end:
349 parser->destroy(parser);
350 return success;
351 }
352
353
354 /*
355 * Described in header.
356 */
357 pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level)
358 {
359 private_pkcs9_t *this = pkcs9_create_empty();
360
361 this->encoding = chunk_clone(chunk);
362
363 if (!parse_attributes(chunk, level, this))
364 {
365 destroy(this);
366 return NULL;
367 }
368 return &this->public;
369 }