windows-nt/Source/XPSP1/NT/enduser/msasn1/perencod.c
2020-09-26 16:20:57 +08:00

1730 lines
49 KiB
C

/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */
#include "precomp.h"
#include <math.h>
#include "cintern.h"
#if HAS_IEEEFP_H
#include <ieeefp.h>
#elif HAS_FLOAT_H
#include <float.h>
#endif
#define ENCODE_BUFFER_INCREMENT 1024
void PerEncAdvance(ASN1encoding_t enc, ASN1uint32_t nbits)
{
enc->pos += ((enc->bit + nbits) >> 3);
enc->bit = (enc->bit + nbits) & 7;
}
static const ASN1uint8_t c_aBitMask2[] =
{
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
};
/* compare two string table entries */
/* return 0 if a1 == a2, 1 if a1 > a2 and -1 if a1 < a2 */
static int __cdecl ASN1CmpStringTableEntries(const void *a1, const void *a2)
{
ASN1stringtableentry_t *c1 = (ASN1stringtableentry_t *)a1;
ASN1stringtableentry_t *c2 = (ASN1stringtableentry_t *)a2;
if (c1->upper < c2->lower)
return -1;
return ((c1->lower > c2->upper) ? 1 : 0);
}
/* check for space in buffer for PER and BER. */
int ASN1EncCheck(ASN1encoding_t enc, ASN1uint32_t noctets)
{
// any additional space required?
if (noctets)
{
// buffer exists?
if (NULL != enc->buf)
{
// buffer large enough?
if (enc->size - (enc->pos - enc->buf) - ((enc->bit != 0) ? 1 : 0) >= noctets)
{
return 1;
}
// static buffer overflow?
if (enc->dwFlags & ASN1ENCODE_SETBUFFER)
{
ASN1EncSetError(enc, ASN1_ERR_OVERFLOW);
return 0;
}
else
{
// round up to next 256 byte boundary and resize buffer
ASN1octet_t *oldbuf = enc->buf;
// enc->size = ((noctets + (enc->pos - oldbuf) + (enc->bit != 0) - 1) | 255) + 1;
if (ASN1_PER_RULE & enc->eRule)
{
enc->size += max(noctets, ENCODE_BUFFER_INCREMENT);
}
else
{
enc->size += max(noctets, enc->size);
}
enc->buf = (ASN1octet_t *)EncMemReAlloc(enc, enc->buf, enc->size);
if (NULL != enc->buf)
{
enc->pos = enc->buf + (enc->pos - oldbuf);
}
else
{
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
}
}
}
else
{
// no buffer exists, allocate new one.
// round up to next 256 byte boundary and allocate buffer
// enc->size = ((noctets - 1) | 255) + 1;
enc->size = max(noctets + enc->cbExtraHeader, ENCODE_BUFFER_INCREMENT);
enc->buf = EncMemAlloc(enc, enc->size);
if (NULL != enc->buf)
{
enc->pos = (ASN1octet_t *) (enc->buf + enc->cbExtraHeader);
}
else
{
enc->pos = NULL;
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
}
}
}
return 1;
}
/* encode a zero octet string of length nbits */
int ASN1PEREncZero(ASN1encoding_t enc, ASN1uint32_t nbits)
{
/* nothing to encode? */
if (nbits)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits + enc->bit + 7) / 8))
{
/* clear bits */
ASN1bitclr(enc->pos, enc->bit, nbits);
PerEncAdvance(enc, nbits);
return 1;
}
return 0;
}
return 1;
}
/* encode a bit */
int ASN1PEREncBit(ASN1encoding_t enc, ASN1uint32_t val)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, 1))
{
/* put one bit */
if (val)
{
*enc->pos |= 0x80 >> enc->bit;
}
if (enc->bit < 7)
{
enc->bit++;
}
else
{
enc->bit = 0;
enc->pos++;
}
return 1;
}
return 0;
}
/* encode an integer value into a bit field of given size */
int ASN1PEREncBitVal(ASN1encoding_t enc, ASN1uint32_t nbits, ASN1uint32_t val)
{
/* nothing to encode? */
if (nbits)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits + enc->bit + 7) / 8))
{
/* put bits */
ASN1bitput(enc->pos, enc->bit, val, nbits);
PerEncAdvance(enc, nbits);
return 1;
}
return 0;
}
return 1;
}
/* encode an integer value of intx type into a bit field of given size */
int ASN1PEREncBitIntx(ASN1encoding_t enc, ASN1uint32_t nbits, ASN1intx_t *val)
{
/* nothing to encode? */
if (nbits)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits + enc->bit + 7) / 8))
{
/* stuff sign bits into if value encoding is too small */
if (nbits > 8 * val->length)
{
if (val->value[0] > 0x7f)
ASN1bitset(enc->pos, enc->bit, nbits - 8 * val->length);
else
ASN1bitclr(enc->pos, enc->bit, nbits - 8 * val->length);
PerEncAdvance(enc, nbits - 8 * val->length);
nbits = 8 * val->length;
}
/* copy bits of value */
ASN1bitcpy(enc->pos, enc->bit, val->value, 8 * val->length - nbits, nbits);
PerEncAdvance(enc, nbits);
return 1;
}
return 0;
}
return 1;
}
/* encode a bit field of given size */
int ASN1PEREncBits(ASN1encoding_t enc, ASN1uint32_t nbits, ASN1octet_t *val)
{
/* nothing to encode? */
if (nbits)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits + enc->bit + 7) / 8))
{
/* copy bits */
ASN1bitcpy(enc->pos, enc->bit, val, 0, nbits);
PerEncAdvance(enc, nbits);
return 1;
}
return 0;
}
return 1;
}
/* encode a normally small integer value */
int ASN1PEREncNormallySmall(ASN1encoding_t enc, ASN1uint32_t val)
{
ASN1uint32_t noctets;
/* is normally small ASN1really small? */
if (val < 64)
{
return ASN1PEREncBitVal(enc, 7, val);
}
/* large */
if (ASN1PEREncBitVal(enc, 1, 1))
{
ASN1PEREncAlignment(enc);
noctets = ASN1uint32_uoctets(val);
if (ASN1PEREncCheck(enc, noctets + 1))
{
EncAssert(enc, noctets < 256);
*enc->pos++ = (ASN1octet_t) noctets;
ASN1octetput(enc->pos, val, noctets);
enc->pos += noctets;
return 1;
}
}
return 0;
}
/* encode a bit field with a normally small length */
int ASN1PEREncNormallySmallBits(ASN1encoding_t enc, ASN1uint32_t nbits, ASN1octet_t *val)
{
/* is normally small really small? */
if (nbits <= 64)
{
if (ASN1PEREncBitVal(enc, 7, nbits - 1))
{
return ASN1PEREncBits(enc, nbits, val);
}
}
/* large */
else
{
if (ASN1PEREncBitVal(enc, 1, 1))
{
return ASN1PEREncFragmented(enc, nbits, val, 1);
}
}
return 0;
}
/* encode an octet string of given length */
#ifdef ENABLE_ALL
int ASN1PEREncOctets(ASN1encoding_t enc, ASN1uint32_t noctets, ASN1octet_t *val)
{
/* nothing to encode? */
if (noctets)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, noctets + (enc->bit != 0)))
{
ASN1bitcpy(enc->pos, enc->bit, val, 0, noctets * 8);
PerEncAdvance(enc, noctets * 8);
return 1;
}
return 0;
}
return 1;
}
#endif // ENABLE_ALL
/* encode a string of given length and fixed character size */
int ASN1PEREncCharString(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits)
{
/* nothing to encode? */
if (nchars)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* same src and dst charsize? then do it simple (and fast!) */
if (nbits == 8)
{
ASN1bitcpy(enc->pos, enc->bit, (ASN1octet_t *)val, 0, nchars * 8);
PerEncAdvance(enc, nchars * 8);
return 1;
}
/* copy characters one by one */
while (nchars--)
{
ASN1bitput(enc->pos, enc->bit, *val++, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
/* encode a 16 bit string of given length and fixed character size */
int ASN1PEREncChar16String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char16_t *val, ASN1uint32_t nbits)
{
/* nothing to encode? */
if (nchars)
{
/* octet aligned and same src and dst charsize?
then do it simple (and fast!) */
if (!enc->bit && nbits == 16)
{
if (ASN1PEREncCheck(enc, nchars * 2))
{
while (nchars--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
return 1;
}
return 0;
}
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* copy characters one by one */
while (nchars--)
{
ASN1bitput(enc->pos, enc->bit, *val++, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
/* encode a 32 bit string of given length and fixed character size */
#ifdef ENABLE_ALL
int ASN1PEREncChar32String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char32_t *val, ASN1uint32_t nbits)
{
/* nothing to encode? */
if (nchars)
{
/* octet aligned and same src and dst charsize?
then do it simple (and fast!) */
if (!enc->bit && nbits == 32)
{
if (ASN1PEREncCheck(enc, nchars * 4))
{
while (nchars--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 24);
*enc->pos++ = (ASN1octet_t)(*val >> 16);
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
return 1;
}
return 0;
}
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* copy characters */
while (nchars--)
{
ASN1bitput(enc->pos, enc->bit, *val++, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
#endif // ENABLE_ALL
/* encode a table string of given length and fixed character size */
int ASN1PEREncTableCharString(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
/* nothing to encode? */
if (nchars)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* copy characters one by one */
while (nchars--)
{
ASN1stringtableentry_t chr, *entry;
chr.lower = chr.upper = (unsigned char)*val++;
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries);
ASN1bitput(enc->pos, enc->bit,
entry ? entry->value + (chr.lower - entry->lower) : 0, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
/* encode a 16 bit table string of given length and fixed character size */
int ASN1PEREncTableChar16String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char16_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
/* nothing to encode? */
if (nchars)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* copy characters one by one */
while (nchars--)
{
ASN1stringtableentry_t chr, *entry;
chr.lower = chr.upper = *val++;
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries);
ASN1bitput(enc->pos, enc->bit,
entry ? entry->value + (chr.lower - entry->lower) : 0, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
/* encode a 32 bit table string of given length and fixed character size */
#ifdef ENABLE_ALL
int ASN1PEREncTableChar32String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char32_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
/* nothing to encode? */
if (nchars)
{
/* get enough space in buffer */
if (ASN1PEREncCheck(enc, (nbits * nchars + enc->bit + 7) / 8))
{
/* copy characters one by one */
while (nchars--)
{
ASN1stringtableentry_t chr, *entry;
chr.lower = chr.upper = *val++;
entry = (ASN1stringtableentry_t *)ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries);
ASN1bitput(enc->pos, enc->bit,
entry ? entry->value + (chr.lower - entry->lower) : 0, nbits);
PerEncAdvance(enc, nbits);
}
return 1;
}
return 0;
}
return 1;
}
#endif // ENABLE_ALL
/* encode a fragmented string of given length and fixed character size */
int ASN1PEREncFragmentedCharString(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncCharString(enc, n, val, nbits))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
/* encode a fragmented 16 bit string of given length and fixed character size */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedChar16String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char16_t *val, ASN1uint32_t nbits)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncChar16String(enc, n, val, nbits))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
#endif // ENABLE_ALL
/* encode a fragmented 32 bit string of given length and fixed character size */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedChar32String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char32_t *val, ASN1uint32_t nbits)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncChar32String(enc, n, val, nbits))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
#endif // ENABLE_ALL
/* encode a fragmented table string of given length and fixed character size */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedTableCharString(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncTableCharString(enc, n, val, nbits, table))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
#endif // ENABLE_ALL
/* encode a fragmented 16 bit table string of given length and fixed */
/* character size */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedTableChar16String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char16_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncTableChar16String(enc, n, val, nbits, table))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
#endif // ENABLE_ALL
/* encode a fragmented 32 bit table string of given length and fixed */
/* character size */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedTableChar32String(ASN1encoding_t enc, ASN1uint32_t nchars, ASN1char32_t *val, ASN1uint32_t nbits, ASN1stringtable_t *table)
{
ASN1uint32_t n = 0x4000;
/* encode fragments */
while (nchars)
{
if (ASN1PEREncFragmentedLength(&n, enc, nchars))
{
if (ASN1PEREncTableChar32String(enc, n, val, nbits, table))
{
nchars -= n;
val += n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K chars */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
#endif // ENABLE_ALL
#if 0
#ifdef ENABLE_ALL
int ASN1PEREncCheckTableCharString(ASN1uint32_t nchars, ASN1char_t *val, ASN1stringtable_t *table)
{
ASN1stringtableentry_t chr;
/* check if every char is in given string table */
while (nchars--) {
chr.lower = chr.upper = (unsigned char)*val++;
if (!ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries))
return 0;
}
return 1;
}
#endif // ENABLE_ALL
#ifdef ENABLE_ALL
int ASN1PEREncCheckTableChar16String(ASN1uint32_t nchars, ASN1char16_t *val, ASN1stringtable_t *table)
{
ASN1stringtableentry_t chr;
/* check if every char is in given string table */
while (nchars--) {
chr.lower = chr.upper = *val++;
if (!ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries))
return 0;
}
return 1;
}
#endif // ENABLE_ALL
#ifdef ENABLE_ALL
int ASN1PEREncCheckTableChar32String(ASN1uint32_t nchars, ASN1char32_t *val, ASN1stringtable_t *table)
{
ASN1stringtableentry_t chr;
/* check if every char is in given string table */
while (nchars--) {
chr.lower = chr.upper = *val++;
if (!ms_bSearch(&chr, table->values,
table->length, sizeof(ASN1stringtableentry_t),
ASN1CmpStringTableEntries))
return 0;
}
return 1;
}
#endif // ENABLE_ALL
#endif // 0
/* remove trailing zero bits of a bit string */
#ifdef ENABLE_ALL
int ASN1PEREncRemoveZeroBits(ASN1uint32_t *nbits, ASN1octet_t *val, ASN1uint32_t minlen)
{
ASN1uint32_t n;
int i;
/* get value */
n = *nbits;
/* nothing to scan? */
if (n > minlen)
{
/* let val point to last ASN1octet used */
val += (n - 1) / 8;
/* check if broken ASN1octet consist out of zero bits */
if ((n & 7) && !(*val & c_aBitMask2[n & 7])) {
n &= ~7;
val--;
}
/* scan complete ASN1octets (memrchr missing ...) */
if (!(n & 7)) {
while (n > minlen && !*val) {
n -= 8;
val--;
}
}
/* scan current octet bit after bit */
if (n > minlen) {
for (i = (n - 1) & 7; i >= 0; i--) {
if (*val & (0x80 >> i))
break;
n--;
}
}
/* return real bitstring len */
*nbits = n < minlen ? minlen : n;
}
return 1;
}
#endif // ENABLE_ALL
/* encode a fragmented integer of intx type */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedIntx(ASN1encoding_t enc, ASN1intx_t *val)
{
ASN1uint32_t noctets;
ASN1uint32_t n = 0x4000;
ASN1octet_t *v;
ASN1uint32_t val1, val2;
/* get length */
noctets = val->length;
/* get value */
v = val->value;
/* required size:
noctets for data itself
+ noctets / 0x10000 for 64K-fragment size prefixes
+ ((noctets & 0xc000) > 0) for last 16K..48K-fragment size prefix
+ 1 for size prefix of remaining <128 octets
+ ((noctets & 0x3fff) >= 0x80) for additional octet if rem. data >= 128
*/
val1 = ((noctets & 0xc000) > 0) ? 1 : 0;
val2 = ((noctets & 0x3fff) >= 0x80) ? 1 : 0;
if (ASN1PEREncCheck(enc, noctets + noctets / 0x10000 + val1 + 1 + val2))
{
/* encode fragments */
while (noctets)
{
if (ASN1PEREncFragmentedLength(&n, enc, noctets))
{
CopyMemory(enc->pos, v, n);
enc->pos += n;
noctets -= n;
v += n;
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K octets */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
return 0;
}
#endif // ENABLE_ALL
/* encode a fragmented unsigned integer of intx type */
#ifdef ENABLE_ALL
int ASN1PEREncFragmentedUIntx(ASN1encoding_t enc, ASN1intx_t *val)
{
ASN1uint32_t noctets;
ASN1uint32_t n = 0x4000;
ASN1octet_t *v;
ASN1uint32_t val1, val2;
/* get length */
noctets = ASN1intx_uoctets(val);
/* get value */
v = val->value + val->length - noctets;
/* required size:
noctets for data itself
+ noctets / 0x10000 for 64K-fragment size prefixes
+ ((noctets & 0xc000) > 0) for last 16K..48K-fragment size prefix
+ 1 for size prefix of remaining <128 octets
+ ((noctets & 0x3fff) >= 0x80) for additional octet if rem. data >= 128
*/
val1 = ((noctets & 0xc000) > 0) ? 1 : 0;
val2 = ((noctets & 0x3fff) >= 0x80) ? 1 : 0;
if (ASN1PEREncCheck(enc, noctets + noctets / 0x10000 + val1 + 1 + val2))
{
/* encode fragments */
while (noctets)
{
if (ASN1PEREncFragmentedLength(&n, enc, noctets))
{
CopyMemory(enc->pos, v, n);
enc->pos += n;
noctets -= n;
v += n;
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K octets */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
return 0;
}
#endif // ENABLE_ALL
/* encode a fragment length */
int ASN1PEREncFragmentedLength(ASN1uint32_t *len, ASN1encoding_t enc, ASN1uint32_t nitems)
{
/* always ASN1octet aligned */
ASN1PEREncAlignment(enc);
/* fragmented encoding:
*
* - nitems < 0x80:
* octet #1:
* bit 8: 0,
* bit 7..1: nitems
* octet #2..:
* nitems items
* - 0x80 <= nitems < 0x4000:
* octet #1:
* bit 8..7: 10,
* bit 6..1: bit 14..9 of nitems
* octet #2:
* bit 8..1: bit 8..1 of nitems
* octet #3..:
* nitems items
* - 0x4000 <= nitems < 0x10000:
* octet #1:
* bit 8..7: 11,
* bit 6..1: nitems / 0x4000
* octet #2..:
* (nitems & 0xc000) items
* - 0x10000 <= nitems:
* octet #1:
* bit 8..1: 11000100
* octet #2..:
* 0x10000 items
*/
if (nitems < 0x80)
{
if (ASN1PEREncCheck(enc, 1))
{
*enc->pos++ = (ASN1octet_t)nitems;
*len = nitems;
return 1;
}
}
else
if (nitems < 0x4000)
{
if (ASN1PEREncCheck(enc, 2))
{
*enc->pos++ = (ASN1octet_t)(0x80 | (nitems >> 8));
*enc->pos++ = (ASN1octet_t)nitems;
*len = nitems;
return 1;
}
}
else
if (nitems < 0x10000)
{
if (ASN1PEREncCheck(enc, 1))
{
*enc->pos++ = (ASN1octet_t)(0xc0 | (nitems >> 14));
*len = nitems & 0xc000;
return 1;
}
}
else
{
if (ASN1PEREncCheck(enc, 1))
{
*enc->pos++ = (ASN1octet_t)0xc4;
*len = 0x10000;
return 1;
}
}
return 0;
}
/* encode a fragment bit string containing nitems of size itemsize */
int ASN1PEREncFragmented(ASN1encoding_t enc, ASN1uint32_t nitems, ASN1octet_t *val, ASN1uint32_t itemsize)
{
ASN1uint32_t n = 0x4000;
ASN1uint32_t noctets = (nitems * itemsize + 7) / 8;
/* required size:
+ noctets for data itself
+ nitems / 0x10000 for 64K-fragment size prefixes
+ ((nitems & 0xc000) > 0) for last 16K..48K-fragment size prefix
+ 1 for size prefix of remaining <128 ASN1octets
+ ((nitems & 0x3fff) >= 0x80) for additional ASN1octet if rem. data >= 128
*/
if (ASN1PEREncCheck(enc, noctets + nitems / 0x10000 + ((nitems & 0xc000) > 0) + 1 + ((nitems & 0x3fff) >= 0x80)))
{
/* encode fragments */
while (nitems)
{
if (ASN1PEREncFragmentedLength(&n, enc, nitems))
{
ASN1bitcpy(enc->pos, 0, val, 0, n * itemsize);
PerEncAdvance(enc, n * itemsize);
nitems -= n;
val += n * itemsize / 8;
}
else
{
return 0;
}
}
/* add zero length octet if last fragment contained more than 16K items */
return ((n < 0x4000) ? 1 : ASN1PEREncFragmentedLength(&n, enc, 0));
}
return 0;
}
int ASN1PEREncFlushFragmentedToParent(ASN1encoding_t enc)
{
// make sure it is parented
EncAssert(enc, ((ASN1INTERNencoding_t)enc)->parent != (ASN1INTERNencoding_t)enc);
if (ASN1PEREncFlush(enc))
{
if (ASN1PEREncFragmented((ASN1encoding_t) ((ASN1INTERNencoding_t)enc)->parent,
enc->len, enc->buf, 8))
{
// reset the buffer, i.e. keep enc->buf and enc->size
enc->pos = enc->buf;
enc->len = enc->bit = 0;
return 1;
}
}
return 0;
}
ASN1octet_t * _PEREncOidNode(ASN1octet_t *p, ASN1uint32_t s)
{
if (s < 0x80)
{
*p++ = (ASN1octet_t)(s);
}
else
if (s < 0x4000)
{
*p++ = (ASN1octet_t)((s >> 7) | 0x80);
*p++ = (ASN1octet_t)(s & 0x7f);
}
else
if (s < 0x200000)
{
*p++ = (ASN1octet_t)((s >> 14) | 0x80);
*p++ = (ASN1octet_t)((s >> 7) | 0x80);
*p++ = (ASN1octet_t)(s & 0x7f);
}
else
if (s < 0x10000000)
{
*p++ = (ASN1octet_t)((s >> 21) | 0x80);
*p++ = (ASN1octet_t)((s >> 14) | 0x80);
*p++ = (ASN1octet_t)((s >> 7) | 0x80);
*p++ = (ASN1octet_t)(s & 0x7f);
}
else
{
*p++ = (ASN1octet_t)((s >> 28) | 0x80);
*p++ = (ASN1octet_t)((s >> 21) | 0x80);
*p++ = (ASN1octet_t)((s >> 14) | 0x80);
*p++ = (ASN1octet_t)((s >> 7) | 0x80);
*p++ = (ASN1octet_t)(s & 0x7f);
}
return p;
}
/* encode an object identifier */
int ASN1PEREncObjectIdentifier(ASN1encoding_t enc, ASN1objectidentifier_t *val)
{
ASN1objectidentifier_t obj = *val;
ASN1uint32_t l = GetObjectIdentifierCount(obj);
if (l)
{
ASN1uint32_t i, s;
ASN1octet_t *data, *p;
int rc;
/* convert object identifier to octets */
p = data = (ASN1octet_t *)MemAlloc(l * 5, _ModName(enc)); /* max. 5 octets/subelement */
if (p)
{
for (i = 0; i < l; i++)
{
s = obj->value;
obj = obj->next;
if (!i && l > 1)
{
s = s * 40 + obj->value;
obj = obj->next;
i++;
}
p = _PEREncOidNode(p, s);
}
/* encode octet string as fragmented octet string */
rc = ASN1PEREncFragmented(enc, (ASN1uint32_t) (p - data), data, 8);
MemFree(data);
return rc;
}
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
}
/* encode zero length */
return ASN1PEREncFragmented(enc, 0, NULL, 8);
}
/* encode an object identifier */
int ASN1PEREncObjectIdentifier2(ASN1encoding_t enc, ASN1objectidentifier2_t *val)
{
if (val->count)
{
ASN1uint32_t i, s;
ASN1octet_t *data, *p;
int rc;
/* convert object identifier to octets */
p = data = (ASN1octet_t *)MemAlloc(val->count * 5, _ModName(enc)); /* max. 5 octets/subelement */
if (p)
{
for (i = 0; i < val->count; i++)
{
s = val->value[i];
if (!i && val->count > 1)
{
i++;
s = s * 40 + val->value[i];
}
p = _PEREncOidNode(p, s);
}
/* encode octet string as fragmented octet string */
rc = ASN1PEREncFragmented(enc, (ASN1uint32_t) (p - data), data, 8);
MemFree(data);
return rc;
}
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
}
/* encode zero length */
return ASN1PEREncFragmented(enc, 0, NULL, 8);
}
/* encode real value with double representation */
int ASN1PEREncDouble(ASN1encoding_t enc, double dbl)
{
double mantissa;
int exponent;
ASN1octet_t mASN1octets[16]; /* should be enough */
ASN1uint32_t nmASN1octets;
ASN1octet_t eASN1octets[16]; /* should be enough */
ASN1uint32_t neASN1octets;
ASN1octet_t head;
ASN1uint32_t sign;
ASN1uint32_t len;
ASN1uint32_t n;
/* always octet aligned */
ASN1PEREncAlignment(enc);
/* check for PLUS_INFINITY */
if (ASN1double_ispinf(dbl))
{
if (ASN1PEREncCheck(enc, 2))
{
*enc->pos++ = 1;
*enc->pos++ = 0x40;
return 1;
}
}
else
/* check for MINUS_INFINITY */
if (ASN1double_isminf(dbl))
{
if (ASN1PEREncCheck(enc, 2))
{
*enc->pos++ = 1;
*enc->pos++ = 0x41;
return 1;
}
}
else
/* check for bad real value */
if (finite(dbl))
{
/* encode normal real value */
/* split into mantissa and exponent */
mantissa = frexp(dbl, &exponent);
/* check for zero value */
if (mantissa == 0.0 && exponent == 0)
{
if (ASN1PEREncCheck(enc, 1))
{
*enc->pos++ = 0;
return 1;
}
}
else
{
/* get sign bit */
if (mantissa < 0.0)
{
sign = 1;
mantissa = -mantissa;
}
else
{
sign = 0;
}
/* encode mantissa */
nmASN1octets = 0;
while (mantissa != 0.0 && nmASN1octets < sizeof(mASN1octets))
{
mantissa *= 256.0;
exponent -= 8;
mASN1octets[nmASN1octets++] = (int)mantissa;
mantissa -= (double)(int)mantissa;
}
/* encode exponent and create head octet of encoded value */
head = (ASN1octet_t) (0x80 | (sign << 6));
if (exponent <= 0x7f && exponent >= -0x80)
{
eASN1octets[0] = (ASN1octet_t)(exponent);
neASN1octets = 1;
}
else
if (exponent <= 0x7fff && exponent >= -0x8000)
{
eASN1octets[0] = (ASN1octet_t)(exponent >> 8);
eASN1octets[1] = (ASN1octet_t)(exponent);
neASN1octets = 2;
head |= 0x01;
}
else
if (exponent <= 0x7fffff && exponent >= -0x800000)
{
eASN1octets[0] = (ASN1octet_t)(exponent >> 16);
eASN1octets[1] = (ASN1octet_t)(exponent >> 8);
eASN1octets[2] = (ASN1octet_t)(exponent);
neASN1octets = 3;
head |= 0x02;
}
else
{
eASN1octets[0] = 4; /* XXX does not work if int32_t != int */
eASN1octets[1] = (ASN1octet_t)(exponent >> 24);
eASN1octets[2] = (ASN1octet_t)(exponent >> 16);
eASN1octets[3] = (ASN1octet_t)(exponent >> 8);
eASN1octets[4] = (ASN1octet_t)(exponent);
neASN1octets = 5;
head |= 0x03;
}
/* encode length into first octet */
len = 1 + neASN1octets + nmASN1octets;
if (ASN1PEREncFragmentedLength(&n, enc, len))
{
/* check for space for head octet, mantissa and exponent */
if (ASN1PEREncCheck(enc, len))
{
/* put head octet, mantissa and exponent */
*enc->pos++ = head;
CopyMemory(enc->pos, eASN1octets, neASN1octets);
enc->pos += neASN1octets;
CopyMemory(enc->pos, mASN1octets, nmASN1octets);
enc->pos += nmASN1octets;
return 1;
}
}
}
}
else
{
ASN1EncSetError(enc, ASN1_ERR_BADREAL);
}
/* finished */
return 0;
}
/* encode an external value */
#ifdef ENABLE_EXTERNAL
int ASN1PEREncExternal(ASN1encoding_t enc, ASN1external_t *val)
{
ASN1uint32_t t, l;
if (!val->data_value_descriptor)
val->o[0] &= ~0x80;
/* encode identification */
switch (val->identification.o)
{
case ASN1external_identification_syntax_o:
if (!ASN1PEREncBitVal(enc, 3, 4 | !!val->data_value_descriptor))
return 0;
if (!ASN1PEREncObjectIdentifier(enc, &val->identification.u.syntax))
return 0;
break;
case ASN1external_identification_presentation_context_id_o:
if (!ASN1PEREncBitVal(enc, 3, 2 | !!val->data_value_descriptor))
return 0;
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(val->identification.u.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1external_identification_context_negotiation_o:
if (!ASN1PEREncBitVal(enc, 3, 6 | !!val->data_value_descriptor))
return 0;
if (!ASN1PEREncObjectIdentifier(enc, &val->identification.u.context_negotiation.transfer_syntax))
return 0;
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(
val->identification.u.context_negotiation.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8,
val->identification.u.context_negotiation.presentation_context_id))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* encode value descriptor */
if (val->o[0] & 0x80)
{
t = My_lstrlenA(val->data_value_descriptor);
if (!ASN1PEREncFragmentedCharString(enc, t,
val->data_value_descriptor, 8))
return 0;
}
/* encode value */
switch (val->data_value.o)
{
case ASN1external_data_value_notation_o:
if (!ASN1PEREncBitVal(enc, 2, 0))
return 0;
if (!ASN1PEREncFragmented(enc,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded, 8))
return 0;
break;
case ASN1external_data_value_encoded_o:
if (!(val->data_value.u.encoded.length & 7))
{
if (!ASN1PEREncBitVal(enc, 2, 1))
return 0;
if (!ASN1PEREncFragmented(enc, val->data_value.u.encoded.length / 8,
val->data_value.u.encoded.value, 8))
return 0;
}
else
{
if (!ASN1PEREncBitVal(enc, 2, 2))
return 0;
if (!ASN1PEREncFragmented(enc, val->data_value.u.encoded.length,
val->data_value.u.encoded.value, 1))
return 0;
}
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
return 1;
}
#endif // ENABLE_EXTERNAL
/* encode an embedded pdv value */
#ifdef ENABLE_EMBEDDED_PDV
int ASN1PEREncEmbeddedPdv(ASN1encoding_t enc, ASN1embeddedpdv_t *val)
{
ASN1uint32_t l;
ASN1uint32_t index;
ASN1uint32_t flag;
/* search identification */
if (!ASN1EncSearchEmbeddedPdvIdentification(((ASN1INTERNencoding_t) enc)->parent,
&val->identification, &index, &flag))
return 0;
/* encode EP-A/EP-B flag */
if (!ASN1PEREncBitVal(enc, 1, flag))
return 0;
/* encode index of identification */
if (!ASN1PEREncNormallySmall(enc, index))
return 0;
if (flag)
{
/* EP-A encoding: */
/* encode identification */
if (!ASN1PEREncBitVal(enc, 3, val->identification.o))
return 0;
switch (val->identification.o)
{
case ASN1embeddedpdv_identification_syntaxes_o:
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.syntaxes.abstract))
return 0;
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.syntaxes.transfer))
return 0;
break;
case ASN1embeddedpdv_identification_syntax_o:
if (!ASN1PEREncObjectIdentifier(enc, &val->identification.u.syntax))
return 0;
break;
case ASN1embeddedpdv_identification_presentation_context_id_o:
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(
val->identification.u.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1embeddedpdv_identification_context_negotiation_o:
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(val->
identification.u.context_negotiation.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8, val->
identification.u.context_negotiation.presentation_context_id))
return 0;
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.context_negotiation.transfer_syntax))
return 0;
break;
case ASN1embeddedpdv_identification_transfer_syntax_o:
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.transfer_syntax))
return 0;
break;
case ASN1embeddedpdv_identification_fixed_o:
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
}
/* encode value */
ASN1PEREncAlignment(enc);
switch (val->data_value.o)
{
case ASN1embeddedpdv_data_value_notation_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded, 1))
return 0;
break;
case ASN1embeddedpdv_data_value_encoded_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value, 1))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
return 1;
}
#endif // ENABLE_EMBEDDED_PDV
/* encode an optimized embedded pdv value */
#ifdef ENABLE_EMBEDDED_PDV
int ASN1PEREncEmbeddedPdvOpt(ASN1encoding_t enc, ASN1embeddedpdv_t *val)
{
/* encode data value */
switch (val->data_value.o)
{
case ASN1embeddedpdv_data_value_notation_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded, 1))
return 0;
break;
case ASN1embeddedpdv_data_value_encoded_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value, 1))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
return 1;
}
#endif // ENABLE_EMBEDDED_PDV
/* encode a character string */
#ifdef ENABLE_GENERALIZED_CHAR_STR
int ASN1PEREncCharacterString(ASN1encoding_t enc, ASN1characterstring_t *val)
{
ASN1uint32_t l;
ASN1uint32_t index;
ASN1uint32_t flag;
/* search identification */
if (!ASN1EncSearchCharacterStringIdentification(((ASN1INTERNencoding_t) enc)->parent,
&val->identification, &index, &flag))
return 0;
/* encode CS-A/CS-B flag */
if (!ASN1PEREncBitVal(enc, 1, flag))
return 0;
/* encode index of identification */
if (!ASN1PEREncNormallySmall(enc, index))
return 0;
if (flag)
{
/* CS-A encoding: */
/* encode identification */
if (!ASN1PEREncBitVal(enc, 3, val->identification.o))
return 0;
switch (val->identification.o) {
case ASN1characterstring_identification_syntaxes_o:
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.syntaxes.abstract))
return 0;
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.syntaxes.transfer))
return 0;
break;
case ASN1characterstring_identification_syntax_o:
if (!ASN1PEREncObjectIdentifier(enc, &val->identification.u.syntax))
return 0;
break;
case ASN1characterstring_identification_presentation_context_id_o:
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(
val->identification.u.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1characterstring_identification_context_negotiation_o:
ASN1PEREncAlignment(enc);
l = ASN1uint32_uoctets(val->
identification.u.context_negotiation.presentation_context_id);
if (!ASN1PEREncBitVal(enc, 8, l))
return 0;
if (!ASN1PEREncBitVal(enc, l * 8, val->
identification.u.context_negotiation.presentation_context_id))
return 0;
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.context_negotiation.transfer_syntax))
return 0;
break;
case ASN1characterstring_identification_transfer_syntax_o:
if (!ASN1PEREncObjectIdentifier(enc,
&val->identification.u.transfer_syntax))
return 0;
break;
case ASN1characterstring_identification_fixed_o:
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
}
/* encode value */
ASN1PEREncAlignment(enc);
switch (val->data_value.o)
{
case ASN1characterstring_data_value_notation_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded, 8))
return 0;
break;
case ASN1characterstring_data_value_encoded_o:
if (!ASN1PEREncFragmented(enc,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value, 8))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
return 1;
}
#endif // ENABLE_GENERALIZED_CHAR_STR
/* encode an optimized character string value */
#ifdef ENABLE_GENERALIZED_CHAR_STR
int ASN1PEREncCharacterStringOpt(ASN1encoding_t enc, ASN1characterstring_t *val)
{
switch (val->data_value.o)
{
case ASN1characterstring_data_value_notation_o:
return ASN1PEREncFragmented(enc,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded, 8);
break;
case ASN1characterstring_data_value_encoded_o:
return ASN1PEREncFragmented(enc,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value, 8);
break;
}
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
#endif // ENABLE_GENERALIZED_CHAR_STR
/* encode a multibyte string */
#ifdef ENABLE_ALL
int ASN1PEREncMultibyteString(ASN1encoding_t enc, ASN1char_t *val)
{
return ASN1PEREncFragmented(enc, My_lstrlenA(val), (ASN1octet_t *)val, 8);
}
#endif // ENABLE_ALL
/* encode a generalized time */
int ASN1PEREncGeneralizedTime(ASN1encoding_t enc, ASN1generalizedtime_t *val, ASN1uint32_t nbits)
{
char time[32];
if (ASN1generalizedtime2string(time, val))
{
return ASN1PEREncFragmentedCharString(enc, My_lstrlenA(time), time, nbits);
}
return 0;
}
/* encode a utc time */
#ifdef ENABLE_ALL
int ASN1PEREncUTCTime(ASN1encoding_t enc, ASN1utctime_t *val, ASN1uint32_t nbits)
{
char time[32];
if (ASN1utctime2string(time, val))
{
return ASN1PEREncFragmentedCharString(enc, My_lstrlenA(time), time, nbits);
}
return 0;
}
#endif // ENABLE_ALL
/* end of encoding */
int ASN1PEREncFlush(ASN1encoding_t enc)
{
/* complete broken octet */
ASN1PEREncAlignment(enc);
/* allocate at least one octet */
if (enc->buf)
{
/* fill in zero-octet if encoding is empty bitstring */
if (enc->buf == enc->pos)
*enc->pos++ = 0;
/* calculate length */
enc->len = (ASN1uint32_t) (enc->pos - enc->buf);
return 1;
}
return ASN1PEREncCheck(enc, 1);
}
/* encode an octet alignment */
void ASN1PEREncAlignment(ASN1encoding_t enc)
{
/* complete broken octet */
if (enc->bit)
{
enc->pos++;
enc->bit = 0;
}
}
/* compare two encodings */
#ifdef ENABLE_ALL
int ASN1PEREncCmpEncodings(const void *p1, const void *p2)
{
ASN1INTERNencoding_t e1 = (ASN1INTERNencoding_t)p1;
ASN1INTERNencoding_t e2 = (ASN1INTERNencoding_t)p2;
ASN1uint32_t l1, l2;
int r;
l1 = (ASN1uint32_t) (e1->info.pos - e1->info.buf) + ((e1->info.bit > 0) ? 1 : 0);
l2 = (ASN1uint32_t) (e2->info.pos - e2->info.buf) + ((e2->info.bit > 0) ? 1 : 0);
r = memcmp(e1->info.buf, e2->info.buf, l1 < l2 ? l1 : l2);
if (!r)
r = l1 - l2;
return r;
}
#endif // ENABLE_ALL
/* check a bit field for present optionals */
int ASN1PEREncCheckExtensions(ASN1uint32_t nbits, ASN1octet_t *val)
{
while (nbits >= 8)
{
if (*val)
return 1;
val++;
nbits -= 8;
}
if (nbits)
{
return ((*val & c_aBitMask2[nbits]) ? 1 : 0);
}
return 0;
}
/* encode an open type value */
#ifdef ENABLE_ALL
int ASN1PEREncOpenType(ASN1encoding_t enc, ASN1open_t *val)
{
return ASN1PEREncFragmented(enc, val->length, (ASN1octet_t *)val->encoded, 8);
}
#endif // ENABLE_ALL