Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2003 - 2005 Pekka Riikonen
+ Copyright (C) 2003 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-#include "silcincludes.h"
+#include "silc.h"
#include "silcasn1.h"
#include "silcber.h"
+#define SILC_ASN1_BUFFER_FREE(b, stack) if (!stack) silc_buffer_purge(b);
+#define SILC_ASN1_STACK(stack, asn1) stack ? stack : asn1->orig_stack
+
/************************** ASN.1 Encoder routines **************************/
/* Encode string from UTF-8 string to other string encodings. Encodes
goto fail; \
} \
silc_stack_push(asn1->stack2, &frame); \
- s = silc_smalloc_ua(stack2, s_len + 1); \
+ s = silc_smalloc(stack2, s_len + 1); \
if (s) { \
silc_utf8_decode(d, d_len, (enc), s, s_len); \
s[s_len] = '\0'; \
} \
len = silc_ber_encoded_len(tag, s_len, indef); \
- dest = silc_buffer_srealloc_size(stack1, dest, \
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest, \
silc_buffer_truelen(dest) + len); \
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE, \
tag, s, s_len, indef); \
indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
/* By default UNIVERSAL is implied unless the following conditions
- are met when CONTEXT will apply. */
+ are met when CONTEXT will apply. For SILC_ASN1_TAG_ANY_PRIMITIVE
+ the class is changed only if flags dictate it. */
if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
- if (tag != type ||
- opts & SILC_ASN1_IMPLICIT ||
- opts & SILC_ASN1_EXPLICIT)
- ber_class = SILC_BER_CLASS_CONTEXT;
+ if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
+ if (opts & SILC_ASN1_IMPLICIT ||
+ opts & SILC_ASN1_EXPLICIT)
+ ber_class = SILC_BER_CLASS_CONTEXT;
+ } else {
+ if (tag != type ||
+ opts & SILC_ASN1_IMPLICIT ||
+ opts & SILC_ASN1_EXPLICIT)
+ ber_class = SILC_BER_CLASS_CONTEXT;
+ }
}
#ifdef SILC_DEBUG
ret = silc_asn1_encoder(asn1, stack2, stack1, type, type,
SILC_BER_CLASS_UNIVERSAL, opts,
&buf, depth + 1, primitive);
- silc_stack_pop(stack2);
if (!ret) {
SILC_LOG_DEBUG(("Error encoding explicit tag"));
+ silc_stack_pop(stack2);
goto fail;
}
/* Encode the explicit tag */
len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
tag, buf.data, silc_buffer_len(&buf), FALSE);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
+ silc_stack_pop(stack2);
if (!ret)
goto fail;
if (primitive) {
/* Now encode with implicit tagging */
len = silc_ber_encoded_len(tag, d_len, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
tag, d, d_len, FALSE);
} else {
/* Copy the data directly into the tree. */
len = silc_buffer_len(node);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
+ if (!dest)
+ goto fail;
silc_buffer_put(dest, node->data, len);
}
break;
}
+ case SILC_ASN1_TAG_ANY_PRIMITIVE:
+ {
+ /* ANY_PRIMITIVE is any primitive in encoded format. */
+ SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
+ if (!prim)
+ break;
+
+ /* Encode the primitive data */
+ len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
+ silc_buffer_truelen(dest) + len);
+ ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
+ tag, prim->data, silc_buffer_len(prim), FALSE);
+ if (!ret)
+ goto fail;
+ break;
+ }
+
case SILC_ASN1_TAG_SEQUENCE:
case SILC_ASN1_TAG_SET:
{
silc_stack_push(stack2, &frame);
ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
ropts, &buf, depth + 1, FALSE);
- silc_stack_pop(stack2);
if (!ret) {
SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
+ silc_stack_pop(stack2);
goto fail;
}
/* Encode the sequence */
len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
tag, buf.data, silc_buffer_len(&buf), indef);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
+ silc_stack_pop(stack2);
if (!ret)
goto fail;
break;
bytes in 1s complement */
} else {
/* Positive */
- len = (silc_mp_sizeinbase(mpint, 2) + 7) / 8;
- len += len & 7 ? 1: 0;
+ len = silc_mp_sizeinbase(mpint, 2);
+ if (!(len & 7))
+ len = ((len + 7) / 8) + 1;
+ else
+ len = (len + 7) / 8;
silc_stack_push(stack2, &frame);
silc_buffer_srealloc_size(stack2, &buf,
silc_buffer_truelen(&buf) + len);
+ buf.data[0] = 0x00;
silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
}
/* Encode the integer */
len = silc_ber_encoded_len(tag, len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, buf.data, silc_buffer_len(&buf), FALSE);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
silc_stack_pop(stack2);
if (!ret)
goto fail;
break;
}
+ case SILC_ASN1_TAG_SHORT_INTEGER:
+ {
+ /* Short Integer */
+ SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
+ SilcMPInt z;
+
+ if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
+ tag = SILC_ASN1_TAG_INTEGER;
+
+ memset(&buf, 0, sizeof(buf));
+
+ silc_stack_push(stack2, &frame);
+ silc_mp_sinit(stack2, &z);
+ silc_mp_set_ui(&z, sint);
+
+ len = silc_mp_sizeinbase(&z, 2);
+ if (!(len & 7))
+ len = ((len + 7) / 8) + 1;
+ else
+ len = (len + 7) / 8;
+ silc_buffer_srealloc_size(stack2, &buf,
+ silc_buffer_truelen(&buf) + len);
+ buf.data[0] = 0x00;
+ silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
+ silc_mp_uninit(&z);
+
+ /* Encode the integer */
+ len = silc_ber_encoded_len(tag, len, indef);
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
+ silc_buffer_truelen(dest) + len);
+ ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
+ tag, buf.data, silc_buffer_len(&buf), FALSE);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
+ silc_stack_pop(stack2);
+ if (!ret)
+ goto fail;
+ break;
+ }
+ break;
+
case SILC_ASN1_TAG_OID:
{
/* Object identifier */
char *cp, *oidstr = va_arg(asn1->ap, char *);
SilcUInt32 words[24], oid, mask;
- int i, c = -1;
+ int i, k, c = 0;
if (!oidstr)
break;
/* Get OID words from the string */
cp = strchr(oidstr, '.');
while (cp) {
- c = sscanf(oidstr, "%lu", (unsigned long *)&oid);
- if (c < 1) {
+ if (sscanf(oidstr, "%lu", &oid) != 1) {
SILC_LOG_DEBUG(("Malformed OID string"));
goto fail;
}
words[c++] = oid;
oidstr = cp + 1;
cp = strchr(oidstr, '.');
+
+ if (!cp) {
+ if (sscanf(oidstr, "%lu", &oid) != 1) {
+ SILC_LOG_DEBUG(("Malformed OID string"));
+ goto fail;
+ }
+ if (c + 1 > sizeof(words) / sizeof(words[0]))
+ goto fail;
+ words[c++] = oid;
+ break;
+ }
}
if (c < 2) {
SILC_LOG_DEBUG(("Malfromed OID string"));
for (i = 2, len = 1; i < c; i++) {
oid = words[i];
if (oid) {
- c = len;
+ k = len;
mask = 0;
while (oid) {
buf.data[len++] = (oid & 0x7f) | mask;
mask |= 0x80;
}
mask = len - 1;
- while (c < mask) {
- oid = buf.data[c];
- buf.data[c] = buf.data[mask];
+ while (k < mask) {
+ oid = buf.data[k];
+ buf.data[k] = buf.data[mask];
buf.data[mask] = oid;
- c++;
+ k++;
mask--;
}
buf.data[len++] = 0x00;
}
- len = silc_ber_encoded_len(tag, len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, buf.data, silc_buffer_len(&buf), FALSE);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
silc_stack_pop(stack2);
if (!ret)
goto fail;
assert(indef == FALSE);
len = silc_ber_encoded_len(tag, 1, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, val, 1, FALSE);
silc_buffer_push(&buf, 1);
len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, buf.data, silc_buffer_len(&buf), indef);
+ SILC_ASN1_BUFFER_FREE(&buf, stack2);
silc_stack_pop(stack2);
if (!ret)
goto fail;
case SILC_ASN1_TAG_NULL:
{
/* Encode empty BER block */
+ SilcBool val = va_arg(asn1->ap, SilcUInt32);
+
assert(indef == FALSE);
+
+ if (!val)
+ break;
+
len = silc_ber_encoded_len(tag, 0, FALSE);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, NULL, 0, FALSE);
if (!ret)
goto fail;
+
break;
}
}
len = silc_ber_encoded_len(tag, strlen(timestr), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, timestr, strlen(timestr), indef);
}
len = silc_ber_encoded_len(tag, strlen(timestr), indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, timestr, strlen(timestr), indef);
}
len = silc_ber_encoded_len(tag, d_len, indef);
- dest = silc_buffer_srealloc_size(stack1, dest,
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
silc_buffer_truelen(dest) + len);
ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
tag, d, d_len, indef);
case SILC_ASN1_TAG_OCTET_STRING:
{
- /* Octet string. We put it in as 8-bit ASCII */
- SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
+ /* Octet string. Put data as is. */
+ unsigned char *d = va_arg(asn1->ap, unsigned char *);
+ SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
+
+ len = silc_ber_encoded_len(tag, d_len, indef);
+ dest = silc_buffer_srealloc_size(SILC_ASN1_STACK(stack1, asn1), dest,
+ silc_buffer_truelen(dest) + len);
+ ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
+ tag, d, d_len, indef);
+ if (!ret)
+ goto fail;
break;
}
SilcAsn1Options opts;
SilcBerClass ber_class;
SilcStackFrame frame1, frame2;
- SilcStack stack1 = NULL;
+ SilcStack stack1 = NULL, orig;
SilcBool ret;
if (!asn1)
va_start(asn1->ap, dest);
+ orig = asn1->orig_stack;
+ asn1->orig_stack = NULL;
+
/* Get the first arguments and call the encoder. */
SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
if (!type) {
va_end(asn1->ap);
- asn1->ap = NULL;
return FALSE;
}
that stack aware calls revert to normal allocation routines. */
stack1 = asn1->stack1;
asn1->stack1 = NULL;
+ asn1->orig_stack = orig;
}
if (o & SILC_ASN1_ACCUMUL) {
if (stack1 && !asn1->stack1)
asn1->stack1 = stack1;
+ asn1->orig_stack = orig;
+
va_end(asn1->ap);
- asn1->ap = NULL;
return ret;
}