2 * Copyright (C) 2006 Martin Will
3 * Copyright (C) 2000-2008 Andreas Steffen
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * $Id: asn1.c 3589 2008-03-13 14:14:44Z martin $
28 #include "asn1_parser.h"
30 #define ASN1_MAX_LEVEL 10
32 typedef struct private_asn1_parser_t private_asn1_parser_t
;
35 * Private data of an asn1_cxt_t object.
37 struct private_asn1_parser_t
{
44 * Syntax definition of ASN.1 object
46 asn1Object_t
const *objects
;
49 * Current syntax definition line
54 * Current stat of the parsing operation
59 * Declare object data as private - use debug level 4 to log it
64 * Top-most type is implicit - ignore it
69 * Top-most parsing level - defaults to 0
74 * Jump back address for loops for each level
76 int loopAddr
[ASN1_MAX_LEVEL
+ 1];
79 * Current parsing pointer for each level
81 chunk_t blobs
[ASN1_MAX_LEVEL
+ 2];
85 * Implementation of asn1_parser_t.iterate
87 static bool iterate(private_asn1_parser_t
*this, int *objectID
, chunk_t
*object
)
89 chunk_t
*blob
, *blob1
;
94 *object
= chunk_empty
;
96 /* Advance to the next object syntax definition line */
97 obj
= this->objects
[++(this->line
)];
99 /* Terminate if the end of the object syntax definition has been reached */
100 if (obj
.flags
& ASN1_EXIT
)
105 if (obj
.flags
& ASN1_END
) /* end of loop or option found */
107 if (this->loopAddr
[obj
.level
] && this->blobs
[obj
.level
+1].len
> 0)
109 this->line
= this->loopAddr
[obj
.level
]; /* another iteration */
110 obj
= this->objects
[this->line
];
114 this->loopAddr
[obj
.level
] = 0; /* exit loop or option*/
119 level
= this->level0
+ obj
.level
;
120 blob
= this->blobs
+ obj
.level
;
122 start_ptr
= blob
->ptr
;
124 /* handle ASN.1 defaults values */
125 if ((obj
.flags
& ASN1_DEF
) && (blob
->len
== 0 || *start_ptr
!= obj
.type
) )
127 /* field is missing */
128 DBG2("L%d - %s:", level
, obj
.name
);
129 if (obj
.type
& ASN1_CONSTRUCTED
)
131 this->line
++ ; /* skip context-specific tag */
136 /* handle ASN.1 options */
138 if ((obj
.flags
& ASN1_OPT
)
139 && (blob
->len
== 0 || *start_ptr
!= obj
.type
))
141 /* advance to end of missing option field */
146 while (!((this->objects
[this->line
].flags
& ASN1_END
) &&
147 (this->objects
[this->line
].level
== obj
.level
)));
151 /* an ASN.1 object must possess at least a tag and length field */
155 DBG1("L%d - %s: ASN.1 object smaller than 2 octets",
157 this->success
= FALSE
;
161 blob1
->len
= asn1_length(blob
);
163 if (blob1
->len
== ASN1_INVALID_LENGTH
|| blob
->len
< blob1
->len
)
165 DBG1("L%d - %s: length of ASN.1 object invalid or too large",
167 this->success
= FALSE
;
170 blob1
->ptr
= blob
->ptr
;
171 blob
->ptr
+= blob1
->len
;
172 blob
->len
-= blob1
->len
;
174 /* return raw ASN.1 object without prior type checking */
176 if (obj
.flags
& ASN1_RAW
)
178 DBG2("L%d - %s:", level
, obj
.name
);
179 object
->ptr
= start_ptr
;
180 object
->len
= (size_t)(blob
->ptr
- start_ptr
);
184 if (*start_ptr
!= obj
.type
&& !(this->implicit
&& this->line
== 0))
186 DBG1("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
187 level
, obj
.name
, obj
.type
, *start_ptr
);
188 DBG3("%b", start_ptr
, (u_int
)(blob
->ptr
- start_ptr
));
189 this->success
= FALSE
;
193 DBG2("L%d - %s:", level
, obj
.name
);
195 /* In case of "SEQUENCE OF" or "SET OF" start a loop */
196 if (obj
.flags
& ASN1_LOOP
)
200 /* at least one item, start the loop */
201 this->loopAddr
[obj
.level
] = this->line
+ 1;
205 /* no items, advance directly to end of loop */
210 while (!((this->objects
[this->line
].flags
& ASN1_END
) &&
211 (this->objects
[this->line
].level
== obj
.level
)));
216 if (obj
.flags
& ASN1_OBJ
)
218 object
->ptr
= start_ptr
;
219 object
->len
= (size_t)(blob
->ptr
- start_ptr
);
229 else if (obj
.flags
& ASN1_BODY
)
232 asn1_debug_simple_object(*object
, obj
.type
, this->private);
236 *objectID
= this->line
;
237 return this->success
;
241 * Implementation of asn1_parser_t.get_level
243 static u_int
get_level(private_asn1_parser_t
*this)
245 return this->level0
+ this->objects
[this->line
].level
;
249 * Implementation of asn1_parser_t.set_top_level
251 static void set_top_level(private_asn1_parser_t
*this, u_int level0
)
253 this->level0
= level0
;
257 * Implementation of asn1_parser_t.set_flags
259 static void set_flags(private_asn1_parser_t
*this, bool implicit
, bool private)
261 this->implicit
= implicit
;
262 this->private = private;
266 * Implementation of asn1_parser_t.success
268 static bool success(private_asn1_parser_t
*this)
270 return this->success
;
274 * Implementation of asn1_parser_t.destroy
276 static void destroy(private_asn1_parser_t
*this)
284 asn1_parser_t
* asn1_parser_create(asn1Object_t
const *objects
, chunk_t blob
)
286 private_asn1_parser_t
*this = malloc_thing(private_asn1_parser_t
);
288 memset(this, '\0', sizeof(private_asn1_parser_t
));
289 this->objects
= objects
;
290 this->blobs
[0] = blob
;
292 this->success
= TRUE
;
294 this->public.iterate
= (bool (*)(asn1_parser_t
*, int*, chunk_t
*))iterate
;
295 this->public.get_level
= (u_int (*)(asn1_parser_t
*))get_level
;
296 this->public.set_top_level
= (void (*)(asn1_parser_t
*, u_int
))set_top_level
;
297 this->public.set_flags
= (void (*)(asn1_parser_t
*, bool, bool))set_flags
;
298 this->public.success
= (bool (*)(asn1_parser_t
*))success
;
299 this->public.destroy
= (void (*)(asn1_parser_t
*))destroy
;
301 return &this->public;