#include "DER_Encode.h"
#include "asn1Types.h"
#include "libDER_config.h"
#include "DER_Decode.h"
#ifndef DER_ENCODE_ENABLE
#error Please define DER_ENCODE_ENABLE.
#endif
#if DER_ENCODE_ENABLE
static DERSize DERLengthOfTag(
DERTag tag)
{
DERSize rtn = 1;
tag &= ASN1_TAGNUM_MASK;
if (tag >= 0x1F) {
while(tag != 0) {
rtn++;
tag >>= 7;
}
}
return rtn;
}
static DERReturn DEREncodeTag(
DERTag tag,
DERByte *buf,
DERSize *inOutLen)
{
DERSize outLen = DERLengthOfTag(tag);
DERTag tagNumber = tag & ASN1_TAGNUM_MASK;
DERByte tag1 = (tag >> (sizeof(DERTag) * 8 - 8)) & 0xE0;
if(outLen > *inOutLen) {
return DR_BufOverflow;
}
if(outLen == 1) {
*buf = tag1 | tagNumber;
}
else {
DERByte *tagBytes = buf + outLen; *buf = tag1 | 0x1F; *--tagBytes = tagNumber & 0x7F;
tagNumber >>= 7;
while(tagNumber != 0) {
*--tagBytes = (tagNumber & 0x7F) | 0x80;
tagNumber >>= 7;
}
}
*inOutLen = outLen;
return DR_Success;
}
DERSize DERLengthOfLength(
DERSize length)
{
DERSize rtn;
if(length < 0x80) {
return 1;
}
rtn = 1;
while(length != 0) {
rtn++;
length >>= 8;
}
return rtn;
}
DERReturn DEREncodeLength(
DERSize length,
DERByte *buf,
DERSize *inOutLen)
{
DERByte *lenBytes;
DERSize outLen = DERLengthOfLength(length);
if(outLen > *inOutLen) {
return DR_BufOverflow;
}
if(length < 0x80) {
*buf = (DERByte)length;
*inOutLen = 1;
return DR_Success;
}
*buf = (outLen - 1) | 0x80; lenBytes = buf + outLen - 1; while(length != 0) {
*lenBytes-- = (DERByte)length;
length >>= 8;
}
*inOutLen = outLen;
return DR_Success;
}
DERSize DERLengthOfItem(
DERTag tag,
DERSize length)
{
return DERLengthOfTag(tag) + DERLengthOfLength(length) + length;
}
DERReturn DEREncodeItem(
DERTag tag,
DERSize length,
const DERByte *src,
DERByte *derOut,
DERSize *inOutLen)
{
DERReturn drtn;
DERSize itemLen;
DERByte *currPtr = derOut;
DERSize bytesLeft = DERLengthOfItem(tag, length);
if(bytesLeft > *inOutLen) {
return DR_BufOverflow;
}
*inOutLen = bytesLeft;
itemLen = bytesLeft;
drtn = DEREncodeTag(tag, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
itemLen = bytesLeft;
drtn = DEREncodeLength(length, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
DERMemmove(currPtr, src, length);
return DR_Success;
}
static
DERSize DERContentLengthOfEncodedSequence(
const void *src,
DERShort numItems,
const DERItemSpec *itemSpecs)
{
DERSize contentLen = 0;
unsigned dex;
DERSize thisContentLen;
for(dex=0; dex<numItems; dex++) {
const DERItemSpec *currItemSpec = &itemSpecs[dex];
DERShort currOptions = currItemSpec->options;
const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
const DERItem *itemSrc = (const DERItem *)byteSrc;
if(currOptions & DER_ENC_WRITE_DER) {
contentLen += itemSrc->length;
continue;
}
if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
continue;
}
contentLen += DERLengthOfTag(currItemSpec->tag);
thisContentLen = itemSrc->length;
if((currOptions & DER_ENC_SIGNED_INT) &&
(itemSrc->length != 0)) {
if(itemSrc->data[0] & 0x80) {
thisContentLen++;
}
}
contentLen += DERLengthOfLength(thisContentLen);
contentLen += thisContentLen;
}
return contentLen;
}
DERReturn DEREncodeSequence(
DERTag topTag,
const void *src,
DERShort numItems,
const DERItemSpec *itemSpecs,
DERByte *derOut,
DERSize *inOutLen)
{
const DERByte *endPtr = derOut + *inOutLen;
DERByte *currPtr = derOut;
DERSize bytesLeft = *inOutLen;
DERSize contentLen;
DERReturn drtn;
DERSize itemLen;
unsigned dex;
itemLen = bytesLeft;
drtn = DEREncodeTag(topTag, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
if(currPtr >= endPtr) {
return DR_BufOverflow;
}
contentLen = DERContentLengthOfEncodedSequence(src, numItems, itemSpecs);
itemLen = bytesLeft;
drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
if(currPtr + contentLen > endPtr) {
return DR_BufOverflow;
}
for(dex=0; dex<numItems; dex++) {
const DERItemSpec *currItemSpec = &itemSpecs[dex];
DERShort currOptions = currItemSpec->options;
const DERByte *byteSrc = (const DERByte *)src + currItemSpec->offset;
const DERItem *itemSrc = (const DERItem *)byteSrc;
int prependZero = 0;
if(currOptions & DER_ENC_WRITE_DER) {
DERMemmove(currPtr, itemSrc->data, itemSrc->length);
currPtr += itemSrc->length;
bytesLeft -= itemSrc->length;
continue;
}
if ((currOptions & DER_DEC_OPTIONAL) && itemSrc->length == 0) {
continue;
}
itemLen = bytesLeft;
drtn = DEREncodeTag(currItemSpec->tag, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
contentLen = itemSrc->length;
if((currOptions & DER_ENC_SIGNED_INT) &&
(itemSrc->length != 0)) {
if(itemSrc->data[0] & 0x80) {
contentLen++;
prependZero = 1;
}
}
itemLen = bytesLeft;
drtn = DEREncodeLength(contentLen, currPtr, &itemLen);
if(drtn) {
return drtn;
}
currPtr += itemLen;
bytesLeft -= itemLen;
if(prependZero) {
*currPtr++ = 0;
bytesLeft--;
}
DERMemmove(currPtr, itemSrc->data, itemSrc->length);
currPtr += itemSrc->length;
bytesLeft -= itemSrc->length;
}
*inOutLen = (currPtr - derOut);
return DR_Success;
}
DERSize DERLengthOfEncodedSequence(
DERTag topTag,
const void *src,
DERShort numItems,
const DERItemSpec *itemSpecs)
{
DERSize contentLen = DERContentLengthOfEncodedSequence(
src, numItems, itemSpecs);
return DERLengthOfTag(topTag) +
DERLengthOfLength(contentLen) +
contentLen;
}
#endif