mirror of https://github.com/tongzx/nt5src
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.
2632 lines
75 KiB
2632 lines
75 KiB
/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
|
|
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */
|
|
|
|
// lonchanc: things to optimize
|
|
// (1) merge ASN1PERDecCharString() and ASN1PERDecZeroCharString().
|
|
// (2) merge ASN1PERDecChar16String() and ASN1PERDecZeroChar16String().
|
|
// (3) merge ASN1PERDecChar32String() and ASN1PERDecZeroChar32String().
|
|
// (4) merge ASN1PERDecTableCharString() and ASN1PERDecZeroTableCharString().
|
|
// (5) merge ASN1PERDecTableChar16String() and ASN1PERDecZeroTableChar16String().
|
|
// (6) merge ASN1PERDecTableChar32String() and ASN1PERDecZeroTableChar32String().
|
|
// (7) merge ASN1PERDecFragmentedCharString() and ASN1PERDecFragmentedZeroCharString().
|
|
// (8) merge ASN1PERDecFragmentedChar16String() and ASN1PERDecFragmentedZeroChar16String().
|
|
// (9) merge ASN1PERDecFragmentedChar32String() and ASN1PERDecFragmentedZeroChar32String().
|
|
// (10) merge ASN1PERDecFragmentedTableCharString() and ASN1PERDecFragmentedZeroTableCharString().
|
|
// (11) merge ASN1PERDecFragmentedTableChar16String() and ASN1PERDecFragmentedZeroTableChar16String().
|
|
// (12) merge ASN1PERDecFragmentedTableChar32String() and ASN1PERDecFragmentedZeroTableChar32String().
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <math.h>
|
|
#include "cintern.h"
|
|
|
|
void PerDecAdvance(ASN1decoding_t dec, ASN1uint32_t nbits)
|
|
{
|
|
dec->pos += ((dec->bit + nbits) >> 3);
|
|
dec->bit = (dec->bit + nbits) & 7;
|
|
}
|
|
|
|
static const ASN1uint8_t c_aBitMask3[] =
|
|
{
|
|
0x00, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80
|
|
};
|
|
|
|
/* check if sufficient data is in decoding buffer */
|
|
int ASN1PERDecCheck(ASN1decoding_t dec, ASN1uint32_t nbits)
|
|
{
|
|
if ((dec->pos - dec->buf) * 8 + dec->bit + nbits <= dec->size * 8)
|
|
{
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_EOD);
|
|
return 0;
|
|
}
|
|
|
|
/* compare function for binary search in stringtable */
|
|
static int __cdecl ASN1CmpStringTableEntriesByIndex(const void *a1, const void *a2)
|
|
{
|
|
ASN1stringtableentry_t *c1 = (ASN1stringtableentry_t *)a1;
|
|
ASN1stringtableentry_t *c2 = (ASN1stringtableentry_t *)a2;
|
|
|
|
if (c1->value > c2->value + (c2->upper - c2->lower))
|
|
return 1;
|
|
if (c2->value > c1->value + (c1->upper - c1->lower))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/* skip nbits bits */
|
|
int ASN1PERDecSkipBits(ASN1decoding_t dec, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
/* check if enough bits present */
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
/* skip bits */
|
|
n = dec->bit + nbits;
|
|
dec->pos += n / 8;
|
|
dec->bit = n & 7;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* skip a fragmented value */
|
|
int ASN1PERDecSkipFragmented(ASN1decoding_t dec, ASN1uint32_t itemsize)
|
|
{
|
|
ASN1uint32_t n, m;
|
|
|
|
/* skip a fragments one by one */
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
m = n * itemsize;
|
|
if (ASN1PERDecCheck(dec, m))
|
|
{
|
|
dec->pos += m / 8;
|
|
dec->bit = m & 7;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
return 1;
|
|
}
|
|
|
|
/* decode one bit */
|
|
int ASN1PERDecBit(ASN1decoding_t dec, ASN1uint32_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, 1))
|
|
{
|
|
*val = (*dec->pos >> (7 - dec->bit)) & 1;
|
|
if (dec->bit < 7)
|
|
{
|
|
dec->bit++;
|
|
}
|
|
else
|
|
{
|
|
dec->bit = 0;
|
|
dec->pos++;
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode unsigned 32 bit integer value */
|
|
int ASN1PERDecU32Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1uint32_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 32)
|
|
{
|
|
*val = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode unsigned 16 bit integer value */
|
|
int ASN1PERDecU16Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1uint16_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 16)
|
|
{
|
|
*val = (ASN1uint16_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode unsigned 8 bit integer value */
|
|
int ASN1PERDecU8Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1uint8_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 8)
|
|
{
|
|
*val = (ASN1uint8_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode unsigned intx_t integer value */
|
|
int ASN1PERDecUXVal(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1intx_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
val->length = (*dec->pos & (0x80 >> dec->bit)) ? (nbits + 7) / 8 : (nbits + 7 + 1) / 8;
|
|
if (NULL != (val->value = (ASN1octet_t *)DecMemAlloc(dec, val->length)))
|
|
{
|
|
val->value[0] = 0;
|
|
ASN1bitcpy(val->value, val->length * 8 - nbits, dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode signed 32 bit integer value */
|
|
int ASN1PERDecS32Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1int32_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 32)
|
|
{
|
|
*val = ASN1bitget(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode signed 16 bit value */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecS16Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1int16_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 16)
|
|
{
|
|
*val = (ASN1int16_t) ASN1bitget(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode signed 8 bit value */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecS8Val(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1int8_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
if (nbits <= 8)
|
|
{
|
|
*val = (ASN1int8_t) ASN1bitget(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode signed intx_t value */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecSXVal(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1intx_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
val->length = (nbits + 7) / 8;
|
|
if (NULL != (val->value = (ASN1octet_t *)DecMemAlloc(dec, val->length)))
|
|
{
|
|
val->value[0] = (*dec->pos & (0x80 >> dec->bit)) ? c_aBitMask3[nbits & 7] : 0;
|
|
ASN1bitcpy(val->value, val->length * 8 - nbits, dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode length of a fragment */
|
|
int ASN1PERDecFragmentedLength(ASN1decoding_t dec, ASN1uint32_t *nitems)
|
|
{
|
|
ASN1PERDecAlignment(dec);
|
|
|
|
if (ASN1PERDecCheck(dec, 8))
|
|
{
|
|
ASN1uint32_t n = *dec->pos++;
|
|
if (n < 0x80)
|
|
{
|
|
*nitems = n;
|
|
}
|
|
else
|
|
if (n < 0xc0)
|
|
{
|
|
if (ASN1PERDecCheck(dec, 8))
|
|
{
|
|
*nitems = ((n & 0x3f) << 8) | *dec->pos++;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*nitems = 0x4000 * (n & 0x3f);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode a fragment */
|
|
int ASN1PERDecFragmented(ASN1decoding_t dec, ASN1uint32_t *nitems, ASN1octet_t **val, ASN1uint32_t itemsize)
|
|
{
|
|
ASN1uint32_t n, m, l;
|
|
*nitems = 0;
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
l = n * itemsize;
|
|
if (ASN1PERDecCheck(dec, l))
|
|
{
|
|
*nitems += n;
|
|
if (NULL != (*val = (ASN1octet_t *)DecMemReAlloc(dec, *val, (m + l + 7) / 8)))
|
|
{
|
|
ASN1bitcpy(*val, m, dec->pos, dec->bit, l);
|
|
PerDecAdvance(dec, l);
|
|
m += l;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
return 1;
|
|
}
|
|
|
|
/* end of decoding */
|
|
int ASN1PERDecFlush(ASN1decoding_t dec)
|
|
{
|
|
/* complete broken byte */
|
|
ASN1PERDecAlignment(dec);
|
|
|
|
/* get zero-octet if encoding is empty bitstring */
|
|
if (dec->buf == dec->pos)
|
|
{
|
|
if (ASN1PERDecCheck(dec, 8))
|
|
{
|
|
if (*dec->pos == 0)
|
|
{
|
|
dec->pos++;
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* calculate length */
|
|
dec->len = (ASN1uint32_t) (dec->pos - dec->buf);
|
|
|
|
/* set WRN_NOEOD if data left */
|
|
if (dec->len >= dec->size)
|
|
{
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_WRN_NOEOD);
|
|
return 1;
|
|
}
|
|
|
|
/* skip up to octet boundary */
|
|
void ASN1PERDecAlignment(ASN1decoding_t dec)
|
|
{
|
|
if (dec->bit)
|
|
{
|
|
dec->bit = 0;
|
|
dec->pos++;
|
|
}
|
|
}
|
|
|
|
/* decode normally small 32 bit integer */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecN32Val(ASN1decoding_t dec, ASN1uint32_t *val)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
/* is normally small really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (!n)
|
|
{
|
|
return ASN1PERDecU32Val(dec, 6, val);
|
|
}
|
|
|
|
/* large */
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (n <= 4)
|
|
{
|
|
if (n)
|
|
{
|
|
if (ASN1PERDecCheck(dec, n * 8))
|
|
{
|
|
*val = ASN1octetget(dec->pos, n);
|
|
dec->pos += n;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode normally small 16 bit integer */
|
|
int ASN1PERDecN16Val(ASN1decoding_t dec, ASN1uint16_t *val)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
/* is normally small really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (!n)
|
|
{
|
|
return ASN1PERDecU16Val(dec, 6, val);
|
|
}
|
|
|
|
/* large */
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (n <= 2)
|
|
{
|
|
if (n)
|
|
{
|
|
if (ASN1PERDecCheck(dec, n * 8))
|
|
{
|
|
*val = (ASN1uint16_t) ASN1octetget(dec->pos, n);
|
|
dec->pos += n;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode normally small 8 bit integer */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecN8Val(ASN1decoding_t dec, ASN1uint8_t *val)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
/* is normally small really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (!n)
|
|
{
|
|
return ASN1PERDecU8Val(dec, 6, val);
|
|
}
|
|
|
|
/* large */
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (n)
|
|
{
|
|
if (n <= 1)
|
|
{
|
|
if (ASN1PERDecCheck(dec, n * 8))
|
|
{
|
|
*val = (ASN1uint8_t) ASN1octetget(dec->pos, n);
|
|
dec->pos += n;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* skip normally small integer */
|
|
int ASN1PERDecSkipNormallySmall(ASN1decoding_t dec)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
/* is normally small really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (!n)
|
|
{
|
|
return ASN1PERDecSkipBits(dec, 6);
|
|
}
|
|
|
|
/* large */
|
|
return ASN1PERDecSkipFragmented(dec, 8);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode extension bits with normally small length */
|
|
int ASN1PERDecNormallySmallExtension(ASN1decoding_t dec, ASN1uint32_t *nextensions, ASN1uint32_t nbits, ASN1octet_t *val)
|
|
{
|
|
ASN1uint32_t n, m;
|
|
|
|
*nextensions = 0;
|
|
memset(val, 0, (nbits + 7) / 8);
|
|
|
|
/* is normally small length really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (n)
|
|
{
|
|
/* no, get extension bits as fragments */
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n))
|
|
{
|
|
if (n <= nbits)
|
|
{
|
|
ASN1bitcpy(val, m, dec->pos, 0, n);
|
|
m += n;
|
|
nbits -= n;
|
|
}
|
|
else
|
|
if (nbits)
|
|
{
|
|
ASN1bitcpy(val, m, dec->pos, 0, nbits);
|
|
*nextensions += ASN1bitcount(dec->pos, nbits, n - nbits);
|
|
nbits = 0;
|
|
}
|
|
else
|
|
{
|
|
*nextensions += ASN1bitcount(dec->pos, 0, n);
|
|
}
|
|
PerDecAdvance(dec, n);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
return 1;
|
|
}
|
|
|
|
/* yes, get length of extension bit string */
|
|
if (ASN1PERDecU32Val(dec, 6, &n))
|
|
{
|
|
n++;
|
|
|
|
/* copy extension bits */
|
|
if (ASN1PERDecCheck(dec, n))
|
|
{
|
|
if (n <= nbits)
|
|
{
|
|
ASN1bitcpy(val, 0, dec->pos, dec->bit, n);
|
|
}
|
|
else
|
|
{
|
|
ASN1bitcpy(val, 0, dec->pos, dec->bit, nbits);
|
|
*nextensions = ASN1bitcount(dec->pos, dec->bit + nbits, n - nbits);
|
|
}
|
|
PerDecAdvance(dec, n);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* skip extension bits with normally small length */
|
|
int ASN1PERDecSkipNormallySmallExtension(ASN1decoding_t dec, ASN1uint32_t *nextensions)
|
|
{
|
|
ASN1uint32_t n;
|
|
|
|
*nextensions = 0;
|
|
|
|
/* is normally small length really small? */
|
|
if (ASN1PERDecBit(dec, &n))
|
|
{
|
|
if (n)
|
|
{
|
|
/* no, get extension bits as fragments */
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n))
|
|
{
|
|
*nextensions += ASN1bitcount(dec->pos, 0, n);
|
|
PerDecAdvance(dec, n);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
return 1;
|
|
}
|
|
|
|
/* yes, get length of extension bit string */
|
|
if (ASN1PERDecU32Val(dec, 6, &n))
|
|
{
|
|
n++;
|
|
if (ASN1PERDecCheck(dec, n))
|
|
{
|
|
*nextensions = ASN1bitcount(dec->pos, dec->bit, n);
|
|
PerDecAdvance(dec, n);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode bit string of optionals of sequence/set */
|
|
// lonchanc: decode octet string with length constraint.
|
|
int ASN1PERDecExtension(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1octet_t *val)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
ASN1bitcpy(val, 0, dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode bit string */
|
|
int ASN1PERDecBits(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1octet_t **val)
|
|
{
|
|
if (NULL != (*val = (ASN1octet_t *)DecMemAlloc(dec, (nbits + 7) / 8)))
|
|
{
|
|
if (ASN1PERDecCheck(dec, nbits))
|
|
{
|
|
ASN1bitcpy(*val, 0, dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode real value */
|
|
int ASN1PERDecDouble(ASN1decoding_t dec, double *val)
|
|
{
|
|
ASN1uint32_t head;
|
|
ASN1int32_t exponent;
|
|
ASN1uint32_t baselog2;
|
|
ASN1uint32_t len;
|
|
ASN1uint32_t i;
|
|
ASN1octet_t *p, *q;
|
|
double v;
|
|
char buf[256], *b;
|
|
|
|
if (ASN1PERDecFragmentedLength(dec, &len))
|
|
{
|
|
if (len < 0x4000)
|
|
{
|
|
if (len)
|
|
{
|
|
p = q = dec->pos;
|
|
dec->pos += len;
|
|
head = *p++;
|
|
|
|
/* binary encoding? */
|
|
if (head & 0x80)
|
|
{
|
|
/* get base */
|
|
switch (head & 0x30)
|
|
{
|
|
case 0:
|
|
/* base 2 */
|
|
baselog2 = 1;
|
|
break;
|
|
case 0x10:
|
|
/* base 8 */
|
|
baselog2 = 3;
|
|
break;
|
|
case 0x20:
|
|
/* base 16 */
|
|
baselog2 = 4;
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* get exponent */
|
|
switch (head & 0x03)
|
|
{
|
|
case 0:
|
|
/* 8 bit exponent */
|
|
exponent = (ASN1int8_t)*p++;
|
|
break;
|
|
case 1:
|
|
/* 16 bit exponent */
|
|
exponent = (ASN1int16_t)((*p << 8) | p[1]);
|
|
p += 2;
|
|
break;
|
|
case 2:
|
|
/* 24 bit exponent */
|
|
exponent = ((*p << 16) | (p[1] << 8) | p[2]);
|
|
if (exponent & 0x800000)
|
|
exponent -= 0x1000000;
|
|
break;
|
|
default:
|
|
/* variable length exponent */
|
|
exponent = (p[1] & 0x80) ? -1 : 0;
|
|
for (i = 1; i <= *p; i++)
|
|
exponent = (exponent << 8) | p[i];
|
|
p += *p + 1;
|
|
break;
|
|
}
|
|
|
|
/* calculate remaining length */
|
|
len -= (ASN1uint32_t) (p - q);
|
|
|
|
/* get mantissa */
|
|
v = 0.0;
|
|
for (i = 0; i < len; i++)
|
|
v = v * 256.0 + *p++;
|
|
|
|
/* scale mantissa */
|
|
switch (head & 0x0c)
|
|
{
|
|
case 0x04:
|
|
/* scaling factor 1 */
|
|
v *= 2.0;
|
|
break;
|
|
case 0x08:
|
|
/* scaling factor 2 */
|
|
v *= 4.0;
|
|
break;
|
|
case 0x0c:
|
|
/* scaling factor 3 */
|
|
v *= 8.0;
|
|
break;
|
|
}
|
|
|
|
/* check sign */
|
|
if (head & 0x40)
|
|
v = -v;
|
|
|
|
/* calculate value */
|
|
*val = ldexp(v, exponent * baselog2);
|
|
|
|
/* special real values? */
|
|
}
|
|
else
|
|
if (head & 0x40)
|
|
{
|
|
switch (head)
|
|
{
|
|
case 0x40:
|
|
/* PLUS-INFINITY */
|
|
*val = ASN1double_pinf();
|
|
break;
|
|
case 0x41:
|
|
/* MINUS-INFINITY */
|
|
*val = ASN1double_minf();
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* decimal encoding */
|
|
}
|
|
else
|
|
{
|
|
CopyMemory(buf, p, len - 1);
|
|
buf[len - 1] = 0;
|
|
b = strchr(buf, ',');
|
|
if (b)
|
|
*b = '.';
|
|
*val = strtod((char *)buf, &b);
|
|
if (*b)
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*val = 0.0;
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode external value */
|
|
#ifdef ENABLE_EXTERNAL
|
|
int ASN1PERDecExternal(ASN1decoding_t dec, ASN1external_t *val)
|
|
{
|
|
ASN1uint32_t l, u;
|
|
|
|
/* get optional bits */
|
|
if (ASN1PERDecU32Val(dec, 3, &u))
|
|
{
|
|
/* get identification */
|
|
switch (u & 6)
|
|
{
|
|
case 4:
|
|
val->identification.o = ASN1external_identification_syntax_o;
|
|
if (!ASN1PERDecObjectIdentifier(dec, &val->identification.u.syntax))
|
|
return 0;
|
|
break;
|
|
case 2:
|
|
val->identification.o =
|
|
ASN1external_identification_presentation_context_id_o;
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8,
|
|
&val->identification.u.presentation_context_id))
|
|
return 0;
|
|
break;
|
|
case 6:
|
|
val->identification.o =
|
|
ASN1external_identification_context_negotiation_o;
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.context_negotiation.transfer_syntax))
|
|
return 0;
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8,
|
|
&val->identification.u.context_negotiation.presentation_context_id))
|
|
return 0;
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* get value descriptor */
|
|
val->o[0] = (ASN1octet_t) ((u & 1) << 7);
|
|
if (u & 1)
|
|
{
|
|
if (!ASN1PERDecFragmentedZeroCharString(dec, &val->data_value_descriptor, 8))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
val->data_value_descriptor = NULL;
|
|
}
|
|
|
|
/* get value */
|
|
if (ASN1PERDecU32Val(dec, 2, &u))
|
|
{
|
|
switch (u)
|
|
{
|
|
case 0:
|
|
val->data_value.o = ASN1external_data_value_notation_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.notation.length,
|
|
(ASN1octet_t **) &val->data_value.u.notation.encoded, 8);
|
|
break;
|
|
case 1:
|
|
val->data_value.o = ASN1external_data_value_encoded_o;
|
|
if (ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 8))
|
|
{
|
|
val->data_value.u.encoded.length *= 8;
|
|
return 1;
|
|
}
|
|
break;
|
|
case 2:
|
|
val->data_value.o = ASN1external_data_value_encoded_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 1);
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_EXTERNAL
|
|
|
|
/* decode an embedded pdv value */
|
|
#ifdef ENABLE_EMBEDDED_PDV
|
|
int ASN1PERDecEmbeddedPdv(ASN1decoding_t dec, ASN1embeddedpdv_t *val)
|
|
{
|
|
ASN1uint32_t flag;
|
|
ASN1uint32_t index;
|
|
ASN1uint32_t l;
|
|
ASN1embeddedpdv_identification_t *identification;
|
|
|
|
/* get EP-A/EP-B encoding bit */
|
|
if (!ASN1PERDecBit(dec, &flag))
|
|
return 0;
|
|
|
|
/* get index value */
|
|
if (!ASN1PERDecN32Val(dec, &index))
|
|
return 0;
|
|
|
|
if (flag)
|
|
{
|
|
/* EP-A encoding */
|
|
|
|
/* get identification */
|
|
if (!ASN1PERDecU8Val(dec, 3, &val->identification.o))
|
|
return 0;
|
|
switch (val->identification.o)
|
|
{
|
|
case ASN1embeddedpdv_identification_syntaxes_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract))
|
|
return 0;
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_syntax_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_presentation_context_id_o:
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8,
|
|
&val->identification.u.presentation_context_id))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_context_negotiation_o:
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8, &val->
|
|
identification.u.context_negotiation.presentation_context_id))
|
|
return 0;
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.context_negotiation.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_transfer_syntax_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_fixed_o:
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* save identification */
|
|
if (!ASN1DecAddEmbeddedPdvIdentification(((ASN1INTERNdecoding_t) dec)->parent,
|
|
&val->identification))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* EP-B encoding */
|
|
|
|
/* get identification */
|
|
identification = ASN1DecGetEmbeddedPdvIdentification(((ASN1INTERNdecoding_t) dec)->parent, index);
|
|
if (!identification)
|
|
return 0;
|
|
val->identification.o = identification->o;
|
|
switch (identification->o)
|
|
{
|
|
case ASN1embeddedpdv_identification_syntaxes_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract,
|
|
&identification->u.syntaxes.abstract))
|
|
return 0;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer,
|
|
&identification->u.syntaxes.transfer))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_syntax_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntax,
|
|
&identification->u.syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_presentation_context_id_o:
|
|
val->identification.u.presentation_context_id =
|
|
identification->u.presentation_context_id;
|
|
break;
|
|
case ASN1embeddedpdv_identification_context_negotiation_o:
|
|
val->identification.u.context_negotiation.presentation_context_id =
|
|
identification->u.context_negotiation.presentation_context_id;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.context_negotiation.transfer_syntax,
|
|
&identification->u.context_negotiation.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_transfer_syntax_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.transfer_syntax,
|
|
&identification->u.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1embeddedpdv_identification_fixed_o:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* get value */
|
|
ASN1PERDecAlignment(dec);
|
|
val->data_value.o = ASN1embeddedpdv_data_value_encoded_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 1);
|
|
}
|
|
#endif // ENABLE_EMBEDDED_PDV
|
|
|
|
/* decode an optimized embedded pdv value */
|
|
#ifdef ENABLE_EMBEDDED_PDV
|
|
int ASN1PERDecEmbeddedPdvOpt(ASN1decoding_t dec, ASN1embeddedpdv_t *val, ASN1objectidentifier_t *abstract, ASN1objectidentifier_t *transfer)
|
|
{
|
|
/* set identification */
|
|
if (abstract && transfer)
|
|
{
|
|
val->identification.o = ASN1embeddedpdv_identification_syntaxes_o;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract, abstract))
|
|
return 0;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer, transfer))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
val->identification.o = ASN1embeddedpdv_identification_fixed_o;
|
|
}
|
|
|
|
/* get value */
|
|
val->data_value.o = ASN1embeddedpdv_data_value_encoded_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 1);
|
|
}
|
|
#endif // ENABLE_EMBEDDED_PDV
|
|
|
|
/* decode character string */
|
|
#ifdef ENABLE_GENERALIZED_CHAR_STR
|
|
int ASN1PERDecCharacterString(ASN1decoding_t dec, ASN1characterstring_t *val)
|
|
{
|
|
ASN1uint32_t flag;
|
|
ASN1uint32_t index;
|
|
ASN1uint32_t l;
|
|
ASN1characterstring_identification_t *identification;
|
|
|
|
/* get CS-A/CS-B encoding bit */
|
|
if (!ASN1PERDecBit(dec, &flag))
|
|
return 0;
|
|
|
|
/* get index value */
|
|
if (!ASN1PERDecN32Val(dec, &index))
|
|
return 0;
|
|
|
|
if (flag)
|
|
{
|
|
/* CS-A encoding */
|
|
|
|
/* get identification */
|
|
if (!ASN1PERDecU8Val(dec, 3, &val->identification.o))
|
|
return 0;
|
|
switch (val->identification.o)
|
|
{
|
|
case ASN1characterstring_identification_syntaxes_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract))
|
|
return 0;
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_syntax_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_presentation_context_id_o:
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8,
|
|
&val->identification.u.presentation_context_id))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_context_negotiation_o:
|
|
if (!ASN1PERDecFragmentedLength(dec, &l))
|
|
return 0;
|
|
if (!ASN1PERDecU32Val(dec, l * 8, &val->
|
|
identification.u.context_negotiation.presentation_context_id))
|
|
return 0;
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.context_negotiation.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_transfer_syntax_o:
|
|
if (!ASN1PERDecObjectIdentifier(dec,
|
|
&val->identification.u.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_fixed_o:
|
|
break;
|
|
default:
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
|
|
/* save identification */
|
|
if (!ASN1DecAddCharacterStringIdentification((ASN1INTERNdecoding_t) dec, &val->identification))
|
|
return 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
/* CS-B encoding */
|
|
|
|
/* get identification */
|
|
identification = ASN1DecGetCharacterStringIdentification((ASN1INTERNdecoding_t) dec, index);
|
|
if (!identification)
|
|
return 0;
|
|
val->identification.o = identification->o;
|
|
switch (identification->o)
|
|
{
|
|
case ASN1characterstring_identification_syntaxes_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract,
|
|
&identification->u.syntaxes.abstract))
|
|
return 0;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer,
|
|
&identification->u.syntaxes.transfer))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_syntax_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntax,
|
|
&identification->u.syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_presentation_context_id_o:
|
|
val->identification.u.presentation_context_id =
|
|
identification->u.presentation_context_id;
|
|
break;
|
|
case ASN1characterstring_identification_context_negotiation_o:
|
|
val->identification.u.context_negotiation.presentation_context_id =
|
|
identification->u.context_negotiation.presentation_context_id;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.context_negotiation.transfer_syntax,
|
|
&identification->u.context_negotiation.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_transfer_syntax_o:
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.transfer_syntax,
|
|
&identification->u.transfer_syntax))
|
|
return 0;
|
|
break;
|
|
case ASN1characterstring_identification_fixed_o:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* get value */
|
|
ASN1PERDecAlignment(dec);
|
|
val->data_value.o = ASN1characterstring_data_value_encoded_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 8);
|
|
}
|
|
#endif // ENABLE_GENERALIZED_CHAR_STR
|
|
|
|
/* decode an optimized character string value */
|
|
#ifdef ENABLE_GENERALIZED_CHAR_STR
|
|
int ASN1PERDecCharacterStringOpt(ASN1decoding_t dec, ASN1characterstring_t *val, ASN1objectidentifier_t *abstract, ASN1objectidentifier_t *transfer)
|
|
{
|
|
/* set identification */
|
|
if (abstract && transfer)
|
|
{
|
|
val->identification.o = ASN1characterstring_identification_syntaxes_o;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.abstract, abstract))
|
|
return 0;
|
|
if (!ASN1DecDupObjectIdentifier(dec,
|
|
&val->identification.u.syntaxes.transfer, transfer))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
val->identification.o = ASN1characterstring_identification_fixed_o;
|
|
}
|
|
|
|
/* get value */
|
|
val->data_value.o = ASN1characterstring_data_value_encoded_o;
|
|
return ASN1PERDecFragmented(dec,
|
|
&val->data_value.u.encoded.length,
|
|
&val->data_value.u.encoded.value, 8);
|
|
}
|
|
#endif // ENABLE_GENERALIZED_CHAR_STR
|
|
|
|
/* decode a multibyte string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecMultibyteString(ASN1decoding_t dec, ASN1char_t **val)
|
|
{
|
|
return ASN1PERDecFragmentedZeroCharString(dec, val, 8);
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a string */
|
|
int ASN1PERDecCharStringNoAlloc(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char_t *p = val;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
if (nbits == 8)
|
|
{
|
|
ASN1bitcpy((ASN1octet_t *)p, 0, dec->pos, dec->bit, nchars * 8);
|
|
PerDecAdvance(dec, nchars * 8);
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = (ASN1char_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecCharString(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t **val, ASN1uint32_t nbits)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, nchars);
|
|
return ((*val) ? ASN1PERDecCharStringNoAlloc(dec, nchars, *val, nbits) : 0);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a 16 bit string */
|
|
int ASN1PERDecChar16String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char16_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char16_t *p;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
p = *val = (ASN1char16_t *)DecMemAlloc(dec, nchars * sizeof(ASN1char16_t));
|
|
if (p)
|
|
{
|
|
if (!dec->bit && nbits == 16)
|
|
{
|
|
while (nchars--)
|
|
{
|
|
*p++ = (dec->pos[0] << 8) | dec->pos[1];
|
|
dec->pos += 2;
|
|
}
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = (ASN1char16_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode a 32 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecChar32String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char32_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char32_t *p;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
p = *val = (ASN1char32_t *)DecMemAlloc(dec, nchars * sizeof(ASN1char32_t));
|
|
if (p)
|
|
{
|
|
if (!dec->bit && nbits == 32)
|
|
{
|
|
while (nchars--)
|
|
{
|
|
*p++ = (dec->pos[0] << 24) | (dec->pos[1] << 16) |
|
|
(dec->pos[2] << 8) | dec->pos[3];
|
|
dec->pos += 4;
|
|
}
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated string */
|
|
int ASN1PERDecZeroCharStringNoAlloc(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char_t *p = val;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
if (nbits == 8)
|
|
{
|
|
ASN1bitcpy((ASN1octet_t *)p, 0, dec->pos, dec->bit, nchars * 8);
|
|
PerDecAdvance(dec, nchars * 8);
|
|
p[nchars] = 0;
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = (ASN1char_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroCharString(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t **val, ASN1uint32_t nbits)
|
|
{
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, nchars + 1);
|
|
return ((*val) ? ASN1PERDecZeroCharStringNoAlloc(dec, nchars, *val, nbits) : 0);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated 16 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroChar16String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char16_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char16_t *p;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
p = *val = (ASN1char16_t *)DecMemAlloc(dec, (nchars + 1) * sizeof(ASN1char16_t));
|
|
if (p)
|
|
{
|
|
if (!dec->bit && nbits == 16)
|
|
{
|
|
while (nchars--)
|
|
{
|
|
*p++ = (dec->pos[0] << 8) | dec->pos[1];
|
|
dec->pos += 2;
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = (ASN1char16_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated 32 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroChar32String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char32_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1char32_t *p;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
p = *val = (ASN1char32_t *)DecMemAlloc(dec, (nchars + 1) * sizeof(ASN1char32_t));
|
|
if (p)
|
|
{
|
|
if (!dec->bit && nbits == 32)
|
|
{
|
|
while (nchars--)
|
|
{
|
|
*p++ = (dec->pos[0] << 24) | (dec->pos[1] << 16) |
|
|
(dec->pos[2] << 8) | dec->pos[3];
|
|
dec->pos += 4;
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
while (nchars--)
|
|
{
|
|
*p++ = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecTableCharStringNoAlloc(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char_t *p = val;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecTableCharString(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, nchars);
|
|
return ((*val) ? ASN1PERDecTableCharStringNoAlloc(dec, nchars, *val, nbits, table) : 0);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a 16 bit table string */
|
|
int ASN1PERDecTableChar16String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char16_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char16_t *p;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
*val = p = (ASN1char16_t *)DecMemAlloc(dec, nchars * sizeof(ASN1char16_t));
|
|
if (p)
|
|
{
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char16_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode a 32 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecTableChar32String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char32_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char32_t *p;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
if (ASN1PERDecCheck(dec, nchars * nbits))
|
|
{
|
|
*val = p = (ASN1char32_t *)DecMemAlloc(dec, nchars * sizeof(ASN1char32_t));
|
|
if (p)
|
|
{
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = entry->lower + (chr.value - entry->value);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated table string */
|
|
int ASN1PERDecZeroTableCharStringNoAlloc(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char_t *p = val;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
if (ASN1PERDecU32Val(dec, nbits, &chr.value))
|
|
{
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
|
|
/* decode a zero-terminated table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroTableCharString(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char_t *p;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, nchars + 1);
|
|
return ((*val) ? ASN1PERDecZeroTableCharStringNoAlloc(dec, nchars, *val, nbits, table) : 0);
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated 16 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroTableChar16String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char16_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char16_t *p;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
*val = p = (ASN1char16_t *)DecMemAlloc(dec, (nchars + 1) * sizeof(ASN1char16_t));
|
|
if (p)
|
|
{
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
if (ASN1PERDecU32Val(dec, nbits, &chr.value))
|
|
{
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char16_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a zero-terminated 32 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecZeroTableChar32String(ASN1decoding_t dec, ASN1uint32_t nchars, ASN1char32_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1char32_t *p;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
|
|
*val = p = (ASN1char32_t *)DecMemAlloc(dec, (nchars + 1) * sizeof(ASN1char32_t));
|
|
if (p)
|
|
{
|
|
chr.lower = chr.upper = 0;
|
|
while (nchars--)
|
|
{
|
|
if (ASN1PERDecU32Val(dec, nbits, &chr.value))
|
|
{
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = entry->lower + (chr.value - entry->value);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
*p = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode an object identifier */
|
|
int ASN1PERDecObjectIdentifier(ASN1decoding_t dec, ASN1objectidentifier_t *val)
|
|
{
|
|
ASN1uint32_t len, i, v;
|
|
ASN1octet_t *data, *p;
|
|
ASN1uint32_t nelem;
|
|
ASN1objectidentifier_t q;
|
|
|
|
if (ASN1PERDecFragmented(dec, &len, &data, 8))
|
|
{
|
|
int rc = 0;
|
|
nelem = 1;
|
|
for (i = 0, p = data; i < len; i++, p++)
|
|
{
|
|
if (!(*p & 0x80))
|
|
nelem++;
|
|
}
|
|
*val = q = DecAllocObjectIdentifier(dec, nelem);
|
|
if (q)
|
|
{
|
|
v = 0;
|
|
for (i = 0, p = data; i < len; i++, p++)
|
|
{
|
|
v = (v << 7) | (*p & 0x7f);
|
|
if (!(*p & 0x80))
|
|
{
|
|
if (q == *val)
|
|
{ // first id
|
|
q->value = v / 40;
|
|
if (q->value > 2)
|
|
q->value = 2;
|
|
q->next->value = v - 40 * q->value;
|
|
q = q->next->next;
|
|
}
|
|
else
|
|
{
|
|
q->value = v;
|
|
q = q->next;
|
|
}
|
|
v = 0;
|
|
}
|
|
}
|
|
rc = 1;
|
|
}
|
|
DecMemFree(dec, data);
|
|
return rc;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode an object identifier */
|
|
int ASN1PERDecObjectIdentifier2(ASN1decoding_t dec, ASN1objectidentifier2_t *val)
|
|
{
|
|
ASN1uint32_t len, i, v;
|
|
ASN1octet_t *data, *p;
|
|
ASN1uint32_t nelem;
|
|
ASN1objectidentifier_t q;
|
|
|
|
int rc = 0;
|
|
if (ASN1PERDecFragmented(dec, &len, &data, 8))
|
|
{
|
|
if (len <= 16) // lonchanc: hard-coded value 16 to be consistent with ASN1objectidentifier2_t
|
|
{
|
|
val->count = 0;
|
|
v = 0;
|
|
for (i = 0, p = data; i < len; i++, p++)
|
|
{
|
|
v = (v << 7) | (*p & 0x7f);
|
|
if (!(*p & 0x80))
|
|
{
|
|
if (! val->count)
|
|
{ // first id
|
|
val->value[0] = v / 40;
|
|
if (val->value[0] > 2)
|
|
val->value[0] = 2;
|
|
val->value[1] = v - 40 * val->value[0];
|
|
val->count = 2;
|
|
}
|
|
else
|
|
{
|
|
val->value[val->count++] = v;
|
|
}
|
|
v = 0;
|
|
}
|
|
}
|
|
|
|
// success
|
|
rc = 1;
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_LARGE);
|
|
}
|
|
|
|
DecMemFree(dec, data);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/* decode a fragmented signed intx value */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedIntx(ASN1decoding_t dec, ASN1intx_t *val)
|
|
{
|
|
return ASN1PERDecFragmented(dec, &val->length, &val->value, 8);
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented unsigned intx value */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedUIntx(ASN1decoding_t dec, ASN1intx_t *val)
|
|
{
|
|
if (ASN1PERDecFragmented(dec, &val->length, &val->value, 8))
|
|
{
|
|
if (val->length && val->value[0] > 0x7f)
|
|
{
|
|
ASN1octet_t *p;
|
|
if (NULL != (p = (ASN1octet_t *)DecMemAlloc(dec, val->length + 1)))
|
|
{
|
|
*p = 0;
|
|
CopyMemory(p + 1, val->value, val->length);
|
|
DecMemFree(dec, val->value);
|
|
val->value = p;
|
|
val->length++;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode fragmented extension bits */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedExtension(ASN1decoding_t dec, ASN1uint32_t nbits, ASN1octet_t *val)
|
|
{
|
|
ASN1uint32_t m, n;
|
|
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (m + n <= nbits)
|
|
{
|
|
if (ASN1PERDecCheck(dec, n))
|
|
{
|
|
ASN1bitcpy(val, m, dec->pos, dec->bit, n);
|
|
PerDecAdvance(dec, n);
|
|
m += n;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedCharString(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char_t *)DecMemReAlloc(dec, *val, m + n)))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (nbits == 8)
|
|
{
|
|
ASN1bitcpy((ASN1octet_t *)p, 0, dec->pos, dec->bit, n * 8);
|
|
PerDecAdvance(dec, n * 8);
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (ASN1char_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented 16 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedChar16String(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char16_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char16_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char16_t *)DecMemReAlloc(dec, *val, (m + n) * sizeof(ASN1char16_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (!dec->bit && nbits == 16)
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (dec->pos[0] << 8) | dec->pos[1];
|
|
dec->pos += 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (ASN1char16_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented 32 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedChar32String(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char32_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char32_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char32_t *)DecMemReAlloc(dec, *val, (m + n) * sizeof(ASN1char32_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (!dec->bit && nbits == 32)
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (dec->pos[0] << 24) | (dec->pos[1] << 16) |
|
|
(dec->pos[2] << 8) | dec->pos[3];
|
|
dec->pos += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented zero-terminated string */
|
|
int ASN1PERDecFragmentedZeroCharString(ASN1decoding_t dec, ASN1char_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char_t *)DecMemReAlloc(dec, *val, m + n + 1)))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (nbits == 8)
|
|
{
|
|
ASN1bitcpy((ASN1octet_t *)p, 0, dec->pos, dec->bit, n * 8);
|
|
PerDecAdvance(dec, n * 8);
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (ASN1char_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, 1);
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* decode a fragmented zero-terminated 16 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedZeroChar16String(ASN1decoding_t dec, ASN1char16_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char16_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char16_t *)DecMemReAlloc(dec, *val, (m + n + 1) * sizeof(ASN1char16_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (!dec->bit && nbits == 16)
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (dec->pos[0] << 8) | dec->pos[1];
|
|
dec->pos += 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (ASN1char16_t) ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char16_t *)DecMemAlloc(dec, sizeof(ASN1char16_t));
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented zero-terminated 32 bit string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedZeroChar32String(ASN1decoding_t dec, ASN1char32_t **val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1char32_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char32_t *)DecMemReAlloc(dec, *val, (m + n + 1) * sizeof(ASN1char32_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
if (!dec->bit && nbits == 32)
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = (dec->pos[0] << 24) | (dec->pos[1] << 16) |
|
|
(dec->pos[2] << 8) | dec->pos[3];
|
|
dec->pos += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = n; i; i--)
|
|
{
|
|
*p++ = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char32_t *)DecMemAlloc(dec, sizeof(ASN1char32_t));
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedTableCharString(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char_t *)DecMemReAlloc(dec, *val, m + n)))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented 16 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedTableChar16String(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char16_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char16_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char16_t *)DecMemReAlloc(dec, *val, (m + n) * sizeof(ASN1char16_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char16_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented 32 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedTableChar32String(ASN1decoding_t dec, ASN1uint32_t *nchars, ASN1char32_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char32_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char32_t *)DecMemReAlloc(dec, *val, (m + n) * sizeof(ASN1char32_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = entry->lower + (chr.value - entry->value);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
*nchars = m;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented zero-terminated table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedZeroTableCharString(ASN1decoding_t dec, ASN1char_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char_t *)DecMemReAlloc(dec, *val, m + n + 1)))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char_t *)DecMemAlloc(dec, 1);
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented zero-terminated 16 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedZeroTableChar16String(ASN1decoding_t dec, ASN1char16_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char16_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char16_t *)DecMemReAlloc(dec, *val, (m + n + 1) * sizeof(ASN1char16_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = (ASN1char16_t) (entry->lower + (chr.value - entry->value));
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char16_t *)DecMemAlloc(dec, sizeof(ASN1char16_t));
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a fragmented zero-terminated 32 bit table string */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecFragmentedZeroTableChar32String(ASN1decoding_t dec, ASN1char32_t **val, ASN1uint32_t nbits, ASN1stringtable_t *table)
|
|
{
|
|
ASN1uint32_t m, n, i;
|
|
ASN1stringtableentry_t chr, *entry;
|
|
ASN1char32_t *p;
|
|
|
|
*val = 0;
|
|
m = 0;
|
|
chr.lower = chr.upper = 0;
|
|
do {
|
|
if (ASN1PERDecFragmentedLength(dec, &n))
|
|
{
|
|
if (!n)
|
|
break;
|
|
if (ASN1PERDecCheck(dec, n * nbits))
|
|
{
|
|
if (NULL != (*val = (ASN1char32_t *)DecMemReAlloc(dec, *val, (m + n + 1) * sizeof(ASN1char32_t))))
|
|
{
|
|
p = *val + m;
|
|
m += n;
|
|
for (i = n; i; i--)
|
|
{
|
|
chr.value = ASN1bitgetu(dec->pos, dec->bit, nbits);
|
|
PerDecAdvance(dec, nbits);
|
|
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
|
|
table->length, sizeof(ASN1stringtableentry_t),
|
|
ASN1CmpStringTableEntriesByIndex);
|
|
if (entry)
|
|
{
|
|
*p++ = entry->lower + (chr.value - entry->value);
|
|
}
|
|
else
|
|
{
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} while (n >= 0x4000);
|
|
|
|
if (!*val)
|
|
*val = (ASN1char32_t *)DecMemAlloc(dec, sizeof(ASN1char32_t));
|
|
if (*val)
|
|
(*val)[m] = 0;
|
|
return 1;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
/* decode a generalized time */
|
|
int ASN1PERDecGeneralizedTime(ASN1decoding_t dec, ASN1generalizedtime_t *val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1ztcharstring_t time;
|
|
if (ASN1PERDecFragmentedZeroCharString(dec, &time, nbits))
|
|
{
|
|
int rc = ASN1string2generalizedtime(val, time);
|
|
DecMemFree(dec, time);
|
|
if (rc)
|
|
{
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* decode a utc time */
|
|
#ifdef ENABLE_ALL
|
|
int ASN1PERDecUTCTime(ASN1decoding_t dec, ASN1utctime_t *val, ASN1uint32_t nbits)
|
|
{
|
|
ASN1ztcharstring_t time;
|
|
if (ASN1PERDecFragmentedZeroCharString(dec, &time, nbits))
|
|
{
|
|
int rc = ASN1string2utctime(val, time);
|
|
DecMemFree(dec, time);
|
|
if (rc)
|
|
{
|
|
return 1;
|
|
}
|
|
ASN1DecSetError(dec, ASN1_ERR_CORRUPT);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ENABLE_ALL
|
|
|
|
|
|
|