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