2 * Copyright (C)2008 Andreas Steffen
3 * Hochschule fuer Technik Rapperswil, Switzerland
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>.
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
20 #include <asn1/asn1.h>
21 #include <asn1/asn1_parser.h>
22 #include <utils/linked_list.h>
26 typedef struct private_pkcs9_t private_pkcs9_t
;
29 * Private data of a pkcs9_t attribute list.
31 struct private_pkcs9_t
{
38 * DER encoding of PKCS#9 attributes
43 * Linked list of PKCS#9 attributes
45 linked_list_t
*attributes
;
48 typedef struct attribute_t attribute_t
;
51 * Definition of an attribute_t object.
55 * Object Identifier (OID)
70 * Destroys the attribute.
72 * @param this attribute to destroy
74 void (*destroy
) (attribute_t
*this);
79 * PKCS#9 attribute type OIDs
81 static u_char ASN1_contentType_oid_str
[] = {
83 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
86 static u_char ASN1_messageDigest_oid_str
[] = {
88 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
91 static u_char ASN1_signingTime_oid_str
[] = {
93 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05
96 static char ASN1_messageType_oid_str
[] = {
98 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02
101 static char ASN1_senderNonce_oid_str
[] = {
103 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05
106 static char ASN1_transId_oid_str
[] = {
108 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07
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
);
125 * return the ASN.1 encoded OID of a PKCS#9 attribute
127 static chunk_t
asn1_attributeIdentifier(int oid
)
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
;;
149 * return the ASN.1 encoding of a PKCS#9 attribute
151 static asn1_t
asn1_attributeType(int oid
)
157 case OID_PKCS9_CONTENT_TYPE
:
160 case OID_PKCS9_SIGNING_TIME
:
163 case OID_PKCS9_MESSAGE_DIGEST
:
164 type
= ASN1_OCTET_STRING
;
166 case OID_PKI_MESSAGE_TYPE
:
167 type
= ASN1_PRINTABLESTRING
;
170 type
= ASN1_PRINTABLESTRING
;
172 case OID_PKI_FAIL_INFO
:
173 type
= ASN1_PRINTABLESTRING
;
175 case OID_PKI_SENDER_NONCE
:
176 type
= ASN1_OCTET_STRING
;
178 case OID_PKI_RECIPIENT_NONCE
:
179 type
= ASN1_OCTET_STRING
;
181 case OID_PKI_TRANS_ID
:
182 type
= ASN1_PRINTABLESTRING
;
191 * Destroy an attribute_t object.
193 static void attribute_destroy(attribute_t
*this)
195 free(this->value
.ptr
);
196 free(this->encoding
.ptr
);
201 * Create an attribute_t object.
203 static attribute_t
*attribute_create(int oid
, chunk_t value
)
205 attribute_t
*this = malloc_thing(attribute_t
);
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
;
217 * Implements pkcs9_t.build_encoding
219 static void build_encoding(private_pkcs9_t
*this)
221 iterator_t
*iterator
;
222 attribute_t
*attribute
;
223 u_int attributes_len
= 0;
225 if (this->encoding
.ptr
)
227 chunk_free(&this->encoding
);
229 if (this->attributes
->get_count(this->attributes
) == 0)
234 /* compute the total length of the encoded attributes */
235 iterator
= this->attributes
->create_iterator(this->attributes
, TRUE
);
237 while (iterator
->iterate(iterator
, (void**)&attribute
))
239 attributes_len
+= attribute
->encoding
.len
;
241 iterator
->destroy(iterator
);
243 /* allocate memory for the attributes and build the encoding */
245 u_char
*pos
= asn1_build_object(&this->encoding
, ASN1_SET
, attributes_len
);
247 iterator
= this->attributes
->create_iterator(this->attributes
, TRUE
);
249 while (iterator
->iterate(iterator
, (void**)&attribute
))
251 memcpy(pos
, attribute
->encoding
.ptr
, attribute
->encoding
.len
);
252 pos
+= attribute
->encoding
.len
;
254 iterator
->destroy(iterator
);
259 * Implements pkcs9_t.get_encoding
261 static chunk_t
get_encoding(private_pkcs9_t
*this)
263 if (this->encoding
.ptr
== NULL
)
265 build_encoding(this);
267 return this->encoding
;
271 * Implements pkcs9_t.get_attribute
273 static chunk_t
get_attribute(private_pkcs9_t
*this, int oid
)
275 iterator_t
*iterator
= this->attributes
->create_iterator(this->attributes
, TRUE
);
276 chunk_t value
= chunk_empty
;
277 attribute_t
*attribute
;
279 while (iterator
->iterate(iterator
, (void**)&attribute
))
281 if (attribute
->oid
== oid
)
283 value
= attribute
->value
;
287 iterator
->destroy(iterator
);
292 * Implements pkcs9_t.set_attribute
294 static void set_attribute(private_pkcs9_t
*this, int oid
, chunk_t value
)
296 attribute_t
*attribute
= attribute_create(oid
, value
);
298 this->attributes
->insert_last(this->attributes
, (void*)attribute
);
302 * Implements pkcs9_t.get_messageDigest
304 static chunk_t
get_messageDigest(private_pkcs9_t
*this)
306 const int oid
= OID_PKCS9_MESSAGE_DIGEST
;
307 chunk_t value
= get_attribute(this, oid
);
309 if (value
.ptr
== NULL
)
313 if (!asn1_parse_simple_object(&value
, asn1_attributeType(oid
), 0,
314 oid_names
[oid
].name
))
318 return chunk_clone(value
);
322 * Implements pkcs9_t.set_attribute
324 static void set_messageDigest(private_pkcs9_t
*this, chunk_t value
)
326 const int oid
= OID_PKCS9_MESSAGE_DIGEST
;
327 chunk_t messageDigest
= asn1_simple_object(asn1_attributeType(oid
), value
);
329 set_attribute(this, oid
, messageDigest
);
330 free(messageDigest
.ptr
);
334 * Implements pkcs9_t.destroy
336 static void destroy(private_pkcs9_t
*this)
338 this->attributes
->destroy_offset(this->attributes
, offsetof(attribute_t
, destroy
));
339 free(this->encoding
.ptr
);
344 * Generic private constructor
346 static private_pkcs9_t
*pkcs9_create_empty(void)
348 private_pkcs9_t
*this = malloc_thing(private_pkcs9_t
);
351 this->encoding
= chunk_empty
;
352 this->attributes
= linked_list_create();
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
;
367 * Described in header.
369 pkcs9_t
*pkcs9_create(void)
371 private_pkcs9_t
*this = pkcs9_create_empty();
373 return &this->public;
377 * ASN.1 definition of the X.501 atttribute type
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
}
389 #define ATTRIBUTE_OBJ_TYPE 2
390 #define ATTRIBUTE_OBJ_VALUE 4
393 * Parse a PKCS#9 attribute list
395 static bool parse_attributes(chunk_t chunk
, int level0
, private_pkcs9_t
* this)
397 asn1_parser_t
*parser
;
400 int oid
= OID_UNKNOWN
;
401 bool success
= FALSE
;
403 parser
= asn1_parser_create(attributesObjects
, chunk
);
404 parser
->set_top_level(parser
, level0
);
406 while (parser
->iterate(parser
, &objectID
, &object
))
410 case ATTRIBUTE_OBJ_TYPE
:
411 oid
= asn1_known_oid(object
);
413 case ATTRIBUTE_OBJ_VALUE
:
414 if (oid
== OID_UNKNOWN
)
418 /* add the attribute to a linked list */
420 attribute_t
*attribute
= attribute_create(oid
, object
);
422 this->attributes
->insert_last(this->attributes
,
425 /* parse known attributes */
427 asn1_t type
= asn1_attributeType(oid
);
429 if (type
!= ASN1_EOC
)
431 if (!asn1_parse_simple_object(&object
, type
,
432 parser
->get_level(parser
)+1,
433 oid_names
[oid
].name
))
441 success
= parser
->success(parser
);
444 parser
->destroy(parser
);
450 * Described in header.
452 pkcs9_t
*pkcs9_create_from_chunk(chunk_t chunk
, u_int level
)
454 private_pkcs9_t
*this = pkcs9_create_empty();
456 this->encoding
= chunk_clone(chunk
);
458 if (!parse_attributes(chunk
, level
, this))
463 return &this->public;