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