ASN1: Fix stack variable overwrite when encoding OID.
[silc.git] / lib / silcasn1 / silcasn1_encode.c
index fb24c0648687beba13ed17346714c0c868f87a1d..986909c4d7348cdd43e4146dc9cb9f217510e381 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2003 - 2006 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
@@ -21,6 +21,8 @@
 #include "silcasn1.h"
 #include "silcber.h"
 
+#define SILC_ASN1_BUFFER_FREE(b, stack) if (!stack) silc_buffer_purge(b);
+
 /************************** ASN.1 Encoder routines **************************/
 
 /* Encode string from UTF-8 string to other string encodings.  Encodes
@@ -36,7 +38,7 @@
     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';                                                   \
@@ -136,10 +138,10 @@ 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;
       }
 
@@ -149,6 +151,8 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
                                       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) {
@@ -184,10 +188,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
            SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
            goto fail;
          }
-         if (enc != SILC_BER_ENC_CONSTRUCTED) {
-           SILC_LOG_DEBUG(("ANY was not constructed type"));
-           goto fail;
-         }
+         assert(enc == SILC_BER_ENC_CONSTRUCTED);
 
          /* Now encode with implicit tagging */
          len = silc_ber_encoded_len(tag, d_len, FALSE);
@@ -240,9 +241,9 @@ 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;
        }
 
@@ -252,6 +253,8 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
                                         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;
@@ -289,12 +292,53 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
                                         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(stack1, 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 */
@@ -307,7 +351,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
        /* Get OID words from the string */
        cp = strchr(oidstr, '.');
        while (cp) {
-         if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
+         if (sscanf(oidstr, "%u", &oid) != 1) {
            SILC_LOG_DEBUG(("Malformed OID string"));
            goto fail;
          }
@@ -318,7 +362,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
          cp = strchr(oidstr, '.');
 
          if (!cp) {
-           if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
+           if (sscanf(oidstr, "%u", &oid) != 1) {
              SILC_LOG_DEBUG(("Malformed OID string"));
              goto fail;
            }
@@ -378,6 +422,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
                                         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;
@@ -427,6 +472,7 @@ silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
                                         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;
@@ -519,8 +565,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(stack1, 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;
       }
 
@@ -650,7 +705,6 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
   SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
   if (!type) {
     va_end(asn1->ap);
-    asn1->ap = NULL;
     return FALSE;
   }
 
@@ -705,7 +759,6 @@ SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
     asn1->stack1 = stack1;
 
   va_end(asn1->ap);
-  asn1->ap = NULL;
 
   return ret;
 }