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