You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1241 lines
35 KiB
1241 lines
35 KiB
/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
|
|
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
// THE FOLLOWING IS FROM BERENCOD.C
|
|
|
|
/* get the expected length based on the table */
|
|
ASN1uint32_t _BERGetLength(ASN1uint32_t val, const ASN1uint32_t Tbl[], ASN1uint32_t cItems)
|
|
{
|
|
ASN1uint32_t i;
|
|
for (i = 0; i < cItems; i++)
|
|
{
|
|
if (val < Tbl[i])
|
|
return i+1;
|
|
}
|
|
return cItems+1;
|
|
}
|
|
|
|
static const ASN1uint32_t c_TagTable[] = { 31, 0x80, 0x4000, 0x200000, 0x10000000 };
|
|
|
|
/* encode a tag */
|
|
int ASN1BEREncTag(ASN1encoding_t enc, ASN1uint32_t tag)
|
|
{
|
|
ASN1uint32_t tagclass, tagvalue, cbTagLength;
|
|
|
|
tagclass = (tag >> 24) & 0xe0;
|
|
tagvalue = tag & 0x1fffffff;
|
|
|
|
cbTagLength = _BERGetLength(tagvalue, c_TagTable, ARRAY_SIZE(c_TagTable));
|
|
if (ASN1BEREncCheck(enc, cbTagLength))
|
|
{
|
|
if (cbTagLength == 1)
|
|
{
|
|
*enc->pos++ = (ASN1octet_t)(tagclass | tagvalue);
|
|
}
|
|
else
|
|
{
|
|
*enc->pos++ = (ASN1octet_t)(tagclass | 0x1f);
|
|
switch (cbTagLength)
|
|
{
|
|
case 6:
|
|
*enc->pos++ = (ASN1octet_t)((tagvalue >> 28) | 0x80);
|
|
// lonchanc: intentionally fall through
|
|
case 5:
|
|
*enc->pos++ = (ASN1octet_t)((tagvalue >> 21) | 0x80);
|
|
// lonchanc: intentionally fall through
|
|
case 4:
|
|
*enc->pos++ = (ASN1octet_t)((tagvalue >> 14) | 0x80);
|
|
// lonchanc: intentionally fall through
|
|
case 3:
|
|
*enc->pos++ = (ASN1octet_t)((tagvalue >> 7) | 0x80);
|
|
// lonchanc: intentionally fall through
|
|
case 2:
|
|
*enc->pos++ = (ASN1octet_t)(tagvalue & 0x7f);
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* put the length value */
|
|
void _BERPutLength(ASN1encoding_t enc, ASN1uint32_t len, ASN1uint32_t cbLength)
|
|
{
|
|
if (cbLength > 1)
|
|
{
|
|
*enc->pos++ = (ASN1octet_t) (0x7f + cbLength); // 0x80 + cbLength - 1;
|
|
}
|
|
|
|
switch (cbLength)
|
|
{
|
|
case 5:
|
|
*enc->pos++ = (ASN1octet_t)(len >> 24);
|
|
// lonchanc: intentionally fall through
|
|
case 4:
|
|
*enc->pos++ = (ASN1octet_t)(len >> 16);
|
|
// lonchanc: intentionally fall through
|
|
case 3:
|
|
*enc->pos++ = (ASN1octet_t)(len >> 8);
|
|
// lonchanc: intentionally fall through
|
|
default: // case 2: case 1:
|
|
*enc->pos++ = (ASN1octet_t)len;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const ASN1uint32_t c_LengthTable[] = { 0x80, 0x100, 0x10000, 0x1000000 };
|
|
|
|
/* encode length */
|
|
int ASN1BEREncLength(ASN1encoding_t enc, ASN1uint32_t len)
|
|
{
|
|
ASN1uint32_t cbLength = _BERGetLength(len, c_LengthTable, ARRAY_SIZE(c_LengthTable));
|
|
|
|
if (ASN1BEREncCheck(enc, cbLength + len))
|
|
{
|
|
_BERPutLength(enc, len, cbLength);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* encode an octet string value */
|
|
int ASN1BEREncOctetString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1octet_t *val)
|
|
{
|
|
/* encode tag */
|
|
if (ASN1BEREncTag(enc, tag))
|
|
{
|
|
/* encode length */
|
|
if (ASN1BEREncLength(enc, len))
|
|
{
|
|
/* copy value */
|
|
CopyMemory(enc->pos, val, len);
|
|
enc->pos += len;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* encode a boolean value */
|
|
int ASN1BEREncBool(ASN1encoding_t enc, ASN1uint32_t tag, ASN1bool_t val)
|
|
{
|
|
if (ASN1BEREncTag(enc, tag))
|
|
{
|
|
if (ASN1BEREncLength(enc, 1))
|
|
{
|
|
*enc->pos++ = val ? 0xFF : 0;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const c_U32LengthTable[] = { 0x80, 0x8000, 0x800000, 0x80000000 };
|
|
|
|
/* encode a unsigned integer value */
|
|
int ASN1BEREncU32(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t val)
|
|
{
|
|
EncAssert(enc, tag != 0x01);
|
|
if (ASN1BEREncTag(enc, tag))
|
|
{
|
|
ASN1uint32_t cbLength;
|
|
cbLength = _BERGetLength(val, c_U32LengthTable, ARRAY_SIZE(c_U32LengthTable));
|
|
if (ASN1BEREncLength(enc, cbLength))
|
|
{
|
|
switch (cbLength)
|
|
{
|
|
case 5:
|
|
*enc->pos++ = 0;
|
|
// lonchanc: intentionally fall through
|
|
case 4:
|
|
*enc->pos++ = (ASN1octet_t)(val >> 24);
|
|
// lonchanc: intentionally fall through
|
|
case 3:
|
|
*enc->pos++ = (ASN1octet_t)(val >> 16);
|
|
// lonchanc: intentionally fall through
|
|
case 2:
|
|
*enc->pos++ = (ASN1octet_t)(val >> 8);
|
|
// lonchanc: intentionally fall through
|
|
case 1:
|
|
*enc->pos++ = (ASN1octet_t)(val);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// THE FOLLOWING IS FROM BERDECOD.C
|
|
|
|
|
|
/* check if len octets are left in decoding stream */
|
|
int ASN1BERDecCheck(ASN1decoding_t dec, ASN1uint32_t len)
|
|
{
|
|
// We need to ensure:
|
|
// 1) that dec->pos + len doesn't cause an arithmetic overflow
|
|
// 2) dec->pos + len doesn't exceed the size of our buffer
|
|
if (dec->pos + len >= dec->pos &&
|
|
dec->pos + len <= dec->buf + dec->size)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ASN1DecSetError(dec, ASN1_ERR_EOD);
|
|
return 0;
|
|
}
|
|
|
|
int _BERDecPeekCheck(ASN1decoding_t dec, ASN1uint32_t len)
|
|
{
|
|
return ((dec->pos + len <= dec->buf + dec->size) ? 1 : 0);
|
|
}
|
|
|
|
/* start decoding of a constructed value */
|
|
int _BERDecConstructed(ASN1decoding_t dec, ASN1uint32_t len, ASN1uint32_t infinite, ASN1decoding_t *dd, ASN1octet_t **ppBufEnd)
|
|
{
|
|
// safety net
|
|
DecAssert(dec, NULL != dd);
|
|
*dd = dec;
|
|
|
|
#if 0 // NO_NESTED_DECODING
|
|
// lonchanc: this does not work because open type can be the last component and
|
|
// the open type decoder needs to peek a tag. as a result, we may peek the tag
|
|
// outside the buffer boundary.
|
|
if (ppBufEnd && (! infinite))
|
|
{
|
|
*ppBufEnd = dec->pos + len;
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
/* initialize a new decoding stream as child of running decoding stream */
|
|
if (ASN1_CreateDecoder(dec->module, dd,
|
|
dec->pos, infinite ? dec->size - (ASN1uint32_t) (dec->pos - dec->buf) : len, dec) >= 0)
|
|
{
|
|
/* set pointer to end of decoding stream if definite length case selected */
|
|
*ppBufEnd = infinite ? NULL : (*dd)->buf + (*dd)->size;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode a tag value; return constructed bit if desired */
|
|
int ASN1BERDecTag(ASN1decoding_t dec, ASN1uint32_t tag, ASN1uint32_t *constructed)
|
|
{
|
|
ASN1uint32_t tagvalue, tagclass, c;
|
|
|
|
/* get tag class and value */
|
|
if (ASN1BERDecCheck(dec, 1))
|
|
{
|
|
tagclass = *dec->pos & 0xe0;
|
|
tagvalue = *dec->pos++ & 0x1f;
|
|
if (tagvalue == 0x1f)
|
|
{
|
|
tagvalue = 0;
|
|
do {
|
|
if (ASN1BERDecCheck(dec, 1))
|
|
{
|
|
c = *dec->pos++;
|
|
if (! (tagvalue & 0xe0000000))
|
|
{
|
|
tagvalue = (tagvalue << 7) | (c & 0x7f);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_BADTAG);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (c & 0x80);
|
|
}
|
|
|
|
/* extract constructed bit if wanted */
|
|
if (constructed)
|
|
{
|
|
*constructed = tagclass & 0x20;
|
|
tagclass &= ~0x20;
|
|
}
|
|
|
|
/* check if tag equals desires */
|
|
if (tag == ((tagclass << 24) | tagvalue))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ASN1DecSetError(dec, ASN1_ERR_BADTAG);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode length */
|
|
int ASN1BERDecLength(ASN1decoding_t dec, ASN1uint32_t *len, ASN1uint32_t *infinite)
|
|
{
|
|
// default is definite length
|
|
if (infinite)
|
|
{
|
|
*infinite = 0;
|
|
}
|
|
|
|
/* get length and infinite flag */
|
|
if (ASN1BERDecCheck(dec, 1))
|
|
{
|
|
ASN1uint32_t l = *dec->pos++;
|
|
if (l < 0x80)
|
|
{
|
|
*len = l;
|
|
}
|
|
else
|
|
if (l == 0x80)
|
|
{
|
|
*len = 0;
|
|
if (infinite)
|
|
{
|
|
*infinite = 1;
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
if (l <= 0x84)
|
|
{
|
|
ASN1uint32_t i = l - 0x80;
|
|
if (ASN1BERDecCheck(dec, i))
|
|
{
|
|
l = 0;
|
|
switch (i)
|
|
{
|
|
case 4:
|
|
l = *dec->pos++ << 24;
|
|
/*FALLTHROUGH*/
|
|
case 3:
|
|
l |= *dec->pos++ << 16;
|
|
/*FALLTHROUGH*/
|
|
case 2:
|
|
l |= *dec->pos++ << 8;
|
|
/*FALLTHROUGH*/
|
|
case 1:
|
|
l |= *dec->pos++;
|
|
break;
|
|
}
|
|
*len = l;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* check if enough octets left if length is known */
|
|
if (!infinite || !*infinite)
|
|
{
|
|
return ASN1BERDecCheck(dec, *len);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* decode an explicit tag */
|
|
int ASN1BERDecExplicitTag(ASN1decoding_t dec, ASN1uint32_t tag, ASN1decoding_t *dd, ASN1octet_t **ppBufEnd)
|
|
{
|
|
ASN1uint32_t len, infinite, constructed;
|
|
|
|
// safety net
|
|
if (dd)
|
|
{
|
|
*dd = dec;
|
|
}
|
|
|
|
/* skip the constructed tag */
|
|
if (ASN1BERDecTag(dec, tag | 0x20000000, NULL))
|
|
{
|
|
/* get the length */
|
|
if (ASN1BERDecLength(dec, &len, &infinite))
|
|
{
|
|
/* start decoding of constructed value */
|
|
if (! dd)
|
|
{
|
|
*ppBufEnd = infinite ? NULL : dec->pos + len;
|
|
return 1;
|
|
}
|
|
return _BERDecConstructed(dec, len, infinite, dd, ppBufEnd);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode octet string value (helper function) */
|
|
int _BERDecOctetStringWorker(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val, ASN1uint32_t fNoCopy, ASN1uint32_t nMaxRecursionDepth)
|
|
{
|
|
ASN1INTERNdecoding_t d = (ASN1INTERNdecoding_t)dec;
|
|
ASN1uint32_t constructed, len, infinite;
|
|
ASN1decoding_t dd;
|
|
ASN1octet_t *di;
|
|
|
|
/* BUG 750698: Limit the recursion depth for octet strings */
|
|
if (nMaxRecursionDepth-- == 0)
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return -1; /* max recursion depth exceeded */
|
|
}
|
|
|
|
if (ASN1BERDecTag(dec, tag, &constructed))
|
|
{
|
|
if (ASN1BERDecLength(dec, &len, &infinite))
|
|
{
|
|
if (! constructed)
|
|
{
|
|
val->length = len;
|
|
if (fNoCopy)
|
|
{
|
|
val->value = dec->pos;
|
|
dec->pos += len;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (len)
|
|
{
|
|
val->value = (ASN1octet_t *)DecMemAlloc(dec, len);
|
|
if (val->value)
|
|
{
|
|
CopyMemory(val->value, dec->pos, len);
|
|
dec->pos += len;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
val->value = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASN1octetstring_t o;
|
|
val->length = 0;
|
|
val->value = NULL;
|
|
if (_BERDecConstructed(dec, len, infinite, &dd, &di))
|
|
{
|
|
while (ASN1BERDecNotEndOfContents(dd, di))
|
|
{
|
|
int nRet;
|
|
|
|
o.length = 0;
|
|
o.value = NULL;
|
|
|
|
nRet = _BERDecOctetStringWorker(dd, 0x4, &o, fNoCopy, nMaxRecursionDepth);
|
|
|
|
if (-1 == nRet) /* max recursion depth exceeded */
|
|
{
|
|
/* propagate the error */
|
|
return nRet;
|
|
}
|
|
else if (nRet)
|
|
{
|
|
if (o.length)
|
|
{
|
|
if (fNoCopy)
|
|
{
|
|
*val = o;
|
|
break; // break out the loop because nocopy cannot have multiple constructed streams
|
|
}
|
|
|
|
/* resize value */
|
|
val->value = (ASN1octet_t *)DecMemReAlloc(dd, val->value,
|
|
val->length + o.length);
|
|
if (val->value)
|
|
{
|
|
/* concat octet strings */
|
|
CopyMemory(val->value + val->length, o.value, o.length);
|
|
val->length += o.length;
|
|
|
|
/* free unused octet string */
|
|
DecMemFree(dec, o.value);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ASN1BERDecEndOfContents(dec, dd, di);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* define the maximum allowed recursion depth for octet strings */
|
|
#define MAX_OCTET_STRING_DEPTH 10
|
|
|
|
/* decode octet string value */
|
|
int _BERDecOctetString(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val, ASN1uint32_t fNoCopy)
|
|
{
|
|
int nRet = _BERDecOctetStringWorker(dec, tag, val, fNoCopy, MAX_OCTET_STRING_DEPTH);
|
|
|
|
if (-1 == nRet)
|
|
{
|
|
nRet = 0;
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
/* decode octet string value, making copy */
|
|
int ASN1BERDecOctetString(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val)
|
|
{
|
|
return _BERDecOctetString(dec, tag, val, FALSE);
|
|
}
|
|
|
|
/* decode octet string value, no copy */
|
|
int ASN1BERDecOctetString2(ASN1decoding_t dec, ASN1uint32_t tag, ASN1octetstring_t *val)
|
|
{
|
|
return _BERDecOctetString(dec, tag, val, TRUE);
|
|
}
|
|
|
|
/* peek the following tag without advancing the read position */
|
|
int ASN1BERDecPeekTag(ASN1decoding_t dec, ASN1uint32_t *tag)
|
|
{
|
|
ASN1uint32_t tagvalue, tagclass, c;
|
|
ASN1octet_t *p;
|
|
|
|
*tag = 0; // invalid tag
|
|
if (_BERDecPeekCheck(dec, 1))
|
|
{
|
|
p = dec->pos;
|
|
|
|
/* get tagclass without primitive/constructed bit */
|
|
tagclass = *dec->pos & 0xc0;
|
|
|
|
/* get tag value */
|
|
tagvalue = *dec->pos++ & 0x1f;
|
|
if (tagvalue == 0x1f)
|
|
{
|
|
tagvalue = 0;
|
|
do {
|
|
if (_BERDecPeekCheck(dec, 1))
|
|
{
|
|
c = *dec->pos++;
|
|
if (! (tagvalue & 0xe0000000))
|
|
{
|
|
tagvalue = (tagvalue << 7) | (c & 0x7f);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_BADTAG);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (c & 0x80);
|
|
}
|
|
|
|
/* return tag */
|
|
*tag = ((tagclass << 24) | tagvalue);
|
|
|
|
/* reset decoding position */
|
|
dec->pos = p;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode boolean into ASN1boot_t */
|
|
int ASN1BERDecBool(ASN1decoding_t dec, ASN1uint32_t tag, ASN1bool_t *val)
|
|
{
|
|
/* skip tag */
|
|
if (ASN1BERDecTag(dec, tag, NULL))
|
|
{
|
|
/* get length */
|
|
ASN1uint32_t len;
|
|
if (ASN1BERDecLength(dec, &len, NULL))
|
|
{
|
|
if (len >= 1)
|
|
{
|
|
DecAssert(dec, len == 1);
|
|
*val = *dec->pos ? 1 : 0;
|
|
dec->pos += len; // self defensive
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode integer into unsigned 32 bit value */
|
|
int ASN1BERDecU32Val(ASN1decoding_t dec, ASN1uint32_t tag, ASN1uint32_t *val)
|
|
{
|
|
ASN1uint32_t len;
|
|
|
|
/* skip tag */
|
|
if (ASN1BERDecTag(dec, tag, NULL))
|
|
{
|
|
/* get length */
|
|
if (ASN1BERDecLength(dec, &len, NULL))
|
|
{
|
|
/* get value */
|
|
if (len >= 1)
|
|
{
|
|
switch (len)
|
|
{
|
|
case 1:
|
|
*val = *dec->pos++;
|
|
break;
|
|
case 2:
|
|
*val = (*dec->pos << 8) | dec->pos[1];
|
|
dec->pos += 2;
|
|
break;
|
|
case 3:
|
|
*val = (*dec->pos << 16) | (dec->pos[1] << 8) | dec->pos[2];
|
|
dec->pos += 3;
|
|
break;
|
|
case 4:
|
|
*val = (*dec->pos << 24) | (dec->pos[1] << 16) |
|
|
(dec->pos[2] << 8) | dec->pos[3];
|
|
dec->pos += 4;
|
|
break;
|
|
case 5:
|
|
if (! *dec->pos)
|
|
{
|
|
*val = (dec->pos[1] << 24) | (dec->pos[2] << 16) |
|
|
(dec->pos[3] << 8) | dec->pos[4];
|
|
dec->pos += 5;
|
|
break;
|
|
}
|
|
// intentionally fall through
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ASN1BERDecEndOfContents(ASN1decoding_t dec, ASN1decoding_t dd, ASN1octet_t *pBufEnd)
|
|
{
|
|
ASN1error_e err = ASN1_ERR_CORRUPT;
|
|
|
|
if (! dd)
|
|
{
|
|
dd = dec;
|
|
}
|
|
|
|
DecAssert(dec, NULL != dd);
|
|
|
|
if (pBufEnd)
|
|
{
|
|
/* end of definite length case: */
|
|
/* check if decoded up to end of contents */
|
|
if (dd->pos == pBufEnd)
|
|
{
|
|
dec->pos = pBufEnd;
|
|
err = ASN1_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* end of infinite length case: */
|
|
/* expect end-of-contents octets */
|
|
if (ASN1BERDecCheck(dd, 2))
|
|
{
|
|
if (0 == dd->pos[0] && 0 == dd->pos[1])
|
|
{
|
|
dd->pos += 2;
|
|
if (dd != dec)
|
|
{
|
|
/* finit child decoding stream and update parent decoding stream */
|
|
dec->pos = dd->pos;
|
|
}
|
|
err = ASN1_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = ASN1_ERR_EOD;
|
|
}
|
|
}
|
|
|
|
if (dd && dd != dec)
|
|
{
|
|
ASN1_CloseDecoder(dd);
|
|
}
|
|
|
|
if (ASN1_SUCCESS == err)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ASN1DecSetError(dec, err);
|
|
return 0;
|
|
}
|
|
|
|
/* check if end of contents (of a constructed value) has been reached */
|
|
int ASN1BERDecNotEndOfContents(ASN1decoding_t dec, ASN1octet_t *pBufEnd)
|
|
{
|
|
return (pBufEnd ?
|
|
(dec->pos < pBufEnd) :
|
|
(ASN1BERDecCheck(dec, 2) && (dec->pos[0] || dec->pos[1])));
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_BER
|
|
|
|
typedef struct
|
|
{
|
|
ASN1octet_t *pBuf;
|
|
ASN1uint32_t cbBufSize;
|
|
}
|
|
CER_BLK_BUF;
|
|
|
|
typedef struct
|
|
{
|
|
ASN1blocktype_e eBlkType;
|
|
ASN1encoding_t encPrimary;
|
|
ASN1encoding_t encSecondary;
|
|
ASN1uint32_t nMaxBlkSize;
|
|
ASN1uint32_t nCurrBlkSize;
|
|
CER_BLK_BUF *aBlkBuf;
|
|
}
|
|
CER_BLOCK;
|
|
|
|
#define MAX_INIT_BLK_SIZE 16
|
|
|
|
int ASN1CEREncBeginBlk(ASN1encoding_t enc, ASN1blocktype_e eBlkType, void **ppBlk_)
|
|
{
|
|
CER_BLOCK *pBlk = (CER_BLOCK *) EncMemAlloc(enc, sizeof(CER_BLOCK));
|
|
if (NULL != pBlk)
|
|
{
|
|
EncAssert(enc, ASN1_DER_SET_OF_BLOCK == eBlkType);
|
|
pBlk->eBlkType = eBlkType;
|
|
pBlk->encPrimary = enc;
|
|
pBlk->encSecondary = NULL;
|
|
pBlk->nMaxBlkSize = MAX_INIT_BLK_SIZE;
|
|
pBlk->nCurrBlkSize = 0;
|
|
pBlk->aBlkBuf = (CER_BLK_BUF *)EncMemAlloc(enc, MAX_INIT_BLK_SIZE * sizeof(CER_BLK_BUF));
|
|
if (NULL != pBlk->aBlkBuf)
|
|
{
|
|
*ppBlk_ = (void *) pBlk;
|
|
return 1;
|
|
}
|
|
EncMemFree(enc, pBlk);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ASN1CEREncNewBlkElement(void *pBlk_, ASN1encoding_t *enc2)
|
|
{
|
|
CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_;
|
|
if (NULL == pBlk->encSecondary)
|
|
{
|
|
if (ASN1_SUCCESS == ASN1_CreateEncoder(pBlk->encPrimary->module,
|
|
&(pBlk->encSecondary),
|
|
NULL, 0, pBlk->encPrimary))
|
|
{
|
|
pBlk->encSecondary->eRule = pBlk->encPrimary->eRule;
|
|
*enc2 = pBlk->encSecondary;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASN1INTERNencoding_t e = (ASN1INTERNencoding_t) (*enc2 = pBlk->encSecondary);
|
|
|
|
ZeroMemory(e, sizeof(*e));
|
|
e->info.magic = MAGIC_ENCODER;
|
|
// e->info.err = ASN1_SUCCESS;
|
|
// e->info.pos = e->info.buf = NULL;
|
|
// e->info.size = e->info.len = e->info.bit = 0;
|
|
// e->info.dwFlags = 0;
|
|
e->info.module = pBlk->encPrimary->module;
|
|
e->info.eRule = pBlk->encPrimary->eRule;
|
|
|
|
((ASN1INTERNencoding_t) pBlk->encPrimary)->child = e;
|
|
e->parent = (ASN1INTERNencoding_t) pBlk->encPrimary;
|
|
// e->child = NULL;
|
|
|
|
// e->mem = NULL;
|
|
// e->memlength = 0;
|
|
// e->memsize = 0;
|
|
// e->epi = NULL;
|
|
// e->epilength = 0;
|
|
// e->episize = 0;
|
|
// e->csi = NULL;
|
|
// e->csilength = 0;
|
|
// e->csisize = 0;
|
|
|
|
if (ASN1BEREncCheck((ASN1encoding_t) e, 1))
|
|
{
|
|
// lonchanc: make sure the first byte is zeroed out, which
|
|
// is required for h245.
|
|
e->info.buf[0] = '\0';
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
*enc2 = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int ASN1CEREncFlushBlkElement(void *pBlk_)
|
|
{
|
|
CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_;
|
|
ASN1encoding_t enc = pBlk->encSecondary;
|
|
ASN1uint32_t i;
|
|
|
|
if (ASN1BEREncFlush(enc))
|
|
{
|
|
// make sure we have enough space...
|
|
if (pBlk->nCurrBlkSize >= pBlk->nMaxBlkSize)
|
|
{
|
|
CER_BLK_BUF *aBlkBuf = (CER_BLK_BUF *)EncMemAlloc(pBlk->encPrimary, (pBlk->nMaxBlkSize << 1) * sizeof(CER_BLK_BUF));
|
|
if (NULL != aBlkBuf)
|
|
{
|
|
CopyMemory(aBlkBuf, pBlk->aBlkBuf, pBlk->nMaxBlkSize * sizeof(CER_BLK_BUF));
|
|
EncMemFree(pBlk->encPrimary, pBlk->aBlkBuf);
|
|
pBlk->aBlkBuf = aBlkBuf;
|
|
pBlk->nMaxBlkSize <<= 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (pBlk->encPrimary->eRule & (ASN1_BER_RULE_DER | ASN1_BER_RULE_CER))
|
|
{
|
|
// we need to sort these octet strings
|
|
for (i = 0; i < pBlk->nCurrBlkSize; i++)
|
|
{
|
|
if (0 >= My_memcmp(enc->buf, enc->len, pBlk->aBlkBuf[i].pBuf, pBlk->aBlkBuf[i].cbBufSize))
|
|
{
|
|
ASN1uint32_t cnt = pBlk->nCurrBlkSize - i;
|
|
ASN1uint32_t j;
|
|
for (j = pBlk->nCurrBlkSize; cnt--; j--)
|
|
{
|
|
pBlk->aBlkBuf[j] = pBlk->aBlkBuf[j-1];
|
|
}
|
|
// i is the place to hold the new one
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EncAssert(enc, ASN1_BER_RULE_BER == pBlk->encPrimary->eRule);
|
|
i = pBlk->nCurrBlkSize;
|
|
}
|
|
|
|
// remeber the new one.
|
|
pBlk->aBlkBuf[i].pBuf = enc->buf;
|
|
pBlk->aBlkBuf[i].cbBufSize = enc->len;
|
|
pBlk->nCurrBlkSize++;
|
|
|
|
// clean up the encoder structure
|
|
enc->buf = enc->pos = NULL;
|
|
enc->size = enc->len = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ASN1CEREncEndBlk(void *pBlk_)
|
|
{
|
|
CER_BLOCK *pBlk = (CER_BLOCK *) pBlk_;
|
|
ASN1encoding_t enc = pBlk->encPrimary;
|
|
ASN1uint32_t cbTotalSize = 0;
|
|
ASN1uint32_t i;
|
|
int fRet = 0;
|
|
|
|
// calculate the total size for all the buffers.
|
|
for (i = 0; i < pBlk->nCurrBlkSize; i++)
|
|
{
|
|
cbTotalSize += pBlk->aBlkBuf[i].cbBufSize;
|
|
}
|
|
|
|
if (ASN1BEREncCheck(enc, cbTotalSize))
|
|
{
|
|
for (i = 0; i < pBlk->nCurrBlkSize; i++)
|
|
{
|
|
ASN1uint32_t cbBufSize = pBlk->aBlkBuf[i].cbBufSize;
|
|
CopyMemory(enc->pos, pBlk->aBlkBuf[i].pBuf, cbBufSize);
|
|
enc->pos += cbBufSize;
|
|
}
|
|
fRet = 1;
|
|
}
|
|
|
|
// free these block buffers.
|
|
for (i = 0; i < pBlk->nCurrBlkSize; i++)
|
|
{
|
|
EncMemFree(enc, pBlk->aBlkBuf[i].pBuf);
|
|
}
|
|
|
|
// free the block buffer array
|
|
EncMemFree(enc, pBlk->aBlkBuf);
|
|
|
|
// free the secondary encoder structure
|
|
ASN1_CloseEncoder(pBlk->encSecondary);
|
|
|
|
// free the block structure itself.
|
|
EncMemFree(enc, pBlk);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
#endif // ENABLE_BER
|
|
|
|
/* encode explicit tag */
|
|
int ASN1BEREncExplicitTag(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t *pnLenOff)
|
|
{
|
|
/* encode tag */
|
|
if (ASN1BEREncTag(enc, tag | 0x20000000))
|
|
{
|
|
/* encode infinite length */
|
|
if (ASN1BEREncCheck(enc, 1))
|
|
{
|
|
if (ASN1_BER_RULE_CER != enc->eRule)
|
|
{
|
|
// BER and DER always use definite length form.
|
|
/* return the place to hold the length */
|
|
*pnLenOff = (ASN1uint32_t) (enc->pos++ - enc->buf);
|
|
}
|
|
else
|
|
{
|
|
// CER sub-rule always use indefinite length form.
|
|
*enc->pos++ = 0x80;
|
|
*pnLenOff = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* encode definite length */
|
|
int ASN1BEREncEndOfContents(ASN1encoding_t enc, ASN1uint32_t nLenOff)
|
|
{
|
|
if (ASN1_BER_RULE_CER != enc->eRule)
|
|
{
|
|
ASN1octet_t *pbLen = enc->buf + nLenOff;
|
|
ASN1uint32_t len = (ASN1uint32_t) (enc->pos - pbLen - 1);
|
|
ASN1uint32_t cbLength = _BERGetLength(len, c_LengthTable, ARRAY_SIZE(c_LengthTable));
|
|
|
|
ASN1uint32_t i;
|
|
|
|
if (cbLength == 1)
|
|
{
|
|
*pbLen = (ASN1octet_t) len;
|
|
return 1;
|
|
}
|
|
|
|
// we have to move the octets upward by cbLength-1
|
|
// --cbLength;
|
|
if (ASN1BEREncCheck(enc, cbLength-1))
|
|
{
|
|
// update pbLen because enc->buf may change due to realloc.
|
|
pbLen = enc->buf + nLenOff;
|
|
|
|
// move memory
|
|
MoveMemory(pbLen + cbLength, pbLen + 1, len);
|
|
|
|
// put the length
|
|
enc->pos = pbLen;
|
|
_BERPutLength(enc, len, cbLength);
|
|
EncAssert(enc, enc->pos == pbLen + cbLength);
|
|
|
|
// set up new position pointer.
|
|
// now enc->pos is at the beginning of contents.
|
|
enc->pos += len;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EncAssert(enc, 0 == nLenOff);
|
|
if (ASN1BEREncCheck(enc, 2))
|
|
{
|
|
*enc->pos++ = 0;
|
|
*enc->pos++ = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// The following is for CryptoAPI
|
|
|
|
#ifdef ENABLE_BER
|
|
|
|
#include <stdlib.h>
|
|
|
|
// max num of octets, ceiling of 64 / 7, is 10
|
|
#define MAX_BYTES_PER_NODE 10
|
|
|
|
ASN1uint32_t _BEREncOidNode64(ASN1encoding_t enc, unsigned __int64 n64, ASN1octet_t *pOut)
|
|
{
|
|
ASN1uint32_t Low32, i, cb;
|
|
ASN1octet_t aLittleEndian[MAX_BYTES_PER_NODE];
|
|
|
|
ZeroMemory(aLittleEndian, sizeof(aLittleEndian));
|
|
for (i = 0; n64 != 0; i++)
|
|
{
|
|
Low32 = *(ASN1uint32_t *) &n64;
|
|
aLittleEndian[i] = (ASN1octet_t) (Low32 & 0x7f);
|
|
n64 = Int64ShrlMod32(n64, 7);
|
|
}
|
|
cb = i ? i : 1; // at least one byte for zero value
|
|
EncAssert(enc, cb <= MAX_BYTES_PER_NODE);
|
|
for (i = 0; i < cb; i++)
|
|
{
|
|
EncAssert(enc, 0 == (0x80 & aLittleEndian[cb - i - 1]));
|
|
*pOut++ = (ASN1octet_t) (0x80 | aLittleEndian[cb - i - 1]);
|
|
}
|
|
*(pOut-1) &= 0x7f;
|
|
return cb;
|
|
}
|
|
|
|
int ASN1BERDotVal2Eoid(ASN1encoding_t enc, char *pszDotVal, ASN1encodedOID_t *pOut)
|
|
{
|
|
ASN1uint32_t cNodes, cbMaxSize, cb1, cb2;
|
|
char *psz;
|
|
|
|
// calculate how many nodes, at least 1.
|
|
for (cNodes = 0, psz = pszDotVal; NULL != psz; cNodes++)
|
|
{
|
|
psz = strchr(psz, '.');
|
|
if (psz)
|
|
{
|
|
psz++;
|
|
}
|
|
}
|
|
|
|
// calculate how many bytes should be allocated
|
|
cb1 = My_lstrlenA(pszDotVal);
|
|
cb2 = cNodes * MAX_BYTES_PER_NODE;
|
|
cbMaxSize = (cb1 > cb2) ? cb1 : cb2;
|
|
|
|
// allocate buffer
|
|
pOut->length = 0; // safety net
|
|
pOut->value = (ASN1octet_t *) EncMemAlloc(enc, cbMaxSize);
|
|
if (pOut->value)
|
|
{
|
|
ASN1octet_t *p = pOut->value;
|
|
ASN1uint32_t i;
|
|
unsigned __int64 n64;
|
|
psz = pszDotVal;
|
|
for (i = 0; i < cNodes; i++)
|
|
{
|
|
EncAssert(enc, NULL != psz);
|
|
n64 = (unsigned __int64) _atoi64(psz);
|
|
psz = strchr(psz, '.') + 1;
|
|
if (0 == i && cNodes > 1)
|
|
{
|
|
i++;
|
|
n64 = n64 * 40 + (unsigned __int64) _atoi64(psz);
|
|
psz = strchr(psz, '.') + 1;
|
|
}
|
|
|
|
p += _BEREncOidNode64(enc, n64, p);
|
|
}
|
|
pOut->length = (ASN1uint16_t) (p - pOut->value);
|
|
EncAssert(enc, pOut->length <= cbMaxSize);
|
|
return 1;
|
|
}
|
|
pOut->length = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
ASN1uint32_t _BERDecOidNode64(unsigned __int64 *pn64, ASN1octet_t *pIn)
|
|
{
|
|
ASN1uint32_t c;
|
|
*pn64 = 0;
|
|
for (c = 1; TRUE; c++)
|
|
{
|
|
*pn64 = Int64ShllMod32(*pn64, 7) + (unsigned __int64) (*pIn & 0x7f);
|
|
if (!(*pIn++ & 0x80))
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ASN1BEREoid2DotVal(ASN1decoding_t dec, ASN1encodedOID_t *pIn, char **ppszDotVal)
|
|
{
|
|
ASN1octet_t *p;
|
|
ASN1uint32_t i, cNodes, cb, n32, nLen, nChars;
|
|
unsigned __int64 n64;
|
|
char *psz;
|
|
char szBuf[256+64]; // should be large enough
|
|
|
|
// null out return value
|
|
*ppszDotVal = NULL;
|
|
|
|
if (NULL == dec)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// calculate how many nodes
|
|
cNodes = 0;
|
|
for (p = pIn->value, i = 0; i < pIn->length; p++, i++)
|
|
{
|
|
if (!(*p & 0x80))
|
|
{
|
|
cNodes++;
|
|
}
|
|
}
|
|
|
|
if (cNodes++) // first encoded node consists of two nodes
|
|
{
|
|
// decode nodes one by one
|
|
psz = &szBuf[0];
|
|
// BUG 773871 ESCROW: ETA 2/6: Security issue with Msasn1.dll
|
|
// keep a count of how many characters we write to the psz buffer.
|
|
// if this count exceeds 256, then we have a buffer overrun.
|
|
// note that we've padded our buffer with an extra 64 bytes, which
|
|
// allows us to detect the overrun safely. The below code can't
|
|
// overrun our buffer by more than ~22 bytes.
|
|
nChars = 0;
|
|
p = pIn->value;
|
|
for (i = 0; i < cNodes; i++)
|
|
{
|
|
p += _BERDecOidNode64(&n64, p);
|
|
if (!i)
|
|
{ // first node
|
|
n32 = (ASN1uint32_t) (n64 / 40);
|
|
if (n32 > 2)
|
|
{
|
|
n32 = 2;
|
|
}
|
|
n64 -= (unsigned __int64) (40 * n32);
|
|
i++; // first encoded node actually consists of two nodes
|
|
_ultoa(n32, psz, 10);
|
|
nLen = lstrlenA(psz);
|
|
psz += nLen;
|
|
*psz++ = '.';
|
|
nChars += nLen+1;
|
|
}
|
|
_ui64toa(n64, psz, 10);
|
|
nLen = lstrlenA(psz);
|
|
psz += nLen;
|
|
*psz++ = '.';
|
|
nChars += nLen+1;
|
|
|
|
if (nChars > 256)
|
|
{
|
|
// This oid is too long for our buffer. Bail out now.
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
return 0;
|
|
}
|
|
}
|
|
DecAssert(dec, psz > &szBuf[0]);
|
|
*(psz-1) = '\0';
|
|
|
|
// duplicate the string
|
|
cb = (ASN1uint32_t) (psz - &szBuf[0]);
|
|
*ppszDotVal = (char *) DecMemAlloc(dec, cb);
|
|
if (*ppszDotVal)
|
|
{
|
|
CopyMemory(*ppszDotVal, &szBuf[0], cb);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* encode an object identifier value */
|
|
int ASN1BEREncEoid(ASN1encoding_t enc, ASN1uint32_t tag, ASN1encodedOID_t *val)
|
|
{
|
|
/* encode tag */
|
|
if (ASN1BEREncTag(enc, tag))
|
|
{
|
|
/* encode length */
|
|
int rc = ASN1BEREncLength(enc, val->length);
|
|
if (rc)
|
|
{
|
|
/* copy value */
|
|
CopyMemory(enc->pos, val->value, val->length);
|
|
enc->pos += val->length;
|
|
}
|
|
return rc;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode object identifier value */
|
|
int ASN1BERDecEoid(ASN1decoding_t dec, ASN1uint32_t tag, ASN1encodedOID_t *val)
|
|
{
|
|
val->length = 0; // safety net
|
|
if (ASN1BERDecTag(dec, tag, NULL))
|
|
{
|
|
ASN1uint32_t len;
|
|
if (ASN1BERDecLength(dec, &len, NULL))
|
|
{
|
|
val->length = (ASN1uint16_t) len;
|
|
if (len)
|
|
{
|
|
val->value = (ASN1octet_t *) DecMemAlloc(dec, len);
|
|
if (val->value)
|
|
{
|
|
CopyMemory(val->value, dec->pos, len);
|
|
dec->pos += len;
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
val->value = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void ASN1BEREoid_free(ASN1encodedOID_t *val)
|
|
{
|
|
if (val)
|
|
{
|
|
MemFree(val->value);
|
|
}
|
|
}
|
|
|
|
|
|
#endif // ENABLE_BER
|
|
|