X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcasn1%2Fsilcasn1_encode.c;h=58dfbf278bcdedbcf62961c4e7b56a2962661f85;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=a0504f55a8ca000e5b6642e899661561f6cc879c;hpb=0f0340b9fbce9704cc7171f8f0104ce9103d2de6;p=silc.git diff --git a/lib/silcasn1/silcasn1_encode.c b/lib/silcasn1/silcasn1_encode.c index a0504f55..58dfbf27 100644 --- a/lib/silcasn1/silcasn1_encode.c +++ b/lib/silcasn1/silcasn1_encode.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - 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 @@ -17,10 +17,13 @@ */ -#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 @@ -36,13 +39,13 @@ 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); \ @@ -56,18 +59,18 @@ is TRUE if this encoder receives one primitive type as argument. If it is a constructed type it must be FALSE value. */ -static bool +static SilcBool silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, SilcAsn1Tag type, SilcAsn1Tag tag, SilcBerClass ber_class, SilcAsn1Options opts, SilcBuffer dest, SilcUInt32 depth, - bool primitive) + SilcBool primitive) { unsigned char *ptr = dest->data; SilcAsn1Tag rtype, rtag; SilcAsn1Options ropts; SilcBerClass rclass; SilcUInt32 len = 0; - bool ret = FALSE, indef; + SilcBool ret = FALSE, indef; SilcBufferStruct buf; SilcStackFrame frame; @@ -91,12 +94,19 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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 @@ -129,19 +139,21 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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) { @@ -181,7 +193,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, /* 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); @@ -190,13 +202,33 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } 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: { @@ -210,18 +242,20 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; @@ -241,40 +275,84 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; } @@ -283,6 +361,17 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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")); @@ -308,7 +397,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; @@ -316,11 +405,11 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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--; } @@ -329,11 +418,12 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; @@ -348,7 +438,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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); @@ -379,10 +469,11 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; @@ -392,14 +483,21 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; } @@ -417,7 +515,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } 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); @@ -440,7 +538,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } 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); @@ -464,7 +562,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, } 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); @@ -475,8 +573,17 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, 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; } @@ -588,25 +695,27 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2, return ret; } -bool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) +SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) { SilcAsn1Tag type, tag; SilcAsn1Options opts; SilcBerClass ber_class; SilcStackFrame frame1, frame2; - SilcStack stack1 = NULL; - bool ret; + SilcStack stack1 = NULL, orig; + SilcBool ret; if (!asn1) return FALSE; 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; } @@ -619,6 +728,7 @@ bool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) that stack aware calls revert to normal allocation routines. */ stack1 = asn1->stack1; asn1->stack1 = NULL; + asn1->orig_stack = orig; } if (o & SILC_ASN1_ACCUMUL) { @@ -660,8 +770,9 @@ bool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...) if (stack1 && !asn1->stack1) asn1->stack1 = stack1; + asn1->orig_stack = orig; + va_end(asn1->ap); - asn1->ap = NULL; return ret; }