2 * Copyright (c) 2005-2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * DER_Decode.c - DER decoding routines
28 #include <libDER/DER_Decode.h>
29 #include <libDER/asn1Types.h>
31 #include <libDER/libDER_config.h>
33 #ifndef DER_DECODE_ENABLE
34 #error Please define DER_DECODE_ENABLE.
39 #define DER_DECODE_DEBUG 0
42 #define derDecDbg(a) printf(a)
43 #define derDecDbg1(a, b) printf(a, b)
44 #define derDecDbg2(a, b, c) printf(a, b, c)
45 #define derDecDbg3(a, b, c, d) printf(a, b, c, d)
48 #define derDecDbg1(a, b)
49 #define derDecDbg2(a, b, c)
50 #define derDecDbg3(a, b, c, d)
51 #endif /* DER_DECODE_DEBUG */
54 * Basic decoding primitive. Only works with:
56 * -- definite length encoding
58 * -- max content length fits in a DERSize
60 * No malloc or copy of the contents is performed; the returned
61 * content->content.data is a pointer into the incoming der data.
63 DERReturn
DERDecodeItem(
64 const DERItem
*der
, /* data to decode */
65 DERDecodedInfo
*decoded
) /* RETURNED */
67 DERByte tag1
; /* first tag byte */
68 DERByte len1
; /* first length byte */
69 DERTag tagNumber
; /* tag number without class and method bits */
70 DERByte
*derPtr
= der
->data
;
71 DERSize derLen
= der
->length
;
73 /* The tag decoding below is fully BER complient. We support a max tag
74 value of 2 ^ ((sizeof(DERTag) * 8) - 3) - 1 so for tag size 1 byte we
75 support tag values from 0 - 0x1F. For tag size 2 tag values
76 from 0 - 0x1FFF and for tag size 4 values from 0 - 0x1FFFFFFF. */
78 return DR_DecodeError
;
80 /* Grab the first byte of the tag. */
83 tagNumber
= tag1
& 0x1F;
84 if(tagNumber
== 0x1F) {
85 #ifdef DER_MULTIBYTE_TAGS
86 /* Long tag form: bit 8 of each octet shall be set to one unless it is
87 the last octet of the tag */
88 const DERTag overflowMask
= ((DERTag
)0x7F << (sizeof(DERTag
) * 8 - 7));
92 if(derLen
< 2 || (tagNumber
& overflowMask
) != 0) {
93 return DR_DecodeError
;
97 tagNumber
= (tagNumber
<< 7) | (tagByte
& 0x7F);
98 } while((tagByte
& 0x80) != 0);
100 /* Check for any of the top 3 reserved bits being set. */
101 if ((tagNumber
& (overflowMask
<< 4)) != 0)
103 return DR_DecodeError
;
105 /* Returned tag, top 3 bits are class/method remaining bits are number. */
106 decoded
->tag
= ((DERTag
)(tag1
& 0xE0) << ((sizeof(DERTag
) - 1) * 8)) | tagNumber
;
108 /* Tag decoding above ensured we have at least one more input byte left. */
112 /* long length form - first byte is length of length */
113 DERSize longLen
= 0; /* long form length */
117 if((len1
> sizeof(DERSize
)) || (len1
> derLen
)) {
119 return DR_DecodeError
;
121 for(dex
=0; dex
<len1
; dex
++) {
123 longLen
|= *derPtr
++;
126 if(longLen
> derLen
) {
127 /* not enough data left for this encoding */
128 return DR_DecodeError
;
130 decoded
->content
.data
= derPtr
;
131 decoded
->content
.length
= longLen
;
134 /* short length form, len1 is the length */
136 /* not enough data left for this encoding */
137 return DR_DecodeError
;
139 decoded
->content
.data
= derPtr
;
140 decoded
->content
.length
= len1
;
147 * Given a BIT_STRING, in the form of its raw content bytes,
148 * obtain the number of unused bits and the raw bit string bytes.
150 DERReturn
DERParseBitString(
151 const DERItem
*contents
,
152 DERItem
*bitStringBytes
, /* RETURNED */
153 DERByte
*numUnusedBits
) /* RETURNED */
155 if(contents
->length
< 2) {
156 /* not enough room for actual bits after the unused bits field */
158 bitStringBytes
->data
= NULL
;
159 bitStringBytes
->length
= 0;
162 *numUnusedBits
= contents
->data
[0];
163 bitStringBytes
->data
= contents
->data
+ 1;
164 bitStringBytes
->length
= contents
->length
- 1;
169 * Given a BOOLEAN, in the form of its raw content bytes,
172 DERReturn
DERParseBoolean(
173 const DERItem
*contents
,
175 bool *value
) { /* RETURNED */
176 if (contents
->length
== 0) {
177 *value
= defaultValue
;
180 if (contents
->length
!= 1 ||
181 (contents
->data
[0] != 0 && contents
->data
[0] != 0xFF))
182 return DR_DecodeError
;
184 *value
= contents
->data
[0] != 0;
188 DERReturn
DERParseInteger(
189 const DERItem
*contents
,
190 uint32_t *result
) { /* RETURNED */
191 DERSize ix
, length
= contents
->length
;
193 return DR_BufOverflow
;
195 for (ix
= 0; ix
< length
; ++ix
) {
197 value
+= contents
->data
[ix
];
203 /* Sequence/set support */
206 * To decode a set or sequence, call DERDecodeSeqInit once, then
207 * call DERDecodeSeqNext to get each enclosed item.
208 * DERDecodeSeqNext returns DR_EndOfSequence when no more
209 * items are available.
211 DERReturn
DERDecodeSeqInit(
212 const DERItem
*der
, /* data to decode */
213 DERTag
*tag
, /* RETURNED tag of sequence/set. This will be
214 * either ASN1_CONSTR_SEQUENCE or ASN1_CONSTR_SET. */
215 DERSequence
*derSeq
) /* RETURNED, to use in DERDecodeSeqNext */
217 DERDecodedInfo decoded
;
220 drtn
= DERDecodeItem(der
, &decoded
);
225 switch(decoded
.tag
) {
226 case ASN1_CONSTR_SEQUENCE
:
227 case ASN1_CONSTR_SET
:
230 return DR_UnexpectedTag
;
232 derSeq
->nextItem
= decoded
.content
.data
;
233 derSeq
->end
= decoded
.content
.data
+ decoded
.content
.length
;
238 * Use this to start in on decoding a sequence's content, when
239 * the top-level tag and content have already been decoded.
241 DERReturn
DERDecodeSeqContentInit(
242 const DERItem
*content
,
243 DERSequence
*derSeq
) /* RETURNED, to use in DERDecodeSeqNext */
245 /* just prepare for decoding items in content */
246 derSeq
->nextItem
= content
->data
;
247 derSeq
->end
= content
->data
+ content
->length
;
251 DERReturn
DERDecodeSeqNext(
253 DERDecodedInfo
*decoded
) /* RETURNED */
258 if(derSeq
->nextItem
>= derSeq
->end
) {
259 /* normal termination, contents all used up */
260 return DR_EndOfSequence
;
263 /* decode next item */
264 item
.data
= derSeq
->nextItem
;
265 item
.length
= derSeq
->end
- derSeq
->nextItem
;
266 drtn
= DERDecodeItem(&item
, decoded
);
271 /* skip over the item we just decoded */
272 derSeq
->nextItem
= decoded
->content
.data
+ decoded
->content
.length
;
277 * High level sequence parse, starting with top-level tag and content.
278 * Top level tag must be ASN1_CONSTR_SEQUENCE - if it's not, and that's
279 * OK, use DERParseSequenceContent().
281 DERReturn
DERParseSequence(
283 DERShort numItems
, /* size of itemSpecs[] */
284 const DERItemSpec
*itemSpecs
,
285 void *dest
, /* DERDecodedInfo(s) here RETURNED */
286 DERSize sizeToZero
) /* optional */
289 DERDecodedInfo topDecode
;
291 drtn
= DERDecodeItem(der
, &topDecode
);
295 if(topDecode
.tag
!= ASN1_CONSTR_SEQUENCE
) {
296 return DR_UnexpectedTag
;
298 return DERParseSequenceContent(&topDecode
.content
,
299 numItems
, itemSpecs
, dest
, sizeToZero
);
302 /* high level sequence parse, starting with sequence's content */
303 DERReturn
DERParseSequenceContent(
304 const DERItem
*content
,
305 DERShort numItems
, /* size of itemSpecs[] */
306 const DERItemSpec
*itemSpecs
,
307 void *dest
, /* DERDecodedInfo(s) here RETURNED */
308 DERSize sizeToZero
) /* optional */
313 DERByte
*currDER
; /* full DER encoding of current item */
316 DERMemset(dest
, 0, sizeToZero
);
319 drtn
= DERDecodeSeqContentInit(content
, &derSeq
);
325 for(itemDex
=0 ; itemDex
<numItems
; ) {
326 DERDecodedInfo currDecoded
;
331 /* save this in case of DER_DEC_SAVE_DER */
332 currDER
= derSeq
.nextItem
;
334 drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
);
337 * One legal error here is DR_EndOfSequence when
338 * all remaining DERSequenceItems are optional.
340 if(drtn
== DR_EndOfSequence
) {
341 for(i
=itemDex
; i
<numItems
; i
++) {
342 if(!(itemSpecs
[i
].options
& DER_DEC_OPTIONAL
)) {
343 /* unexpected end of sequence */
344 return DR_IncompleteSeq
;
347 /* the rest are optional; success */
351 /* any other error is fatal */
357 * Seek matching tag or ASN_ANY in itemSpecs, skipping
358 * over optional items.
360 foundTag
= currDecoded
.tag
;
361 derDecDbg1("--- foundTag 0x%x\n", foundTag
);
363 for(i
=itemDex
; i
<numItems
; i
++) {
364 const DERItemSpec
*currItemSpec
= &itemSpecs
[i
];
365 DERShort currOptions
= currItemSpec
->options
;
366 derDecDbg3("--- currItem %u expectTag 0x%x currOptions 0x%x\n",
367 i
, currItemSpec
->tag
, currOptions
);
369 if((currOptions
& DER_DEC_ASN_ANY
) ||
370 (foundTag
== currItemSpec
->tag
)) {
372 * We're good with this one. Cook up destination address
375 if(!(currOptions
& DER_DEC_SKIP
)) {
376 derDecDbg1("--- MATCH at currItem %u\n", i
);
377 DERByte
*byteDst
= (DERByte
*)dest
+ currItemSpec
->offset
;
378 DERItem
*dst
= (DERItem
*)byteDst
;
379 *dst
= currDecoded
.content
;
380 if(currOptions
& DER_DEC_SAVE_DER
) {
381 /* recreate full DER encoding of this item */
382 derDecDbg1("--- SAVE_DER at currItem %u\n", i
);
384 dst
->length
+= (currDecoded
.content
.data
- currDER
);
388 /* on to next item */
391 /* is this the end? */
392 if(itemDex
== numItems
) {
393 /* normal termination */
397 /* on to next item */
401 } /* ASN_ANY, or match */
404 * If current itemSpec isn't optional, abort - else on to
407 if(!(currOptions
& DER_DEC_OPTIONAL
)) {
408 derDecDbg1("--- MISMATCH at currItem %u, !OPTIONAL, abort\n", i
);
409 return DR_UnexpectedTag
;
412 /* else this was optional, on to next item */
413 } /* searching for tag match */
415 if(foundMatch
== 0) {
417 * Found an item we couldn't match to any tag spec and we're at
420 derDecDbg("--- TAG NOT FOUND, abort\n");
421 return DR_UnexpectedTag
;
424 /* else on to next item */
428 * If we get here, there appears to be more to process, but we've
429 * given the caller everything they want.
436 * High level sequence parse, starting with top-level tag and content.
437 * Top level tag must be ASN1_CONSTR_SEQUENCE - if it's not, and that's
438 * OK, use DERParseSequenceContent().
440 DERReturn
DERParseSequenceOf(
442 DERShort numItems
, /* size of itemSpecs[] */
443 const DERItemSpec
*itemSpecs
,
444 void *dest
, /* DERDecodedInfo(s) here RETURNED */
445 DERSize
*numDestItems
) /* output */
448 DERDecodedInfo topDecode
;
450 drtn
= DERDecodeItem(der
, &topDecode
);
454 if(topDecode
.tag
!= ASN1_CONSTR_SEQUENCE
) {
455 return DR_UnexpectedTag
;
457 return DERParseSequenceContent(&topDecode
.content
,
458 numItems
, itemSpecs
, dest
, sizeToZero
);
462 * High level set of parse, starting with top-level tag and content.
463 * Top level tag must be ASN1_CONSTR_SET - if it's not, and that's
464 * OK, use DERParseSetOrSequenceOfContent().
466 DERReturn
DERParseSetOf(
468 DERShort numItems
, /* size of itemSpecs[] */
469 const DERItemSpec
*itemSpecs
,
470 void *dest
, /* DERDecodedInfo(s) here RETURNED */
471 DERSize
*numDestItems
) /* output */
474 DERDecodedInfo topDecode
;
476 drtn
= DERDecodeItem(der
, &topDecode
);
480 if(topDecode
.tag
!= ASN1_CONSTR_SET
) {
481 return DR_UnexpectedTag
;
483 return DERParseSetOrSequenceOfContent(&topDecode
.content
,
484 numItems
, itemSpecs
, dest
, numDestItems
);
487 /* High level set of or sequence of parse, starting with set or
488 sequence's content */
489 DERReturn
DERParseSetOrSequenceOfContent(
490 const DERItem
*content
,
491 void(*itemHandeler
)(void *, const DERDecodedInfo
*)
492 void *itemHandelerContext
);
497 drtn
= DERDecodeSeqContentInit(content
, &derSeq
);
498 require_noerr_quiet(drtn
, badCert
);
502 DERDecodedInfo currDecoded
;
507 drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
);
509 /* The only legal error here is DR_EndOfSequence. */
510 if(drtn
== DR_EndOfSequence
) {
511 /* no more items left in the sequence; success */
515 /* any other error is fatal */
516 require_noerr_quiet(drtn
, badCert
);
520 /* Each element can be anything. */
521 foundTag
= currDecoded
.tag
;
524 * We're good with this one. Cook up destination address
527 DERByte
*byteDst
= (DERByte
*)dest
+ currItemSpec
->offset
;
528 DERItem
*dst
= (DERItem
*)byteDst
;
529 *dst
= currDecoded
.content
;
530 if(currOptions
& DER_DEC_SAVE_DER
) {
531 /* recreate full DER encoding of this item */
532 derDecDbg1("--- SAVE_DER at currItem %u\n", i
);
534 dst
->length
+= (currDecoded
.content
.data
- currDER
);
537 /* on to next item */
540 /* is this the end? */
541 if(itemDex
== numItems
) {
542 /* normal termination */
546 /* on to next item */
552 * If current itemSpec isn't optional, abort - else on to
555 if(!(currOptions
& DER_DEC_OPTIONAL
)) {
556 derDecDbg1("--- MISMATCH at currItem %u, !OPTIONAL, abort\n", i
);
557 return DR_UnexpectedTag
;
560 /* else this was optional, on to next item */
561 } /* searching for tag match */
563 if(foundMatch
== 0) {
565 * Found an item we couldn't match to any tag spec and we're at
568 derDecDbg("--- TAG NOT FOUND, abort\n");
569 return DR_UnexpectedTag
;
572 /* else on to next item */
576 * If we get here, there appears to be more to process, but we've
577 * given the caller everything they want.
584 #endif /* DER_DECODE_ENABLE */