optimized parser->success()
[strongswan.git] / src / libstrongswan / crypto / pkcs9.c
1 /*
2 * Copyright (C)2008 Andreas Steffen
3 * Hochschule fuer Technik Rapperswil, Switzerland
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #include <library.h>
19 #include <debug.h>
20
21 #include <asn1/oid.h>
22 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
24 #include <utils/linked_list.h>
25
26 #include "pkcs9.h"
27
28 typedef struct private_pkcs9_t private_pkcs9_t;
29
30 /**
31 * Private data of a pkcs9_t attribute list.
32 */
33 struct private_pkcs9_t {
34 /**
35 * Public interface
36 */
37 pkcs9_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 typedef struct attribute_t attribute_t;
51
52 /**
53 * Definition of an attribute_t object.
54 */
55 struct attribute_t {
56 /**
57 * Object Identifier (OID)
58 */
59 int oid;
60
61 /**
62 * Attribute value
63 */
64 chunk_t value;
65
66 /**
67 * ASN.1 encoding
68 */
69 chunk_t encoding;
70
71 /**
72 * Destroys the attribute.
73 *
74 * @param this attribute to destroy
75 */
76 void (*destroy) (attribute_t *this);
77
78 };
79
80 /* ASN.1 definition of the X.501 atttribute type */
81
82 static const asn1Object_t attributesObjects[] = {
83 { 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
84 { 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
85 { 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
86 { 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
87 { 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
88 { 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
89 { 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
90 };
91 #define ATTRIBUTE_OBJ_TYPE 2
92 #define ATTRIBUTE_OBJ_VALUE 4
93 #define ATTRIBUTE_OBJ_ROOF 7
94
95 /**
96 * PKCS#9 attribute type OIDs
97 */
98 static u_char ASN1_contentType_oid_str[] = {
99 0x06, 0x09,
100 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
101 };
102
103 static u_char ASN1_messageDigest_oid_str[] = {
104 0x06, 0x09,
105 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
106 };
107
108 static u_char ASN1_signingTime_oid_str[] = {
109 0x06, 0x09,
110 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05
111 };
112
113 static char ASN1_messageType_oid_str[] = {
114 0x06, 0x0A,
115 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
116 };
117
118 static char ASN1_senderNonce_oid_str[] = {
119 0x06, 0x0A,
120 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
121 };
122
123 static char ASN1_transId_oid_str[] = {
124 0x06, 0x0A,
125 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
126 };
127
128 static const chunk_t ASN1_contentType_oid =
129 chunk_from_buf(ASN1_contentType_oid_str);
130 static const chunk_t ASN1_messageDigest_oid =
131 chunk_from_buf(ASN1_messageDigest_oid_str);
132 static const chunk_t ASN1_signingTime_oid =
133 chunk_from_buf(ASN1_signingTime_oid_str);
134 static const chunk_t ASN1_messageType_oid =
135 chunk_from_buf(ASN1_messageType_oid_str);
136 static const chunk_t ASN1_senderNonce_oid =
137 chunk_from_buf(ASN1_senderNonce_oid_str);
138 static const chunk_t ASN1_transId_oid =
139 chunk_from_buf(ASN1_transId_oid_str);
140
141 /**
142 * return the ASN.1 encoded OID of a PKCS#9 attribute
143 */
144 static chunk_t asn1_attributeIdentifier(int oid)
145 {
146 switch (oid)
147 {
148 case OID_PKCS9_CONTENT_TYPE:
149 return ASN1_contentType_oid;
150 case OID_PKCS9_MESSAGE_DIGEST:
151 return ASN1_messageDigest_oid;
152 case OID_PKCS9_SIGNING_TIME:
153 return ASN1_signingTime_oid;
154 case OID_PKI_MESSAGE_TYPE:
155 return ASN1_messageType_oid;
156 case OID_PKI_SENDER_NONCE:
157 return ASN1_senderNonce_oid;
158 case OID_PKI_TRANS_ID:
159 return ASN1_transId_oid;;
160 default:
161 return chunk_empty;
162 }
163 }
164
165 /**
166 * return the ASN.1 encoding of a PKCS#9 attribute
167 */
168 static asn1_t asn1_attributeType(int oid)
169 {
170 asn1_t type;
171
172 switch (oid)
173 {
174 case OID_PKCS9_CONTENT_TYPE:
175 type = ASN1_OID;
176 break;
177 case OID_PKCS9_SIGNING_TIME:
178 type = ASN1_UTCTIME;
179 break;
180 case OID_PKCS9_MESSAGE_DIGEST:
181 type = ASN1_OCTET_STRING;
182 break;
183 case OID_PKI_MESSAGE_TYPE:
184 type = ASN1_PRINTABLESTRING;
185 break;
186 case OID_PKI_STATUS:
187 type = ASN1_PRINTABLESTRING;
188 break;
189 case OID_PKI_FAIL_INFO:
190 type = ASN1_PRINTABLESTRING;
191 break;
192 case OID_PKI_SENDER_NONCE:
193 type = ASN1_OCTET_STRING;
194 break;
195 case OID_PKI_RECIPIENT_NONCE:
196 type = ASN1_OCTET_STRING;
197 break;
198 case OID_PKI_TRANS_ID:
199 type = ASN1_PRINTABLESTRING;
200 break;
201 default:
202 type = ASN1_EOC;
203 }
204 return type;
205 }
206
207 /**
208 * Destroy an attribute_t object.
209 */
210 static void attribute_destroy(attribute_t *this)
211 {
212 free(this->value.ptr);
213 free(this->encoding.ptr);
214 free(this);
215 }
216
217 /**
218 * Create an attribute_t object.
219 */
220 static attribute_t *attribute_create(int oid, chunk_t value)
221 {
222 attribute_t *this = malloc_thing(attribute_t);
223
224 this->oid = oid;
225 this->value = chunk_clone(value);
226 this->encoding = asn1_wrap(ASN1_SEQUENCE, "cm",
227 asn1_attributeIdentifier(oid),
228 asn1_simple_object(ASN1_SET, value));
229 this->destroy = (void (*) (attribute_t*))attribute_destroy;
230 return this;
231 }
232
233 /**
234 * Implements pkcs9_t.build_encoding
235 */
236 static void build_encoding(private_pkcs9_t *this)
237 {
238 iterator_t *iterator;
239 attribute_t *attribute;
240 u_int attributes_len = 0;
241
242 if (this->encoding.ptr)
243 {
244 chunk_free(&this->encoding);
245 }
246 if (this->attributes->get_count(this->attributes) == 0)
247 {
248 return;
249 }
250
251 /* compute the total length of the encoded attributes */
252 iterator = this->attributes->create_iterator(this->attributes, TRUE);
253
254 while (iterator->iterate(iterator, (void**)&attribute))
255 {
256 attributes_len += attribute->encoding.len;
257 }
258 iterator->destroy(iterator);
259
260 /* allocate memory for the attributes and build the encoding */
261 {
262 u_char *pos = asn1_build_object(&this->encoding, ASN1_SET, attributes_len);
263
264 iterator = this->attributes->create_iterator(this->attributes, TRUE);
265
266 while (iterator->iterate(iterator, (void**)&attribute))
267 {
268 memcpy(pos, attribute->encoding.ptr, attribute->encoding.len);
269 pos += attribute->encoding.len;
270 }
271 iterator->destroy(iterator);
272 }
273 }
274
275 /**
276 * Implements pkcs9_t.get_encoding
277 */
278 static chunk_t get_encoding(private_pkcs9_t *this)
279 {
280 if (this->encoding.ptr == NULL)
281 {
282 build_encoding(this);
283 }
284 return this->encoding;
285 }
286
287 /**
288 * Implements pkcs9_t.get_attribute
289 */
290 static chunk_t get_attribute(private_pkcs9_t *this, int oid)
291 {
292 iterator_t *iterator = this->attributes->create_iterator(this->attributes, TRUE);
293 chunk_t value = chunk_empty;
294 attribute_t *attribute;
295
296 while (iterator->iterate(iterator, (void**)&attribute))
297 {
298 if (attribute->oid == oid)
299 {
300 value = attribute->value;
301 break;
302 }
303 }
304 iterator->destroy(iterator);
305 return value;
306 }
307
308 /**
309 * Implements pkcs9_t.set_attribute
310 */
311 static void set_attribute(private_pkcs9_t *this, int oid, chunk_t value)
312 {
313 attribute_t *attribute = attribute_create(oid, value);
314
315 this->attributes->insert_last(this->attributes, (void*)attribute);
316 }
317
318 /**
319 * Implements pkcs9_t.get_messageDigest
320 */
321 static chunk_t get_messageDigest(private_pkcs9_t *this)
322 {
323 const int oid = OID_PKCS9_MESSAGE_DIGEST;
324 chunk_t value = get_attribute(this, oid);
325
326 if (value.ptr == NULL)
327 {
328 return chunk_empty;
329 }
330 if (!asn1_parse_simple_object(&value, asn1_attributeType(oid), 0,
331 oid_names[oid].name))
332 {
333 return chunk_empty;
334 }
335 return chunk_clone(value);
336 }
337
338 /**
339 * Implements pkcs9_t.set_attribute
340 */
341 static void set_messageDigest(private_pkcs9_t *this, chunk_t value)
342 {
343 const int oid = OID_PKCS9_MESSAGE_DIGEST;
344 chunk_t messageDigest = asn1_simple_object(asn1_attributeType(oid), value);
345
346 set_attribute(this, oid, messageDigest);
347 free(messageDigest.ptr);
348 }
349
350 /**
351 * Implements pkcs9_t.destroy
352 */
353 static void destroy(private_pkcs9_t *this)
354 {
355 this->attributes->destroy_offset(this->attributes, offsetof(attribute_t, destroy));
356 free(this->encoding.ptr);
357 free(this);
358 }
359
360 /**
361 * Generic private constructor
362 */
363 static private_pkcs9_t *pkcs9_create_empty(void)
364 {
365 private_pkcs9_t *this = malloc_thing(private_pkcs9_t);
366
367 /* initialize */
368 this->encoding = chunk_empty;
369 this->attributes = linked_list_create();
370
371 /*public functions */
372 this->public.build_encoding = (void (*) (pkcs9_t*))build_encoding;
373 this->public.get_encoding = (chunk_t (*) (pkcs9_t*))get_encoding;
374 this->public.get_attribute = (chunk_t (*) (pkcs9_t*,int))get_attribute;
375 this->public.set_attribute = (void (*) (pkcs9_t*,int,chunk_t))set_attribute;
376 this->public.get_messageDigest = (chunk_t (*) (pkcs9_t*))get_messageDigest;
377 this->public.set_messageDigest = (void (*) (pkcs9_t*,chunk_t))set_messageDigest;
378 this->public.destroy = (void (*) (pkcs9_t*))destroy;
379
380 return this;
381 }
382
383 /*
384 * Described in header.
385 */
386 pkcs9_t *pkcs9_create(void)
387 {
388 private_pkcs9_t *this = pkcs9_create_empty();
389
390 return &this->public;
391 }
392
393 /**
394 * Parse a PKCS#9 attribute list
395 */
396 static bool parse_attributes(chunk_t chunk, int level0, private_pkcs9_t* this)
397 {
398 asn1_parser_t *parser;
399 chunk_t object;
400 int objectID;
401 int oid = OID_UNKNOWN;
402 bool success = FALSE;
403
404 parser = asn1_parser_create(attributesObjects, ATTRIBUTE_OBJ_ROOF, chunk);
405 parser->set_top_level(parser, level0);
406
407 while (parser->iterate(parser, &objectID, &object))
408 {
409 switch (objectID)
410 {
411 case ATTRIBUTE_OBJ_TYPE:
412 oid = asn1_known_oid(object);
413 break;
414 case ATTRIBUTE_OBJ_VALUE:
415 if (oid == OID_UNKNOWN)
416 {
417 break;
418 }
419 /* add the attribute to a linked list */
420 {
421 attribute_t *attribute = attribute_create(oid, object);
422
423 this->attributes->insert_last(this->attributes,
424 (void*)attribute);
425 }
426 /* parse known attributes */
427 {
428 asn1_t type = asn1_attributeType(oid);
429
430 if (type != ASN1_EOC)
431 {
432 if (!asn1_parse_simple_object(&object, type,
433 parser->get_level(parser)+1,
434 oid_names[oid].name))
435 {
436 goto end;
437 }
438 }
439 }
440 }
441 }
442 success = parser->success(parser);
443
444 end:
445 parser->destroy(parser);
446 return success;
447 }
448
449
450 /*
451 * Described in header.
452 */
453 pkcs9_t *pkcs9_create_from_chunk(chunk_t chunk, u_int level)
454 {
455 private_pkcs9_t *this = pkcs9_create_empty();
456
457 this->encoding = chunk_clone(chunk);
458
459 if (!parse_attributes(chunk, level, this))
460 {
461 destroy(this);
462 return NULL;
463 }
464 return &this->public;
465 }