windows-nt/Source/XPSP1/NT/ds/security/asn1/asn1c/intx.c

914 lines
24 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. */
// lonchanc: we seem to have a significant amount of memory leak
// while dealing with real number and unlimited integers.
// we definitely want to re-visit all the following routines carefully
// in the future.
// moreover, we need to make sure all the memory allocation and free
// are either using encoding and decoding memory manager or kernel one.
// need to make sure we do not mix them together.
#include "precomp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* builtin intx values */
ASN1octet_t ASN1intx_0_[] = { 0 };
ASN1intx_t ASN1intx_0 = { 1, ASN1intx_0_ };
ASN1octet_t ASN1intx_1_[] = { 1 };
ASN1intx_t ASN1intx_1 = { 1, ASN1intx_1_ };
ASN1octet_t ASN1intx_2_[] = { 2 };
ASN1intx_t ASN1intx_2 = { 1, ASN1intx_2_ };
ASN1octet_t ASN1intx_16_[] = { 16 };
ASN1intx_t ASN1intx_16 = { 1, ASN1intx_16_ };
ASN1octet_t ASN1intx_256_[] = { 1, 0 };
ASN1intx_t ASN1intx_256 = { 2, ASN1intx_256_ };
ASN1octet_t ASN1intx_64K_[] = { 1, 0, 0 };
ASN1intx_t ASN1intx_64K = { 3, ASN1intx_64K_ };
ASN1octet_t ASN1intx_1G_[] = { 64, 0, 0, 0 };
ASN1intx_t ASN1intx_1G = { 4, ASN1intx_1G_ };
/* add two intx values */
void
ASN1intx_add(ASN1intx_t *dst, ASN1intx_t *arg1, ASN1intx_t *arg2)
{
ASN1octet_t *v;
int l;
int s1, s2;
int o1, o2;
int i;
int c;
int w;
/* get signs */
s1 = arg1->value[0] > 0x7f ? 0xff : 0x00;
s2 = arg2->value[0] > 0x7f ? 0xff : 0x00;
/* result length will be <= l */
l = arg1->length > arg2->length ? arg1->length + 1 : arg2->length + 1;
/* offset into values */
o1 = l - arg1->length;
o2 = l - arg2->length;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* clear carry bit */
c = 0;
/* add octet by octet */
for (i = l - 1; i >= 0; i--) {
w = (i >= o1 ? arg1->value[i - o1] : s1) + (i >= o2 ? arg2->value[i - o2] : s2) + c;
v[i] = (ASN1octet_t)w;
c = w > 0xff;
}
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
dst->length = l - i;
dst->value = (ASN1octet_t *)malloc(l - i);
memcpy(dst->value, v + i, l - i);
free(v);
}
/* substract two intx values */
void
ASN1intx_sub(ASN1intx_t *dst, ASN1intx_t *arg1, ASN1intx_t *arg2)
{
ASN1octet_t *v;
int l;
int s1, s2;
int o1, o2;
int i;
int c;
int w;
/* get signs */
s1 = arg1->value[0] > 0x7f ? 0xff : 0x00;
s2 = arg2->value[0] > 0x7f ? 0xff : 0x00;
/* result length will be <= l */
l = arg1->length > arg2->length ? arg1->length + 1 : arg2->length + 1;
/* offset into values */
o1 = l - arg1->length;
o2 = l - arg2->length;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* clear borrow bit */
c = 0;
/* substract octet by octet */
for (i = l - 1; i >= 0; i--) {
w = (i >= o1 ? arg1->value[i - o1] : s1) - (i >= o2 ? arg2->value[i - o2] : s2) - c;
v[i] = (ASN1octet_t)w;
c = w < 0;
}
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
// lonchanc: do we forget to free dst->value???
// in case that dst and arg1 are identical. for instance,
// ASN1BEREncReal() calls ASN1intx_sub(&exponent, &exponent, &help);
/* allocate and copy result */
dst->length = l - i;
dst->value = (ASN1octet_t *)malloc(l - i);
memcpy(dst->value, v + i, l - i);
free(v);
}
/* add one octet to an intx */
void
ASN1intx_addoctet(ASN1intx_t *dst, ASN1intx_t *arg1, ASN1octet_t arg2)
{
ASN1octet_t *v;
int l;
int i;
int c;
int w;
/* result length will be <= l */
l = arg1->length + 1;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* add octet by octet */
c = arg2;
for (i = l - 2; i >= 0; i--) {
w = arg1->value[i] + c;
v[i + 1] = (ASN1octet_t)w;
c = (w > 0xff);
}
v[0] = arg1->value[0] > 0x7f ? (ASN1octet_t)(0xff + c) : (ASN1octet_t)c;
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
dst->length = l - i;
dst->value = (ASN1octet_t *)malloc(l - i);
memcpy(dst->value, v + i, l - i);
free(v);
}
/* substract one octet to an intx */
void
ASN1intx_suboctet(ASN1intx_t *dst, ASN1intx_t *arg1, ASN1octet_t arg2)
{
ASN1octet_t *v;
int l;
int i;
int c;
int w;
/* result length will be <= l */
l = arg1->length + 1;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* substract octet by octet */
c = arg2;
for (i = l - 2; i >= 0; i--) {
w = arg1->value[i] - c;
v[i + 1] = (ASN1octet_t)w;
c = (w < 0);
}
v[0] = arg1->value[0] > 0x7f ? (ASN1octet_t)(0xff - c) : (ASN1octet_t)c;
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
dst->length = l - i;
dst->value = (ASN1octet_t *)malloc(l - i);
memcpy(dst->value, v + i, l - i);
free(v);
}
/* multiply intx by an octet */
void
ASN1intx_muloctet(ASN1intx_t *dst, ASN1intx_t *arg1, ASN1octet_t arg2)
{
ASN1octet_t *v;
int l;
int c;
int i;
int w;
/* result length will be <= l */
l = arg1->length + 1;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* multiply octet by octet */
c = 0;
for (i = l - 2; i >= 0; i--) {
w = arg1->value[i] * arg2 + c;
v[i + 1] = (ASN1octet_t)w;
c = w >> 8;
}
v[0] = (ASN1octet_t)(arg1->value[0] > 0x7f ? 0xff * arg2 + c : c);
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
dst->length = l - i;
dst->value = (ASN1octet_t *)malloc(l - i);
memcpy(dst->value, v + i, l - i);
free(v);
}
/* increment an intx */
void
ASN1intx_inc(ASN1intx_t *val)
{
ASN1octet_t *v;
int l;
int i;
int w;
/* result length will be <= l */
l = val->length + 1;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* copy value */
memcpy(v + 1, val->value, l - 1);
free(val->value);
v[0] = v[1] > 0x7f ? 0xff : 0x00;
/* increment value */
for (i = l - 1; i >= 0; i--) {
if (++v[i])
break;
}
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
val->length = l - i;
val->value = (ASN1octet_t *)malloc(l - i);
memcpy(val->value, v + i, l - i);
free(v);
}
/* decrement an intx */
void
ASN1intx_dec(ASN1intx_t *val)
{
ASN1octet_t *v;
int l;
int i;
int w;
/* result length will be <= l */
l = val->length + 1;
/* allocate result */
v = (ASN1octet_t *)malloc(l);
/* copy value */
memcpy(v + 1, val->value, l - 1);
free(val->value);
v[0] = v[1] > 0x7f ? 0xff : 0x00;
/* decrement value */
for (i = l - 1; i >= 0; i--) {
if (v[i]--)
break;
}
/* octets which may shall dropped */
w = v[0] > 0x7f ? 0xff : 0x00;
/* count octets that shall be dropped */
for (i = 0; i < l - 1; i++) {
if (v[i] != w)
break;
}
if ((v[i] ^ w) & 0x80)
i--;
/* allocate and copy result */
val->length = l - i;
val->value = (ASN1octet_t *)malloc(l - i);
memcpy(val->value, v + i, l - i);
free(v);
}
/* negate an intx value */
void
ASN1intx_neg(ASN1intx_t *dst, ASN1intx_t *arg)
{
ASN1uint32_t i;
/* duplicate value */
ASN1intx_dup(dst, arg);
/* ones complement */
for (i = 0; i < dst->length; i++)
dst->value[i] = ~dst->value[i];
/* and increment */
ASN1intx_inc(dst);
}
/* returns floor(log2(arg - 1)) */
ASN1uint32_t
ASN1intx_log2(ASN1intx_t *arg)
{
ASN1uint32_t i;
ASN1intx_t v;
ASN1uint32_t n;
ASN1intx_dup(&v, arg);
ASN1intx_dec(&v);
if (v.value[0] > 0x7f) {
ASN1intx_free(&v);
return 0;
}
for (i = 0; i < v.length; i++) {
if (v.value[i])
break;
}
if (i >= v.length) {
n = 0;
} else if (v.value[i] > 0x7f) {
n = 8 * (v.length - i - 1) + 8;
} else if (v.value[i] > 0x3f) {
n = 8 * (v.length - i - 1) + 7;
} else if (v.value[i] > 0x1f) {
n = 8 * (v.length - i - 1) + 6;
} else if (v.value[i] > 0x0f) {
n = 8 * (v.length - i - 1) + 5;
} else if (v.value[i] > 0x07) {
n = 8 * (v.length - i - 1) + 4;
} else if (v.value[i] > 0x03) {
n = 8 * (v.length - i - 1) + 3;
} else if (v.value[i] > 0x01) {
n = 8 * (v.length - i - 1) + 2;
} else {
n = 8 * (v.length - i - 1) + 1;
}
ASN1intx_free(&v);
return n;
}
/* returns floor(log2(arg - 1)) */
ASN1uint32_t
ASN1uint32_log2(ASN1uint32_t arg)
{
ASN1uint32_t i;
arg--;
for (i = 32; i != 0; i--) {
if (arg & (1 << (i - 1)))
break;
}
return i;
}
/* returns floor(log256(arg - 1)) */
ASN1uint32_t
ASN1intx_log256(ASN1intx_t *arg)
{
ASN1uint32_t i;
ASN1intx_t v;
ASN1intx_dup(&v, arg);
ASN1intx_dec(&v);
if (v.value[0] > 0x7f) {
ASN1intx_free(&v);
return 0;
}
for (i = 0; i < v.length; i++) {
if (v.value[i])
break;
}
ASN1intx_free(&v);
return v.length - i;
}
/* returns floor(log256(arg - 1)) */
ASN1uint32_t
ASN1uint32_log256(ASN1uint32_t arg)
{
if (arg > 0x10000) {
if (arg > 0x1000000)
return 4;
return 3;
}
if (arg > 0x100)
return 2;
if (arg > 1)
return 1;
return 0;
}
/* compare two intx values; return 0 iff equal */
ASN1int32_t
ASN1intx_cmp(ASN1intx_t *arg1, ASN1intx_t *arg2)
{
int s1, s2;
int o1, o2;
int l;
int i;
int d;
s1 = arg1->value[0] > 0x7f ? 0xff : 0x00;
s2 = arg2->value[0] > 0x7f ? 0xff : 0x00;
if (s1 != s2)
return s1 == 0xff ? -1 : 1;
l = arg1->length > arg2->length ? arg1->length : arg2->length;
o1 = l - arg1->length;
o2 = l - arg2->length;
for (i = 0; i < l; i++) {
d = (i >= o1 ? arg1->value[i - o1] : s1) - (i >= o2 ? arg2->value[i - o2] : s2);
if (d)
return d;
}
return 0;
}
/* create an intx value from an uint32 value */
void
ASN1intx_setuint32(ASN1intx_t *dst, ASN1uint32_t val)
{
ASN1octet_t o[5], *v = o;
int n = 5;
v[0] = 0;
v[1] = (ASN1octet_t)(val >> 24);
v[2] = (ASN1octet_t)(val >> 16);
v[3] = (ASN1octet_t)(val >> 8);
v[4] = (ASN1octet_t)(val);
while (n > 1 && !*v && v[1] <= 0x7f) {
n--;
v++;
}
dst->length = n;
dst->value = (ASN1octet_t *)malloc(n);
memcpy(dst->value, v, n);
}
/* create an intx value from an int32 value */
void
ASN1intx_setint32(ASN1intx_t *dst, ASN1int32_t val)
{
ASN1octet_t o[5], *v = o;
int n = 5;
v[0] = (ASN1octet_t)(val < 0 ? 0xff : 0x00);
v[1] = (ASN1octet_t)(val >> 24);
v[2] = (ASN1octet_t)(val >> 16);
v[3] = (ASN1octet_t)(val >> 8);
v[4] = (ASN1octet_t)(val);
while (n > 1 && ((!*v && v[1] <= 0x7f) || (*v == 0xff && v[1] > 0x7f))) {
n--;
v++;
}
dst->length = n;
dst->value = (ASN1octet_t *)malloc(n);
memcpy(dst->value, v, n);
}
/* copy constructor */
void
ASN1intx_dup(ASN1intx_t *dst, ASN1intx_t *val)
{
dst->length = val->length;
dst->value = (ASN1octet_t *)malloc(val->length);
memcpy(dst->value, val->value, val->length);
}
/* free an intx value */
void
ASN1intx_free(ASN1intx_t *val)
{
free(val->value);
}
#ifdef HAS_SIXTYFOUR_BITS
/* convert an intx value to a uint64 value */
ASN1uint64_t
ASN1intx2uint64(ASN1intx_t *val)
{
switch (val->length) {
case 1:
return (ASN1uint64_t)val->value[val->length - 1];
case 2:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
case 3:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16));
case 4:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 4] << 24));
case 5:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32));
case 6:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40));
case 7:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40) |
((ASN1uint64_t)val->value[val->length - 7] << 48));
default:
return (ASN1uint64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40) |
((ASN1uint64_t)val->value[val->length - 7] << 48) |
((ASN1uint64_t)val->value[val->length - 8] << 56));
}
}
#endif
/* check if intx value is a uint64 value */
int
ASN1intxisuint64(ASN1intx_t *val)
{
if (val->value[0] > 0x7f)
return 0;
return ASN1intx_uoctets(val) <= 8;
}
#ifdef HAS_SIXTYFOUR_BITS
/* convert an intx value to a int64 value */
ASN1int64_t
ASN1intx2int64(ASN1intx_t *val)
{
switch (val->length) {
case 1:
return (ASN1int64_t)(ASN1int8_t)val->value[val->length - 1];
case 2:
return (ASN1int64_t)(ASN1int16_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
case 3:
return (ASN1int64_t)(ASN1int32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 3] > 0x7f ?
0xffffffffff000000LL : 0));
case 4:
return (ASN1int64_t)(ASN1int32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 4] << 24));
case 5:
return (ASN1int64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 5] > 0x7f ?
0xffffff0000000000LL : 0));
case 6:
return (ASN1int64_t)(val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40) |
((ASN1uint64_t)val->value[val->length - 6] > 0x7f ?
0xffff000000000000LL : 0));
case 7:
return (ASN1int64_t)((ASN1uint64_t)val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40) |
((ASN1uint64_t)val->value[val->length - 7] << 48) |
((ASN1uint64_t)val->value[val->length - 7] > 0x7f ?
0xff00000000000000LL : 0));
default:
return (ASN1int64_t)((ASN1uint64_t)val->value[val->length - 1] |
((ASN1uint64_t)val->value[val->length - 2] << 8) |
((ASN1uint64_t)val->value[val->length - 3] << 16) |
((ASN1uint64_t)val->value[val->length - 4] << 24) |
((ASN1uint64_t)val->value[val->length - 5] << 32) |
((ASN1uint64_t)val->value[val->length - 6] << 40) |
((ASN1uint64_t)val->value[val->length - 7] << 48) |
((ASN1uint64_t)val->value[val->length - 8] << 56));
}
}
#endif
/* check if intx value is an int64 value */
int
ASN1intxisint64(ASN1intx_t *val)
{
return ASN1intx_octets(val) <= 8;
}
/* convert intx value to uint32 value */
ASN1uint32_t
ASN1intx2uint32(ASN1intx_t *val)
{
switch (val->length) {
case 1:
return (ASN1uint32_t)val->value[val->length - 1];
case 2:
return (ASN1uint32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
case 3:
return (ASN1uint32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16));
default:
return (ASN1uint32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 4] << 24));
}
}
/* check if intx value is an uint32 value */
int
ASN1intxisuint32(ASN1intx_t *val)
{
if (val->value[0] > 0x7f)
return 0;
return ASN1intx_uoctets(val) <= 4;
}
/* convert intx value to int32 value */
ASN1int32_t
ASN1intx2int32(ASN1intx_t *val)
{
switch (val->length) {
case 1:
return (ASN1int32_t)(ASN1int8_t)val->value[val->length - 1];
case 2:
return (ASN1int32_t)(ASN1int16_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
case 3:
return (ASN1int32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 3] > 0x7f ?
0xff000000 : 0));
default:
return (ASN1int32_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8) |
((ASN1uint32_t)val->value[val->length - 3] << 16) |
((ASN1uint32_t)val->value[val->length - 4] << 24));
}
}
/* check if intx value is an int32 value */
int
ASN1intxisint32(ASN1intx_t *val)
{
return ASN1intx_octets(val) <= 4;
}
/* convert intx value to uint16 value */
ASN1uint16_t
ASN1intx2uint16(ASN1intx_t *val)
{
if (val->length == 1)
return (ASN1uint16_t)val->value[val->length - 1];
return (ASN1uint16_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
}
/* check if intx value is an uint16 value */
int
ASN1intxisuint16(ASN1intx_t *val)
{
if (val->value[0] > 0x7f)
return 0;
return ASN1intx_uoctets(val) <= 2;
}
/* convert intx value to int16 value */
ASN1int16_t
ASN1intx2int16(ASN1intx_t *val)
{
if (val->length == 1)
return (ASN1int16_t)(ASN1int8_t)val->value[val->length - 1];
return (ASN1int16_t)(val->value[val->length - 1] |
((ASN1uint32_t)val->value[val->length - 2] << 8));
}
/* check if intx value is an int16 value */
int
ASN1intxisint16(ASN1intx_t *val)
{
return ASN1intx_octets(val) <= 2;
}
/* convert intx value to uint8 value */
ASN1uint8_t
ASN1intx2uint8(ASN1intx_t *val)
{
return (ASN1uint8_t)val->value[val->length - 1];
}
/* check if intx value is an uint8 value */
int
ASN1intxisuint8(ASN1intx_t *val)
{
if (val->value[0] > 0x7f)
return 0;
return ASN1intx_uoctets(val) <= 1;
}
/* convert intx value to int8 value */
ASN1int8_t
ASN1intx2int8(ASN1intx_t *val)
{
return (ASN1int8_t)val->value[val->length - 1];
}
/* check if intx value is an int8 value */
int
ASN1intxisint8(ASN1intx_t *val)
{
return ASN1intx_octets(val) <= 1;
}
/* count octets for a signed encoding of an intx value */
ASN1uint32_t
ASN1intx_octets(ASN1intx_t *val)
{
ASN1uint32_t i;
ASN1uint32_t s;
s = val->value[0] > 0x7f ? 0xff : 0x00;
for (i = 0; i < val->length; i++) {
if (val->value[i] != s)
break;
}
if (i && ((val->value[i] ^ s) & 0x80))
i--;
return val->length - i;
}
/* count octets for unsigned encoding of an unsigned intx value */
ASN1uint32_t
ASN1intx_uoctets(ASN1intx_t *val)
{
ASN1uint32_t i;
for (i = 0; i < val->length; i++) {
if (val->value[i])
break;
}
return val->length - i;
}
/* count octets for signed encoding of an uint32 value */
ASN1uint32_t
ASN1uint32_octets(ASN1uint32_t val)
{
if (val >= 0x8000) {
if (val >= 0x800000) {
if (val >= 0x80000000)
return 5;
return 4;
}
return 3;
}
if (val >= 0x80)
return 2;
return 1;
}
/* count octets for unsigned encoding of an uint32 value */
ASN1uint32_t
ASN1uint32_uoctets(ASN1uint32_t val)
{
if (val >= 0x10000) {
if (val >= 0x1000000)
return 4;
return 3;
}
if (val >= 0x100)
return 2;
return 1;
}
/* count octets for signed encoding of an int32 value */
ASN1uint32_t
ASN1int32_octets(ASN1int32_t val)
{
if (val >= 0) {
if (val >= 0x8000) {
if (val >= 0x800000)
return 4;
return 3;
}
if (val >= 0x80)
return 2;
return 1;
}
if (val < -0x8000) {
if (val < -0x800000)
return 4;
return 3;
}
if (val < -0x80)
return 2;
return 1;
}
/* convert an intx value into a double */
double
ASN1intx2double(ASN1intx_t *val)
{
double ret;
ASN1uint32_t i;
if (val->value[0] > 0x7f)
ret = (double)(val->value[0] - 0x100);
else
ret = (double)val->value[0];
for (i = 1; i < val->length; i++) {
ret = ret * 256.0 + (double)val->value[i];
}
return ret;
}