#include "DER_Decode.h"
#include "asn1Types.h"
#include "libDER_config.h"
#ifndef DER_DECODE_ENABLE
#error Please define DER_DECODE_ENABLE.
#endif
#if DER_DECODE_ENABLE
#define DER_DECODE_DEBUG 0
#if DER_DECODE_DEBUG
#include <stdio.h>
#define derDecDbg(a) printf(a)
#define derDecDbg1(a, b) printf(a, b)
#define derDecDbg2(a, b, c) printf(a, b, c)
#define derDecDbg3(a, b, c, d) printf(a, b, c, d)
#else
#define derDecDbg(a)
#define derDecDbg1(a, b)
#define derDecDbg2(a, b, c)
#define derDecDbg3(a, b, c, d)
#endif
DERReturn DERDecodeItem(
const DERItem *der,
DERDecodedInfo *decoded)
{
DERByte tag1;
DERByte len1;
DERTag tagNumber;
DERByte *derPtr = der->data;
DERSize derLen = der->length;
if(derLen < 2) {
return DR_DecodeError;
}
tag1 = *derPtr++;
derLen--;
tagNumber = tag1 & 0x1F;
if(tagNumber == 0x1F) {
#ifdef DER_MULTIBYTE_TAGS
const DERTag overflowMask = ((DERTag)0x7F << (sizeof(DERTag) * 8 - 7));
DERByte tagByte;
tagNumber = 0;
do {
if(derLen < 2 || (tagNumber & overflowMask) != 0) {
return DR_DecodeError;
}
tagByte = *derPtr++;
derLen--;
tagNumber = (tagNumber << 7) | (tagByte & 0x7F);
} while((tagByte & 0x80) != 0);
if ((tagNumber & (overflowMask << 4)) != 0)
#endif
return DR_DecodeError;
}
decoded->tag = ((DERTag)(tag1 & 0xE0) << ((sizeof(DERTag) - 1) * 8)) | tagNumber;
len1 = *derPtr++;
derLen--;
if(len1 & 0x80) {
DERSize longLen = 0;
unsigned dex;
len1 &= 0x7f;
if((len1 > sizeof(DERSize)) || (len1 > derLen)) {
return DR_DecodeError;
}
for(dex=0; dex<len1; dex++) {
longLen <<= 8;
longLen |= *derPtr++;
derLen--;
}
if(longLen > derLen) {
return DR_DecodeError;
}
decoded->content.data = derPtr;
decoded->content.length = longLen;
}
else {
if(len1 > derLen) {
return DR_DecodeError;
}
decoded->content.data = derPtr;
decoded->content.length = len1;
}
return DR_Success;
}
DERReturn DERParseBitString(
const DERItem *contents,
DERItem *bitStringBytes,
DERByte *numUnusedBits)
{
if(contents->length < 2) {
*numUnusedBits = 0;
bitStringBytes->data = NULL;
bitStringBytes->length = 0;
return DR_Success;
}
*numUnusedBits = contents->data[0];
bitStringBytes->data = contents->data + 1;
bitStringBytes->length = contents->length - 1;
return DR_Success;
}
DERReturn DERParseBoolean(
const DERItem *contents,
bool defaultValue,
bool *value) {
if (contents->length == 0) {
*value = defaultValue;
return DR_Success;
}
if (contents->length != 1 ||
(contents->data[0] != 0 && contents->data[0] != 0xFF))
return DR_DecodeError;
*value = contents->data[0] != 0;
return DR_Success;
}
DERReturn DERParseInteger(
const DERItem *contents,
uint32_t *result) {
DERSize ix, length = contents->length;
if (length > 4)
return DR_BufOverflow;
uint32_t value = 0;
for (ix = 0; ix < length; ++ix) {
value <<= 8;
value += contents->data[ix];
}
*result = value;
return DR_Success;
}
DERReturn DERDecodeSeqInit(
const DERItem *der,
DERTag *tag,
DERSequence *derSeq)
{
DERDecodedInfo decoded;
DERReturn drtn;
drtn = DERDecodeItem(der, &decoded);
if(drtn) {
return drtn;
}
*tag = decoded.tag;
switch(decoded.tag) {
case ASN1_CONSTR_SEQUENCE:
case ASN1_CONSTR_SET:
break;
default:
return DR_UnexpectedTag;
}
derSeq->nextItem = decoded.content.data;
derSeq->end = decoded.content.data + decoded.content.length;
return DR_Success;
}
DERReturn DERDecodeSeqContentInit(
const DERItem *content,
DERSequence *derSeq)
{
derSeq->nextItem = content->data;
derSeq->end = content->data + content->length;
return DR_Success;
}
DERReturn DERDecodeSeqNext(
DERSequence *derSeq,
DERDecodedInfo *decoded)
{
DERReturn drtn;
DERItem item;
if(derSeq->nextItem >= derSeq->end) {
return DR_EndOfSequence;
}
item.data = derSeq->nextItem;
item.length = derSeq->end - derSeq->nextItem;
drtn = DERDecodeItem(&item, decoded);
if(drtn) {
return drtn;
}
derSeq->nextItem = decoded->content.data + decoded->content.length;
return DR_Success;
}
DERReturn DERParseSequence(
const DERItem *der,
DERShort numItems,
const DERItemSpec *itemSpecs,
void *dest,
DERSize sizeToZero)
{
DERReturn drtn;
DERDecodedInfo topDecode;
drtn = DERDecodeItem(der, &topDecode);
if(drtn) {
return drtn;
}
if(topDecode.tag != ASN1_CONSTR_SEQUENCE) {
return DR_UnexpectedTag;
}
return DERParseSequenceContent(&topDecode.content,
numItems, itemSpecs, dest, sizeToZero);
}
DERReturn DERParseSequenceContent(
const DERItem *content,
DERShort numItems,
const DERItemSpec *itemSpecs,
void *dest,
DERSize sizeToZero)
{
DERSequence derSeq;
DERReturn drtn;
DERShort itemDex;
DERByte *currDER;
if(sizeToZero) {
DERMemset(dest, 0, sizeToZero);
}
drtn = DERDecodeSeqContentInit(content, &derSeq);
if(drtn) {
return drtn;
}
for(itemDex=0 ; itemDex<numItems; ) {
DERDecodedInfo currDecoded;
DERShort i;
DERTag foundTag;
char foundMatch = 0;
currDER = derSeq.nextItem;
drtn = DERDecodeSeqNext(&derSeq, &currDecoded);
if(drtn) {
if(drtn == DR_EndOfSequence) {
for(i=itemDex; i<numItems; i++) {
if(!(itemSpecs[i].options & DER_DEC_OPTIONAL)) {
return DR_IncompleteSeq;
}
}
return DR_Success;
}
else {
return drtn;
}
}
foundTag = currDecoded.tag;
derDecDbg1("--- foundTag 0x%x\n", foundTag);
for(i=itemDex; i<numItems; i++) {
const DERItemSpec *currItemSpec = &itemSpecs[i];
DERShort currOptions = currItemSpec->options;
derDecDbg3("--- currItem %u expectTag 0x%x currOptions 0x%x\n",
i, currItemSpec->tag, currOptions);
if((currOptions & DER_DEC_ASN_ANY) ||
(foundTag == currItemSpec->tag)) {
if(!(currOptions & DER_DEC_SKIP)) {
derDecDbg1("--- MATCH at currItem %u\n", i);
DERByte *byteDst = (DERByte *)dest + currItemSpec->offset;
DERItem *dst = (DERItem *)byteDst;
*dst = currDecoded.content;
if(currOptions & DER_DEC_SAVE_DER) {
derDecDbg1("--- SAVE_DER at currItem %u\n", i);
dst->data = currDER;
dst->length += (currDecoded.content.data - currDER);
}
}
itemDex = i + 1;
if(itemDex == numItems) {
return DR_Success;
}
else {
foundMatch = 1;
break;
}
}
if(!(currOptions & DER_DEC_OPTIONAL)) {
derDecDbg1("--- MISMATCH at currItem %u, !OPTIONAL, abort\n", i);
return DR_UnexpectedTag;
}
}
if(foundMatch == 0) {
derDecDbg("--- TAG NOT FOUND, abort\n");
return DR_UnexpectedTag;
}
}
return DR_Success;
}
#if 0
DERReturn DERParseSequenceOf(
const DERItem *der,
DERShort numItems,
const DERItemSpec *itemSpecs,
void *dest,
DERSize *numDestItems)
{
DERReturn drtn;
DERDecodedInfo topDecode;
drtn = DERDecodeItem(der, &topDecode);
if(drtn) {
return drtn;
}
if(topDecode.tag != ASN1_CONSTR_SEQUENCE) {
return DR_UnexpectedTag;
}
return DERParseSequenceContent(&topDecode.content,
numItems, itemSpecs, dest, sizeToZero);
}
DERReturn DERParseSetOf(
const DERItem *der,
DERShort numItems,
const DERItemSpec *itemSpecs,
void *dest,
DERSize *numDestItems)
{
DERReturn drtn;
DERDecodedInfo topDecode;
drtn = DERDecodeItem(der, &topDecode);
if(drtn) {
return drtn;
}
if(topDecode.tag != ASN1_CONSTR_SET) {
return DR_UnexpectedTag;
}
return DERParseSetOrSequenceOfContent(&topDecode.content,
numItems, itemSpecs, dest, numDestItems);
}
DERReturn DERParseSetOrSequenceOfContent(
const DERItem *content,
void(*itemHandeler)(void *, const DERDecodedInfo *)
void *itemHandelerContext);
{
DERSequence derSeq;
DERShort itemDex;
drtn = DERDecodeSeqContentInit(content, &derSeq);
require_noerr_quiet(drtn, badCert);
for (;;) {
DERDecodedInfo currDecoded;
DERShort i;
DERByte foundTag;
char foundMatch = 0;
drtn = DERDecodeSeqNext(&derSeq, &currDecoded);
if(drtn) {
if(drtn == DR_EndOfSequence) {
return DR_Success;
}
else {
require_noerr_quiet(drtn, badCert);
}
}
foundTag = currDecoded.tag;
DERByte *byteDst = (DERByte *)dest + currItemSpec->offset;
DERItem *dst = (DERItem *)byteDst;
*dst = currDecoded.content;
if(currOptions & DER_DEC_SAVE_DER) {
derDecDbg1("--- SAVE_DER at currItem %u\n", i);
dst->data = currDER;
dst->length += (currDecoded.content.data - currDER);
}
itemDex = i + 1;
if(itemDex == numItems) {
return DR_Success;
}
else {
foundMatch = 1;
break;
}
if(!(currOptions & DER_DEC_OPTIONAL)) {
derDecDbg1("--- MISMATCH at currItem %u, !OPTIONAL, abort\n", i);
return DR_UnexpectedTag;
}
}
if(foundMatch == 0) {
derDecDbg("--- TAG NOT FOUND, abort\n");
return DR_UnexpectedTag;
}
}
return DR_Success;
}
}
#endif
#endif