windows-nt/Source/XPSP1/NT/enduser/msasn1/berencod.c

1430 lines
41 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */
#include "precomp.h"
#ifdef ENABLE_BER
#include <float.h>
#include <math.h>
#if HAS_IEEEFP_H
// #include <ieeefp.h>
#elif HAS_FLOAT_H
// #include <float.h>
#endif
static const char bitmsk2[] =
{
(const char) 0x00,
(const char) 0x80,
(const char) 0xc0,
(const char) 0xe0,
(const char) 0xf0,
(const char) 0xf8,
(const char) 0xfc,
(const char) 0xfe
};
/* encode a string value */
int ASN1BEREncCharString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char_t *val)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len))
{
CopyMemory(enc->pos, val, len);
enc->pos += len;
return 1;
}
}
return 0;
}
/* encode a string value (CER) */
int ASN1CEREncCharString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char_t *val)
{
ASN1uint32_t n;
if (len <= 1000)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len))
{
CopyMemory(enc->pos, val, len);
enc->pos += len;
return 1;
}
}
}
else
{
ASN1uint32_t nLenOff;
/* encode value as constructed, using segments of 1000 octets */
if (ASN1BEREncExplicitTag(enc, tag, &nLenOff))
{
while (len)
{
n = len > 1000 ? 1000 : len;
if (ASN1BEREncTag(enc, 0x4))
{
if (ASN1BEREncLength(enc, n))
{
CopyMemory(enc->pos, val, n);
enc->pos += n;
val += n;
len -= n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
return ASN1BEREncEndOfContents(enc, nLenOff);
}
}
return 0;
}
/* encode a 16 bit string value */
int ASN1BEREncChar16String(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char16_t *val)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len * sizeof(ASN1char16_t)))
{
while (len--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
}
return 1;
}
return 0;
}
/* encode a 16 bit string value (CER) */
int ASN1CEREncChar16String(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char16_t *val)
{
ASN1uint32_t n;
if (len <= 1000 / sizeof(ASN1char16_t))
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len * sizeof(ASN1char16_t)))
{
while (len--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
return 1;
}
}
}
else
{
ASN1uint32_t nLenOff;
/* encode value as constructed, using segments of 1000 octets */
if (ASN1BEREncExplicitTag(enc, tag, &nLenOff))
{
while (len)
{
n = len > 1000 / sizeof(ASN1char16_t) ?
1000 / sizeof(ASN1char16_t) : len;
if (ASN1BEREncTag(enc, 0x4))
{
if (ASN1BEREncLength(enc, n))
{
while (len--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
len -= n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
return ASN1BEREncEndOfContents(enc, nLenOff);
}
}
return 0;
}
/* encode a 32 bit string value */
int ASN1BEREncChar32String(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char32_t *val)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len * sizeof(ASN1char32_t)))
{
while (len--)
{
*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;
}
/* encode a 32 bit string value (CER) */
int ASN1CEREncChar32String(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1char32_t *val)
{
ASN1uint32_t n;
if (len <= 1000 / sizeof(ASN1char32_t))
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len * sizeof(ASN1char32_t)))
{
while (len--)
{
*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;
}
}
}
else
{
ASN1uint32_t nLenOff;
/* encode value as constructed, using segments of 1000 octets */
if (ASN1BEREncExplicitTag(enc, tag, &nLenOff))
{
while (len)
{
n = len > 1000 / sizeof(ASN1char32_t) ?
1000 / sizeof(ASN1char32_t) : len;
if (ASN1BEREncTag(enc, 0x4))
{
if (ASN1BEREncLength(enc, n))
{
while (len--)
{
*enc->pos++ = (ASN1octet_t)(*val >> 24);
*enc->pos++ = (ASN1octet_t)(*val >> 16);
*enc->pos++ = (ASN1octet_t)(*val >> 8);
*enc->pos++ = (ASN1octet_t)(*val);
val++;
}
len -= n;
}
else
{
return 0;
}
}
else
{
return 0;
}
} // while
return ASN1BEREncEndOfContents(enc, nLenOff);
}
}
return 0;
}
/* encode a bit string value */
int ASN1BEREncBitString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1octet_t *val)
{
ASN1uint32_t noctets = (len + 7) / 8;
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, noctets + 1))
{
ASN1uint32_t cUnusedBits = (7 - ((len + 7) & 7));
*enc->pos++ = (ASN1octet_t) cUnusedBits;
CopyMemory(enc->pos, val, noctets);
enc->pos += noctets;
EncAssert(enc, noctets >= 1);
if (cUnusedBits)
{
EncAssert(enc, 8 >= cUnusedBits);
*(enc->pos - 1) &= bitmsk2[8 - cUnusedBits];
}
return 1;
}
}
return 0;
}
/* encode a bit string value (CER) */
int ASN1CEREncBitString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1octet_t *val)
{
ASN1uint32_t noctets;
ASN1uint32_t n;
noctets = (len + 7) / 8;
if (noctets + 1 <= 1000)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, noctets + 1))
{
*enc->pos++ = (ASN1octet_t) (7 - ((len + 7) & 7));
CopyMemory(enc->pos, val, noctets);
enc->pos += noctets;
return 1;
}
}
}
else
{
ASN1uint32_t nLenOff;
/* encode value as constructed, using segments of 1000 octets */
if (ASN1BEREncExplicitTag(enc, tag, &nLenOff))
{
while (noctets)
{
n = len > 999 ? 999 : len;
if (ASN1BEREncTag(enc, 0x3))
{
if (ASN1BEREncLength(enc, n + 1))
{
*enc->pos++ = (ASN1octet_t) (n < len ? 0 : 7 - ((len + 7) & 7));
CopyMemory(enc->pos, val, n);
enc->pos += n;
val += n;
noctets -= n;
}
else
{
return 0;
}
}
else
{
return 0;
}
} // while
return ASN1BEREncEndOfContents(enc, nLenOff);
}
}
return 0;
}
#ifdef ENABLE_GENERALIZED_CHAR_STR
/* encode a character string value */
int ASN1BEREncCharacterString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1characterstring_t *val)
{
ASN1uint32_t index;
ASN1uint32_t flag;
/* search identification */
if (!ASN1EncSearchCharacterStringIdentification(((ASN1INTERNencoding_t) enc)->parent,
&val->identification, &index, &flag))
return 0;
if (index > 255)
flag = 1;
if (flag)
{
ASN1uint32_t nLenOff_, nLenOff0, nLenOff1;
/* CS-A encoding: */
/* encode as constructed value */
if (!ASN1BEREncExplicitTag(enc, tag, &nLenOff_))
return 0;
/* encode index */
if (!ASN1BEREncU32(enc, 0x80000000, index))
return 0;
/* encode tag of identification */
if (!ASN1BEREncExplicitTag(enc, 0x80000001, &nLenOff0))
return 0;
/* encode identification */
switch (val->identification.o)
{
case ASN1characterstring_identification_syntaxes_o:
if (!ASN1BEREncExplicitTag(enc, 0x80000000, &nLenOff1))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000000,
&val->identification.u.syntaxes.abstract))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.syntaxes.transfer))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff1))
return 0;
break;
case ASN1characterstring_identification_syntax_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.syntax))
return 0;
break;
case ASN1characterstring_identification_presentation_context_id_o:
if (!ASN1BEREncU32(enc, 0x80000002,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1characterstring_identification_context_negotiation_o:
if (!ASN1BEREncExplicitTag(enc, 0x80000003, &nLenOff1))
return 0;
if (!ASN1BEREncU32(enc, 0x80000000, val->
identification.u.context_negotiation.presentation_context_id))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.context_negotiation.transfer_syntax))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff1))
return 0;
break;
case ASN1characterstring_identification_transfer_syntax_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x80000004,
&val->identification.u.transfer_syntax))
return 0;
break;
case ASN1characterstring_identification_fixed_o:
if (!ASN1BEREncNull(enc, 0x80000005))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* end of identification */
if (!ASN1BEREncEndOfContents(enc, nLenOff0))
return 0;
/* encode data value */
switch (val->data_value.o)
{
case ASN1characterstring_data_value_notation_o:
if (!ASN1BEREncOctetString(enc, 0x80000002,
val->data_value.u.notation.length,
val->data_value.u.notation.encoded))
return 0;
break;
case ASN1characterstring_data_value_encoded_o:
if (!ASN1BEREncOctetString(enc, 0x80000002,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* end of character string */
if (!ASN1BEREncEndOfContents(enc, nLenOff_))
return 0;
}
else
{
/* CS-B encoding: */
/* encode tag */
if (!ASN1BEREncTag(enc, tag))
return 0;
/* encode data value */
switch (val->data_value.o)
{
case ASN1characterstring_data_value_notation_o:
if (!ASN1BEREncLength(enc,
val->data_value.u.notation.length + 1))
return 0;
*enc->pos++ = (ASN1octet_t) index;
CopyMemory(enc->pos, val->data_value.u.notation.encoded,
val->data_value.u.notation.length);
enc->pos += val->data_value.u.notation.length;
break;
case ASN1characterstring_data_value_encoded_o:
if (!ASN1BEREncLength(enc,
val->data_value.u.encoded.length + 1))
return 0;
*enc->pos++ = (ASN1octet_t) index;
CopyMemory(enc->pos, val->data_value.u.encoded.value,
val->data_value.u.encoded.length);
enc->pos += val->data_value.u.encoded.length;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
}
return 1;
}
#endif // ENABLE_GENERALIZED_CHAR_STR
#ifdef ENABLE_DOUBLE
/* encode a real value */
int ASN1BEREncDouble(ASN1encoding_t enc, ASN1uint32_t tag, double d)
{
double mantissa;
int exponent;
ASN1uint32_t nmoctets;
ASN1uint32_t neoctets;
ASN1octet_t head;
ASN1uint32_t sign;
ASN1uint32_t len;
ASN1octet_t mASN1octets[16]; /* should be enough */
ASN1octet_t eASN1octets[16]; /* should be enough */
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* check for PLUS_INFINITY */
if (ASN1double_ispinf(d))
{
/* encode length */
if (ASN1BEREncLength(enc, 1))
{
/* encode value */
*enc->pos++ = 0x40;
return 1;
}
}
else
/* check for MINUS_INFINITY */
if (ASN1double_isminf(d))
{
/* encode length */
if (ASN1BEREncLength(enc, 1))
{
/* encode value */
*enc->pos++ = 0x41;
return 1;
}
}
else
/* check for bad real value */
if (finite(d))
{
/* encode normal real value */
/* split into mantissa and exponent */
mantissa = frexp(d, &exponent);
/* check for zero value */
if (mantissa == 0.0 && exponent == 0)
{
/* encode zero length */
return ASN1BEREncLength(enc, 0);
}
/* get sign bit */
if (mantissa < 0.0)
{
sign = 1;
mantissa = -mantissa;
}
else
{
sign = 0;
}
/* encode mantissa */
nmoctets = 0;
while (mantissa != 0.0 && nmoctets < sizeof(mASN1octets))
{
mantissa *= 256.0;
exponent -= 8;
mASN1octets[nmoctets++] = (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);
neoctets = 1;
}
else
if (exponent <= 0x7fff && exponent >= -0x8000)
{
eASN1octets[0] = (ASN1octet_t)(exponent >> 8);
eASN1octets[1] = (ASN1octet_t)(exponent);
neoctets = 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);
neoctets = 3;
head |= 0x02;
}
else
{
eASN1octets[0] = 4; /* XXX does not work if ASN1int32_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);
neoctets = 5;
head |= 0x03;
}
/* encode length into first octet */
len = 1 + neoctets + nmoctets;
if (ASN1BEREncLength(enc, len))
{
/* put head octet, mantissa and exponent */
*enc->pos++ = head;
CopyMemory(enc->pos, eASN1octets, neoctets);
enc->pos += neoctets;
CopyMemory(enc->pos, mASN1octets, nmoctets);
enc->pos += nmoctets;
return 1;
}
}
else
{
ASN1EncSetError(enc, ASN1_ERR_BADREAL);
}
}
/* finished */
return 0;
}
#endif // ENABLE_DOUBLE
#ifdef ENABLE_REAL
/* encode a real value */
int ASN1BEREncReal(ASN1encoding_t enc, ASN1uint32_t tag, ASN1real_t *val)
{
ASN1intx_t mantissa;
ASN1intx_t exponent;
ASN1intx_t help;
ASN1uint32_t nmoctets;
ASN1uint32_t neoctets;
ASN1octet_t head;
ASN1uint32_t sign;
ASN1uint32_t len;
ASN1octet_t mASN1octets[256]; /* should be enough */
ASN1octet_t eASN1octets[256]; /* should be enough */
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* check for PLUS_INFINITY */
if (val->type == eReal_PlusInfinity)
{
/* encode length */
if (ASN1BEREncLength(enc, 1))
{
/* encode value */
*enc->pos++ = 0x40;
return 1;
}
}
else
/* check for MINUS_INFINITY */
if (val->type == eReal_MinusInfinity)
{
/* encode length */
if (ASN1BEREncLength(enc, 1))
{
/* encode value */
*enc->pos++ = 0x41;
return 1;
}
}
/* encode normal real value */
else
{
/* check for zero value */
if (!ASN1intx_cmp(&val->mantissa, &ASN1intx_0))
{
/* encode zero length */
return ASN1BEREncLength(enc, 0);
}
/* get sign bit */
if (val->mantissa.value[0] > 0x7f)
{
sign = 1;
ASN1intx_neg(&mantissa, &val->mantissa);
}
else
{
sign = 0;
if (! ASN1intx_dup(&mantissa, &val->mantissa))
{
return 0;
}
}
if (! ASN1intx_dup(&exponent, &val->exponent))
{
return 0;
}
/* encode mantissa */
nmoctets = ASN1intx_uoctets(&mantissa);
if (nmoctets < 256)
{
CopyMemory(mASN1octets,
mantissa.value + mantissa.length - nmoctets,
nmoctets);
ASN1intx_setuint32(&help, 8 * nmoctets);
ASN1intx_sub(&exponent, &exponent, &help);
ASN1intx_free(&mantissa);
ASN1intx_free(&help);
/* encode exponent and create head octet of encoded value */
neoctets = ASN1intx_octets(&exponent);
if (neoctets < 256)
{
CopyMemory(mASN1octets,
val->exponent.value + val->exponent.length - neoctets,
neoctets);
ASN1intx_free(&exponent);
head = (ASN1octet_t) (0x80 | (sign << 6) | (neoctets - 1));
/* encode length into first octet */
len = 1 + neoctets + nmoctets;
if (ASN1BEREncLength(enc, len))
{
/* put head octet, mantissa and exponent */
*enc->pos++ = head;
CopyMemory(enc->pos, eASN1octets, neoctets);
enc->pos += neoctets;
CopyMemory(enc->pos, mASN1octets, nmoctets);
enc->pos += nmoctets;
return 1;
}
}
else
{
ASN1intx_free(&exponent);
ASN1EncSetError(enc, ASN1_ERR_LARGE);
}
}
else
{
ASN1intx_free(&mantissa);
ASN1intx_free(&help);
ASN1EncSetError(enc, ASN1_ERR_LARGE);
}
}
}
/* finished */
return 0;
}
#endif // ENABLE_REAL
#ifdef ENABLE_EMBEDDED_PDV
/* encode an embedded pdv value */
int ASN1BEREncEmbeddedPdv(ASN1encoding_t enc, ASN1uint32_t tag, ASN1embeddedpdv_t *val)
{
ASN1uint32_t index;
ASN1uint32_t flag;
/* search identification */
if (!ASN1EncSearchEmbeddedPdvIdentification(((ASN1INTERNencoding_t) enc)->parent,
&val->identification, &index, &flag))
return 0;
if (index > 255 ||
(val->data_value.o == ASN1embeddedpdv_data_value_encoded_o &&
(val->data_value.u.encoded.length & 7))) {
flag = 1;
}
if (flag)
{
ASN1uint32_t nLenOff_, nLenOff0, nLenOff1;
/* EP-A encoding: */
/* encode as construct value */
if (!ASN1BEREncExplicitTag(enc, tag, &nLenOff_))
return 0;
/* encode index */
if (!ASN1BEREncU32(enc, 0x80000000, index))
return 0;
/* encode tag of identification */
if (!ASN1BEREncExplicitTag(enc, 0x80000001, &nLenOff0))
return 0;
/* encode identification */
switch (val->identification.o)
{
case ASN1embeddedpdv_identification_syntaxes_o:
if (!ASN1BEREncExplicitTag(enc, 0x80000000, &nLenOff1))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000000,
&val->identification.u.syntaxes.abstract))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.syntaxes.transfer))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff1))
return 0;
break;
case ASN1embeddedpdv_identification_syntax_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.syntax))
return 0;
break;
case ASN1embeddedpdv_identification_presentation_context_id_o:
if (!ASN1BEREncU32(enc, 0x80000002,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1embeddedpdv_identification_context_negotiation_o:
if (!ASN1BEREncExplicitTag(enc, 0x80000003, &nLenOff1))
return 0;
if (!ASN1BEREncU32(enc, 0x80000000, val->
identification.u.context_negotiation.presentation_context_id))
return 0;
if (!ASN1BEREncObjectIdentifier(enc, 0x80000001,
&val->identification.u.context_negotiation.transfer_syntax))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff1))
return 0;
break;
case ASN1embeddedpdv_identification_transfer_syntax_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x80000004,
&val->identification.u.transfer_syntax))
return 0;
break;
case ASN1embeddedpdv_identification_fixed_o:
if (!ASN1BEREncNull(enc, 0x80000005))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* end of identification */
if (!ASN1BEREncEndOfContents(enc, nLenOff0))
return 0;
/* encode data value */
switch (val->data_value.o)
{
case ASN1embeddedpdv_data_value_notation_o:
if (!ASN1BEREncBitString(enc, 0x80000002,
val->data_value.u.notation.length * 8,
val->data_value.u.notation.encoded))
return 0;
break;
case ASN1embeddedpdv_data_value_encoded_o:
if (!ASN1BEREncBitString(enc, 0x80000002,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* end of embedded pdv */
if (!ASN1BEREncEndOfContents(enc, nLenOff_))
return 0;
}
else
{
/* EP-B encoding: */
/* encode tag */
if (!ASN1BEREncTag(enc, tag))
return 0;
/* encode data value */
switch (val->data_value.o)
{
case ASN1embeddedpdv_data_value_notation_o:
if (!ASN1BEREncLength(enc,
val->data_value.u.notation.length + 1))
return 0;
*enc->pos++ = (ASN1octet_t) index;
CopyMemory(enc->pos, val->data_value.u.notation.encoded,
val->data_value.u.notation.length);
enc->pos += val->data_value.u.notation.length;
break;
case ASN1embeddedpdv_data_value_encoded_o:
if (!ASN1BEREncLength(enc,
val->data_value.u.encoded.length / 8 + 1))
return 0;
*enc->pos++ = (ASN1octet_t) index;
CopyMemory(enc->pos, val->data_value.u.encoded.value,
val->data_value.u.encoded.length / 8);
enc->pos += val->data_value.u.encoded.length / 8;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
}
return 1;
}
#endif // ENABLE_EMBEDDED_PDV
#ifdef ENABLE_EXTERNAL
/* encode an external value */
int ASN1BEREncExternal(ASN1encoding_t enc, ASN1uint32_t tag, ASN1external_t *val)
{
ASN1uint32_t t;
ASN1uint32_t nLenOff_, nLenOff0;
if (!val->data_value_descriptor)
val->o[0] &= ~0x80;
/* encode tag */
if (!ASN1BEREncExplicitTag(enc, tag, &nLenOff_))
return 0;
/* encode identification */
switch (val->identification.o) {
case ASN1external_identification_syntax_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x6,
&val->identification.u.syntax))
return 0;
break;
case ASN1external_identification_presentation_context_id_o:
if (!ASN1BEREncU32(enc, 0x2,
val->identification.u.presentation_context_id))
return 0;
break;
case ASN1external_identification_context_negotiation_o:
if (!ASN1BEREncObjectIdentifier(enc, 0x6,
&val->identification.u.context_negotiation.transfer_syntax))
return 0;
if (!ASN1BEREncU32(enc, 0x2,
val->identification.u.context_negotiation.presentation_context_id))
return 0;
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* encode data value descriptor if present */
if (val->o[0] & 0x80) {
t = My_lstrlenA(val->data_value_descriptor);
if (!ASN1BEREncCharString(enc, 0x7, t, val->data_value_descriptor))
return 0;
}
/* encode data value */
switch (val->data_value.o)
{
case ASN1external_data_value_notation_o:
if (!ASN1BEREncExplicitTag(enc, 0, &nLenOff0))
return 0;
if (!ASN1BEREncOpenType(enc, &val->data_value.u.notation))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff0))
return 0;
break;
case ASN1external_data_value_encoded_o:
if (!(val->data_value.u.encoded.length & 7))
{
if (!ASN1BEREncExplicitTag(enc, 1, &nLenOff0))
return 0;
if (!ASN1BEREncOctetString(enc, 0x4,
val->data_value.u.encoded.length / 8,
val->data_value.u.encoded.value))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff0))
return 0;
}
else
{
if (!ASN1BEREncExplicitTag(enc, 2, &nLenOff0))
return 0;
if (!ASN1BEREncBitString(enc, 0x3,
val->data_value.u.encoded.length,
val->data_value.u.encoded.value))
return 0;
if (!ASN1BEREncEndOfContents(enc, nLenOff0))
return 0;
}
break;
default:
ASN1EncSetError(enc, ASN1_ERR_INTERNAL);
return 0;
}
/* end of external value */
return ASN1BEREncEndOfContents(enc, nLenOff_);
}
#endif // ENABLE_EXTERNAL
/* encode a generalized time value */
int ASN1BEREncGeneralizedTime(ASN1encoding_t enc, ASN1uint32_t tag, ASN1generalizedtime_t *val)
{
char time[32];
ASN1generalizedtime2string(time, val);
return ASN1BEREncCharString(enc, tag, My_lstrlenA(time), time);
}
/* encode a generalized time value (CER) */
int ASN1CEREncGeneralizedTime(ASN1encoding_t enc, ASN1uint32_t tag, ASN1generalizedtime_t *val)
{
char time[32];
ASN1generalizedtime2string(time, val);
return ASN1CEREncCharString(enc, tag, My_lstrlenA(time), time);
}
/* encode a signed integer value */
int ASN1BEREncS32(ASN1encoding_t enc, ASN1uint32_t tag, ASN1int32_t val)
{
if (ASN1BEREncTag(enc, tag))
{
if (val >= -0x8000 && val < 0x8000)
{
if (val >= -0x80 && val < 0x80)
{
if (ASN1BEREncLength(enc, 1))
{
*enc->pos++ = (ASN1octet_t)(val);
return 1;
}
}
else
{
if (ASN1BEREncLength(enc, 2))
{
*enc->pos++ = (ASN1octet_t)(val >> 8);
*enc->pos++ = (ASN1octet_t)(val);
return 1;
}
}
}
else
{
if (val >= -0x800000 && val < 0x800000)
{
if (ASN1BEREncLength(enc, 3))
{
*enc->pos++ = (ASN1octet_t)(val >> 16);
*enc->pos++ = (ASN1octet_t)(val >> 8);
*enc->pos++ = (ASN1octet_t)(val);
return 1;
}
}
else
{
if (ASN1BEREncLength(enc, 4))
{
*enc->pos++ = (ASN1octet_t)(val >> 24);
*enc->pos++ = (ASN1octet_t)(val >> 16);
*enc->pos++ = (ASN1octet_t)(val >> 8);
*enc->pos++ = (ASN1octet_t)(val);
return 1;
}
}
}
}
return 0;
}
/* encode a intx_t integer value */
int ASN1BEREncSX(ASN1encoding_t enc, ASN1uint32_t tag, ASN1intx_t *val)
{
ASN1uint32_t cb;
ASN1octet_t *p;
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
// strip out leading 0 and ff.
for (cb = val->length, p = val->value; cb > 1; cb--, p++)
{
// break if not 00 nor FF
if (*p && *p != 0xFF)
{
break;
}
// break if 00 FF
if ((! *p) && (*(p+1) & 0x80))
{
break;
}
// break if FF 7F
if (*p == 0xFF && (!(*(p+1) & 0x80)))
{
break;
}
}
/* encode length */
if (ASN1BEREncLength(enc, cb))
{
/* copy value */
CopyMemory(enc->pos, p, cb);
enc->pos += cb;
return 1;
}
}
return 0;
}
/* encode a multibyte string value */
int ASN1BEREncZeroMultibyteString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1ztcharstring_t val)
{
return ASN1BEREncCharString(enc, tag, My_lstrlenA(val), val);
}
int ASN1BEREncMultibyteString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1charstring_t *val)
{
return ASN1BEREncCharString(enc, tag, val->length, val->value);
}
/* encode a multibyte string value (CER) */
int ASN1CEREncZeroMultibyteString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1ztcharstring_t val)
{
return ASN1CEREncCharString(enc, tag, My_lstrlenA(val), val);
}
int ASN1CEREncMultibyteString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1charstring_t *val)
{
return ASN1CEREncCharString(enc, tag, val->length, val->value);
}
/* encode a null value */
int ASN1BEREncNull(ASN1encoding_t enc, ASN1uint32_t tag)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode zero length */
return ASN1BEREncLength(enc, 0);
}
return 0;
}
// encode an oid node s to buffer pointed by p
ASN1octet_t *_BEREncOidNode(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 value */
int ASN1BEREncObjectIdentifier(ASN1encoding_t enc, ASN1uint32_t tag, ASN1objectidentifier_t *val)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
ASN1objectidentifier_t obj = *val;
ASN1uint32_t i, s, l, *v;
ASN1octet_t *data, *p;
l = GetObjectIdentifierCount(obj);
if (l)
{
/* convert object identifier to octets */
p = data = (ASN1octet_t *)MemAlloc(l * 5, _ModName(enc)); /* max. 5 octets/subelement */
if (p)
{
int rc;
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 = _BEREncOidNode(p, s);
} // for
/* encode length */
rc = ASN1BEREncLength(enc, (ASN1uint32_t) (p - data));
if (rc)
{
/* copy value */
CopyMemory(enc->pos, data, p - data);
enc->pos += p - data;
}
MemFree(data);
return rc;
}
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
} // if (l)
/* encode zero length */
return ASN1BEREncLength(enc, 0);
}
return 0;
}
/* encode an object identifier value */
int ASN1BEREncObjectIdentifier2(ASN1encoding_t enc, ASN1uint32_t tag, ASN1objectidentifier2_t *val)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
ASN1uint32_t i, s;
ASN1octet_t *data, *p;
if (val->count)
{
/* convert object identifier to octets */
p = data = (ASN1octet_t *)MemAlloc(val->count * 5, _ModName(enc)); /* max. 5 octets/subelement */
if (p)
{
int rc;
for (i = 0; i < val->count; i++)
{
s = val->value[i];
if (!i && val->count > 1)
{
i++;
s = s * 40 + val->value[i];
}
p = _BEREncOidNode(p, s);
} // for
/* encode length */
rc = ASN1BEREncLength(enc, (ASN1uint32_t) (p - data));
if (rc)
{
/* copy value */
CopyMemory(enc->pos, data, p - data);
enc->pos += p - data;
}
MemFree(data);
return rc;
}
ASN1EncSetError(enc, ASN1_ERR_MEMORY);
return 0;
} // if (l)
/* encode zero length */
return ASN1BEREncLength(enc, 0);
}
return 0;
}
/* encode an octet string value (CER) */
int ASN1CEREncOctetString(ASN1encoding_t enc, ASN1uint32_t tag, ASN1uint32_t len, ASN1octet_t *val)
{
ASN1uint32_t n;
if (len <= 1000)
{
/* encode tag */
if (ASN1BEREncTag(enc, tag))
{
/* encode length */
if (ASN1BEREncLength(enc, len))
{
/* copy value */
CopyMemory(enc->pos, val, len);
enc->pos += len;
return 1;
}
}
}
else
{
ASN1uint32_t nLenOff;
/* encode value as constructed, using segments of 1000 octets */
if (ASN1BEREncExplicitTag(enc, tag, &nLenOff))
{
while (len)
{
n = len > 1000 ? 1000 : len;
if (ASN1BEREncTag(enc, 0x4))
{
if (ASN1BEREncLength(enc, n))
{
CopyMemory(enc->pos, val, n);
enc->pos += n;
val += n;
len -= n;
}
else
{
return 0;
}
}
else
{
return 0;
}
}
return ASN1BEREncEndOfContents(enc, nLenOff);
}
}
return 0;
}
/* encode an open type value */
int ASN1BEREncOpenType(ASN1encoding_t enc, ASN1open_t *val)
{
if (ASN1BEREncCheck(enc, val->length))
{
/* copy value */
CopyMemory(enc->pos, val->encoded, val->length);
enc->pos += val->length;
return 1;
}
return 0;
}
/* remove trailing zero bits from bit string */
int ASN1BEREncRemoveZeroBits(ASN1uint32_t *nbits, ASN1octet_t *val)
{
ASN1uint32_t n;
int i;
/* get value */
n = *nbits;
/* let val point to last ASN1octet used */
val += (n - 1) / 8;
/* check if broken ASN1octet consist out of zero bits */
if ((n & 7) && !(*val & bitmsk2[n & 7]))
{
n &= ~7;
val--;
}
/* scan complete ASN1octets (memcchr missing ...) */
if (!(n & 7))
{
while (n && !*val)
{
n -= 8;
val--;
}
}
/* scan current ASN1octet bit after bit */
if (n)
{
for (i = (n - 1) & 7; i >= 0; i--)
{
if (*val & (0x80 >> i))
break;
n--;
}
}
/* return real bitstring len */
*nbits = n;
return 1;
}
/* encode an utc time value */
int ASN1BEREncUTCTime(ASN1encoding_t enc, ASN1uint32_t tag, ASN1utctime_t *val)
{
char time[32];
ASN1utctime2string(time, val);
return ASN1BEREncCharString(enc, tag, My_lstrlenA(time), time);
}
/* encode an utc time value (CER) */
int ASN1CEREncUTCTime(ASN1encoding_t enc, ASN1uint32_t tag, ASN1utctime_t *val)
{
char time[32];
ASN1utctime2string(time, val);
return ASN1CEREncCharString(enc, tag, My_lstrlenA(time), time);
}
/* end of encoding */
int ASN1BEREncFlush(ASN1encoding_t 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 ASN1BEREncCheck(enc, 1);
}
#endif // ENABLE_BER