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