GSM SMS: follow-up of gd65b7d5
[metze/wireshark/wip.git] / epan / asn1.c
index 26c59c6ae688db4058c128e76b42a2ff48d50134..81ba856c4b7eca7a694bbf8575f8dc58e52fa356 100644 (file)
@@ -1,21 +1,15 @@
 /* asn1.c
- * Routines for ASN.1 BER dissection
- *
- * $Id$
+ * Common routines for ASN.1
+ * 2007  Anders Broman
  *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
  *
- * Based on "g_asn1.c" from:
- *
- * GXSNMP -- An snmp mangament application
- * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
- * Beholder RMON ethernet network monitor, Copyright (C) 1993 DNPAP group
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * 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 the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * MODULE INFORMATION
- * ------------------
- *     FILE     NAME:       g_asn1.c
- *     SYSTEM   NAME:       ASN1 Basic Encoding
- *     ORIGINAL AUTHOR(S):  Dirk Wisse
- *     VERSION  NUMBER:     1
- *     CREATION DATE:       1990/11/22
- *
- * DESCRIPTION: ASN1 Basic Encoding Rules.
- *
- *              To decode this we must do:
- *
- *              asn1_open (asn1, tvb, offset);
- *              asn1_header_decode (asn1, &end_of_seq, cls, con, tag, def, len);
- *              asn1_header_decode (asn1, &end_of_octs, cls, con, tag, def, len);
- *              asn1_octets_decode (asn1, end_of_octs, str, len);
- *              asn1_header_decode (asn1, &end_of_int, cls, con, tag);
- *              asn1_int_decode (asn1, end_of_int, &integer);
- *              asn1_eoc_decode (asn1, end_of_seq);
- *              asn1_close (asn1, &offset);
- *
- *              For indefinite encoding end_of_seq and &end_of_seq in the
- *              example above should be replaced by NULL.
- *              For indefinite decoding nothing has to be changed.
- *              This can be very useful if you want to decode both
- *              definite and indefinite encodings.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-
-#include <limits.h>
+#include "config.h"
 
 #include <glib.h>
 
-#include <epan/tvbuff.h>
-#include <epan/asn1.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
 #include <epan/emem.h>
+#include <epan/packet.h>
 
-/*
- * NAME:        asn1_open                                   [API]
- * SYNOPSIS:    void asn1_open
- *                  (
- *                      ASN1_SCK *asn1,
- *                      tvbuff_t *tvb,
- *                      int       offset
- *                  )
- * DESCRIPTION: Opens an ASN1 socket.
- *              Parameters:
- *              asn1:   pointer to ASN1 socket.
- *              tvb:    Tvbuff for encoding.
- *              offset: Current offset in tvbuff.
- *              Encoding starts at the end of the buffer, and
- *              proceeds to the beginning.
- * RETURNS:     void
- */
+#include "asn1.h"
 
-void
-asn1_open(ASN1_SCK *asn1, tvbuff_t *tvb, int offset)
-{
-    asn1->tvb = tvb;
-    asn1->offset = offset;
+void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, gboolean aligned, packet_info *pinfo) {
+  memset(actx, '\0', sizeof(*actx));
+  actx->signature = ASN1_CTX_SIGNATURE;
+  actx->encoding = encoding;
+  actx->aligned = aligned;
+  actx->pinfo = pinfo;
 }
 
-/*
- * NAME:        asn1_close                                  [API]
- * SYNOPSIS:    void asn1_close
- *                  (
- *                      ASN1_SCK   *asn1,
- *                      int        *offset
- *                  )
- * DESCRIPTION: Closes an ASN1 socket.
- *              Parameters:
- *              asn1:   pointer to ASN1 socket.
- *              offset: pointer to variable into which current offset is
- *              to be put.
- * RETURNS:     void
- */
-
-void
-asn1_close(ASN1_SCK *asn1, int *offset)
-{
-    *offset = asn1->offset;
+gboolean asn1_ctx_check_signature(asn1_ctx_t *actx) {
+  return actx && (actx->signature == ASN1_CTX_SIGNATURE);
 }
 
-/*
- * NAME:        asn1_octet_decode
- * SYNOPSIS:    int asn1_octet_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guchar   *ch
- *                  )
- * DESCRIPTION: Decodes an octet.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_octet_decode(ASN1_SCK *asn1, guchar *ch)
-{
-    *ch = tvb_get_guint8(asn1->tvb, asn1->offset);
-    asn1->offset++;
-    return ASN1_ERR_NOERROR;
+void asn1_ctx_clean_external(asn1_ctx_t *actx) {
+  memset(&actx->external, '\0', sizeof(actx->external));
+  actx->external.hf_index = -1;
+  actx->external.encoding = -1;
 }
 
-/*
- * NAME:        asn1_tag_get
- * SYNOPSIS:    int asn1_tag_get
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint    *tag
- *                  )
- * DESCRIPTION: Decodes a tag number, combining it with existing tag bits.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-static int
-asn1_tag_get(ASN1_SCK *asn1, guint *tag)
-{
-    int    ret;
-    guchar ch;
-
-    do {
-       ret = asn1_octet_decode (asn1, &ch);
-       if (ret != ASN1_ERR_NOERROR)
-           return ret;
-        *tag <<= 7;
-        *tag |= ch & 0x7F;
-    } while ((ch & 0x80) == 0x80);
-    return ASN1_ERR_NOERROR;
+void asn1_ctx_clean_epdv(asn1_ctx_t *actx) {
+  memset(&actx->embedded_pdv, '\0', sizeof(actx->embedded_pdv));
+  actx->embedded_pdv.hf_index = -1;
+  actx->embedded_pdv.identification = -1;
 }
 
-/*
- * NAME:        asn1_tag_decode
- * SYNOPSIS:    int asn1_tag_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint    *tag
- *                  )
- * DESCRIPTION: Decodes a tag number.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_tag_decode(ASN1_SCK *asn1, guint *tag)
-{
-    *tag = 0;
-    return asn1_tag_get(asn1, tag);
-}
 
-/*
- * NAME:        asn1_id_decode
- * SYNOPSIS:    int asn1_id_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint    *cls,
- *                      guint    *con,
- *                      guint    *tag
- *                  )
- * DESCRIPTION: Decodes an identifier.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_id_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag)
-{
-    int    ret;
-    guchar ch;
+/*--- stack/parameters ---*/
 
-    *tag = 0;
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *cls = (ch & 0xC0) >> 6;
-    *con = (ch & 0x20) >> 5;
-    *tag = (ch & 0x1F);
-    if (*tag == 0x1F) {
-        ret = asn1_tag_decode (asn1, tag);
-        if (ret != ASN1_ERR_NOERROR)
-            return ret;
-    }
-    return ASN1_ERR_NOERROR;
-}
+void asn1_stack_frame_push(asn1_ctx_t *actx, const gchar *name) {
+  asn1_stack_frame_t *frame;
 
-/*
- * NAME:        asn1_id_decode1
- * SYNOPSIS:    int asn1_id_decode1
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint    *tag
- *                  )
- * DESCRIPTION: Decodes an identifier.
- *             Like asn1_id_decode() except that the Class and Constructor
- *             bits are returned in the tag.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_id_decode1(ASN1_SCK *asn1, guint *tag)
-{
-    int    ret;
-    guchar ch;
-
-    *tag = 0;
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-
-    *tag = ch;
-    if ((*tag & 0x1F) == 0x1F) { /* high-tag-number format */
-       *tag = ch >> 5; /* leave just the Class and Constructor bits */
-        ret = asn1_tag_get (asn1, tag);
-        if (ret != ASN1_ERR_NOERROR)
-            return ret;
-    }
-    return ASN1_ERR_NOERROR;
+  frame = ep_new0(asn1_stack_frame_t);
+  frame->name = name;
+  frame->next = actx->stack;
+  actx->stack = frame;
 }
 
-/*
- * NAME:        asn1_length_decode
- * SYNOPSIS:    int asn1_length_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      gboolean *def,
- *                      guint    *len
- *                  )
- * DESCRIPTION: Decodes an ASN1 length.
- *              Parameters:
- *              asn1: pointer to ASN1 socket.
- *              def: Boolean - TRUE if length definite, FALSE if not
- *              len: length, if length is definite
- * DESCRIPTION: Decodes a definite or indefinite length.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_length_decode(ASN1_SCK *asn1, gboolean *def, guint *len)
-{
-    int    ret;
-    guchar ch, cnt;
-
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    if (ch == 0x80)
-        *def = FALSE;          /* indefinite length */
-    else {
-        *def = TRUE;           /* definite length */
-        if (ch < 0x80)
-            *len = ch;
-        else {
-            cnt = (guchar) (ch & 0x7F);
-            *len = 0;
-            while (cnt > 0) {
-                ret = asn1_octet_decode (asn1, &ch);
-                if (ret != ASN1_ERR_NOERROR)
-                    return ret;
-                *len <<= 8;
-                *len |= ch;
-                cnt--;
-            }
-        }
-    }
-    return ASN1_ERR_NOERROR;
+void asn1_stack_frame_pop(asn1_ctx_t *actx, const gchar *name) {
+  DISSECTOR_ASSERT(actx->stack);
+  DISSECTOR_ASSERT(!strcmp(actx->stack->name, name));
+  actx->stack = actx->stack->next;
 }
 
-/*
- * NAME:        asn1_header_decode                                [API]
- * SYNOPSIS:    int asn1_header_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint    *cls,
- *                      guint    *con,
- *                      guint    *tag
- *                      gboolean *defp,
- *                      guint    *lenp
- *                  )
- * DESCRIPTION: Decodes an ASN1 header.
- *              Parameters:
- *              asn1: pointer to ASN1 socket.
- *              cls:  Class (see asn1.h)
- *              con:  Primitive, Constructed (ASN1_PRI, ASN1_CON)
- *              tag:  Tag (see asn1.h)
- *              defp: Boolean - TRUE if length definite, FALSE if not
- *              lenp: length, if length is definite
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_header_decode(ASN1_SCK *asn1, guint *cls, guint *con, guint *tag,
-                       gboolean *defp, guint *lenp)
-{
-    int   ret;
-    guint def, len = 0;
-
-    ret = asn1_id_decode (asn1, cls, con, tag);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    ret = asn1_length_decode (asn1, &def, &len);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *defp = def;
-    *lenp = len;
-    return ASN1_ERR_NOERROR;
-}
+void asn1_stack_frame_check(asn1_ctx_t *actx, const gchar *name, const asn1_par_def_t *par_def) {
+  const asn1_par_def_t *pd = par_def;
+  asn1_par_t *par;
 
+  DISSECTOR_ASSERT(actx->stack);
+  DISSECTOR_ASSERT(!strcmp(actx->stack->name, name));
 
-/*
- * NAME:        asn1_eoc                                   [API]
- * SYNOPSIS:    gboolean asn1_eoc
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int       eoc
- *                  )
- * DESCRIPTION: Checks if decoding is at End Of Contents.
- *              Parameters:
- *              asn1: pointer to ASN1 socket.
- *              eoc: offset of end of encoding, or -1 if indefinite.
- * RETURNS:     gboolean success
- */
-gboolean
-asn1_eoc ( ASN1_SCK *asn1, int eoc)
-{
-    if (eoc == -1)
-        return (tvb_get_guint8(asn1->tvb, asn1->offset) == 0x00
-               && tvb_get_guint8(asn1->tvb, asn1->offset + 1) == 0x00);
-    else
-        return (asn1->offset >= eoc);
+  par = actx->stack->par;
+  while (pd->name) {
+    DISSECTOR_ASSERT(par);
+    DISSECTOR_ASSERT((pd->ptype == ASN1_PAR_IRR) || (par->ptype == pd->ptype));
+    par->name = pd->name;
+    pd++;
+    par = par->next;
+  }
+  DISSECTOR_ASSERT(!par);
 }
 
-/*
- * NAME:        asn1_eoc_decode                                [API]
- * SYNOPSIS:    int asn1_eoc_decode
- *                  (
- *                      ASN1_SCK  *asn1,
- *                      int       eoc
- *                  )
- * DESCRIPTION: Decodes End Of Contents.
- *              Parameters:
- *              asn1: pointer to ASN1 socket.
- *              eoc: offset of end of encoding, or -1 if indefinite.
- *              If eoc is -1 it decodes an ASN1 End Of
- *              Contents (0x00 0x00), so it has to be an
- *              indefinite length encoding. If eoc is a non-negative
- *              integer, it probably was filled by asn1_header_decode,
- *              and should refer to the octet after the last of the encoding.
- *              It is checked if this offset refers to the octet to be
- *              decoded. This only takes place in decoding a
- *              definite length encoding.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_eoc_decode (ASN1_SCK *asn1, int eoc)
-{
-    int    ret;
-    guchar ch;
+static asn1_par_t *get_par_by_name(asn1_ctx_t *actx, const gchar *name) {
+  asn1_par_t *par = NULL;
 
-    if (eoc == -1) {
-        ret = asn1_octet_decode (asn1, &ch);
-        if (ret != ASN1_ERR_NOERROR)
-           return ret;
-      if (ch != 0x00)
-       return ASN1_ERR_EOC_MISMATCH;
-      ret = asn1_octet_decode (asn1, &ch);
-      if (ret != ASN1_ERR_NOERROR)
-       return ret;
-      if (ch != 0x00)
-       return ASN1_ERR_EOC_MISMATCH;
-      return ASN1_ERR_NOERROR;
-  } else {
-      if (asn1->offset != eoc)
-       return ASN1_ERR_LENGTH_MISMATCH;
-      return ASN1_ERR_NOERROR;
-    }
+  DISSECTOR_ASSERT(actx->stack);
+  par = actx->stack->par;
+  while (par) {
+    if (!strcmp(par->name, name))
+      return par;
+    par = par->next;
+  }
+  return par;
 }
 
-/*
- * NAME:        asn1_null_decode                                [API]
- * SYNOPSIS:    int asn1_null_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len
- *                  )
- * DESCRIPTION: Decodes Null.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_null_decode ( ASN1_SCK *asn1, int enc_len)
-{
-    int start_off = asn1->offset;
+static asn1_par_t *push_new_par(asn1_ctx_t *actx) {
+  asn1_par_t *par, **pp;
 
-    asn1->offset += enc_len;
-    /*
-     * Check for integer overflows.  
-     * XXX - ASN1_ERR_LENGTH_MISMATCH seemed like the most appropriate
-     *       error from the ones available.  Should we make a new one?
-     */
-    if (asn1->offset < 0 || asn1->offset < start_off)
-        return ASN1_ERR_LENGTH_MISMATCH;
+  DISSECTOR_ASSERT(actx->stack);
 
-    return ASN1_ERR_NOERROR;
-}
+  par = ep_new0(asn1_par_t);
 
-/*
- * NAME:        asn1_bool_decode                                [API]
- * SYNOPSIS:    int asn1_bool_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len,
- *                      gboolean *boolean
- *                  )
- * DESCRIPTION: Decodes Boolean.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- *              bool:    False, True (0, !0).
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_bool_decode ( ASN1_SCK *asn1, int enc_len, gboolean *boolean)
-{
-    int    ret;
-    guchar ch;
+  pp = &(actx->stack->par);
+  while (*pp)
+    pp = &((*pp)->next);
+  *pp = par;
 
-    if (enc_len != 1)
-      return ASN1_ERR_LENGTH_MISMATCH;
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *boolean = ch ? TRUE : FALSE;
-    return ASN1_ERR_NOERROR;
+  return par;
 }
 
-/*
- * NAME:        asn1_int32_value_decode                                [API]
- * SYNOPSIS:    int asn1_int32_value_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len,
- *                      gint32   *integer
- *                  )
- * DESCRIPTION: Decodes value portion of Integer (which must be no more
- *              than 32 bits).
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- *              integer: Integer.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_int32_value_decode ( ASN1_SCK *asn1, int enc_len, gint32 *integer)
-{
-    int          ret;
-    int          eoc;
-    guchar       ch;
-    guint        len;
+void asn1_param_push_boolean(asn1_ctx_t *actx, gboolean value) {
+  asn1_par_t *par;
 
-    eoc = asn1->offset + enc_len;
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *integer = (gint) ch;
-    len = 1;
-    while (asn1->offset < eoc) {
-        if (++len > sizeof (gint32))
-           return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
-        ret = asn1_octet_decode (asn1, &ch);
-        if (ret != ASN1_ERR_NOERROR)
-            return ret;
-        *integer <<= 8;
-        *integer |= ch;
-    }
-    return ASN1_ERR_NOERROR;
+  par = push_new_par(actx);
+  par->ptype = ASN1_PAR_BOOLEAN;
+  par->value.v_boolean = value;
 }
 
-/*
- * NAME:        asn1_int32_decode                                [API]
- * SYNOPSIS:    int asn1_int32_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      gint32   *integer,
- *                      guint    *nbytes,
- *                  )
- * DESCRIPTION: Decodes Integer (which must be no more than 32 bits).
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              integer: Integer.
- *              nbytes:  number of bytes used to encode it.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_int32_decode ( ASN1_SCK *asn1, gint32 *integer, guint *nbytes)
-{
-    int          ret;
-    int          start;
-    guint        cls;
-    guint        con;
-    guint        tag;
-    gboolean     def;
-    guint        enc_len;
+void asn1_param_push_integer(asn1_ctx_t *actx, gint32 value) {
+  asn1_par_t *par;
 
-    start = asn1->offset;
-    ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
-    if (ret != ASN1_ERR_NOERROR)
-       goto done;
-    if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) {
-       ret = ASN1_ERR_WRONG_TYPE;
-       goto done;
-    }
-    if (!def) {
-       ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
-       goto done;
-    }
-    ret = asn1_int32_value_decode (asn1, enc_len, integer);
-
-done:
-    *nbytes = asn1->offset - start;
-    return ret;
+  par = push_new_par(actx);
+  par->ptype = ASN1_PAR_INTEGER;
+  par->value.v_integer = value;
 }
 
-/*
- * NAME:        asn1_uint32_value_decode                             [API]
- * SYNOPSIS:    int asn1_uint32_value_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len,
- *                      guint32  *integer
- *                  )
- * DESCRIPTION: Decodes value part of Unsigned Integer (which must be no
- *              more than 32 bits).
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- *              integer: Integer.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_uint32_value_decode ( ASN1_SCK *asn1, int enc_len, guint32 *integer)
-{
-    int          ret;
-    int          eoc;
-    guchar       ch;
-    guint        len;
+gboolean asn1_param_get_boolean(asn1_ctx_t *actx, const gchar *name) {
+  asn1_par_t *par = NULL;
 
-    eoc = asn1->offset + enc_len;
-    ret = asn1_octet_decode (asn1, &ch);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *integer = ch;
-    if (ch == 0)
-       len = 0;
-    else
-       len = 1;
-    while (asn1->offset < eoc) {
-        if (++len > sizeof (guint32))
-           return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
-        ret = asn1_octet_decode (asn1, &ch);
-        if (ret != ASN1_ERR_NOERROR)
-            return ret;
-        *integer <<= 8;
-        *integer |= ch;
-    }
-    return ASN1_ERR_NOERROR;
+  par = get_par_by_name(actx, name);
+  DISSECTOR_ASSERT(par);
+  return par->value.v_boolean;
 }
 
-/*
- * NAME:        asn1_uint32_decode                             [API]
- * SYNOPSIS:    int asn1_uint32_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      guint32  *integer,
- *                      guint    *nbytes,
- *                  )
- * DESCRIPTION: Decodes Unsigned Integer (which must be no more than 32 bits).
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              integer: Integer.
- *              nbytes:  number of bytes used to encode it.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_uint32_decode ( ASN1_SCK *asn1, guint32 *integer, guint *nbytes)
-{
-    int          ret;
-    int          start;
-    guint        cls;
-    guint        con;
-    guint        tag;
-    gboolean     def;
-    guint        enc_len;
-
-    start = asn1->offset;
-    ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
-    if (ret != ASN1_ERR_NOERROR)
-       goto done;
-    if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) {
-       ret = ASN1_ERR_WRONG_TYPE;
-       goto done;
-    }
-    if (!def) {
-       ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
-       goto done;
-    }
-    ret = asn1_uint32_value_decode (asn1, enc_len, integer);
+gint32 asn1_param_get_integer(asn1_ctx_t *actx, const gchar *name) {
+  asn1_par_t *par = NULL;
 
-done:
-    *nbytes = asn1->offset - start;
-    return ret;
+  par = get_par_by_name(actx, name);
+  DISSECTOR_ASSERT(par);
+  return par->value.v_integer;
 }
 
-/*
- * NAME:        asn1_bits_decode                                [API]
- * SYNOPSIS:    int asn1_bits_decode
- *                  (
- *                      ASN1_SCK  *asn1,
- *                      int        eoc,
- *                      guchar    *bits,
- *                      guint      size,
- *                      guint      len,
- *                      guchar     unused
- *                  )
- * DESCRIPTION: Decodes Bit String.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of value.
- *              bits:    pointer to variable we set to point to strring
- *              len:     Size of Bit String in characters.
- *              unused:  Number of unused bits in last character.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_bits_decode ( ASN1_SCK *asn1, int enc_len, guchar **bits,
-                    guint *len, guchar *unused)
-{
-    int ret;
-    int eoc;
-    guchar *ptr;
-
-    eoc = asn1->offset + enc_len;
-    *bits = NULL;
-    ret = asn1_octet_decode (asn1, unused);
-    if (ret != ASN1_ERR_NOERROR)
-        return ret;
-    *len = 0;
 
-    /*
-     * First, make sure the entire string is in the tvbuff, and throw
-     * an exception if it isn't.  If the length is bogus, this should
-     * keep us from trying to allocate an immensely large buffer.
-     * (It won't help if the length is *valid* but immensely large,
-     * but that's another matter; in any case, that would happen only
-     * if we had an immensely large tvbuff....)
-     */
-    if (enc_len != 0) {
-        tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
-        *bits = g_malloc (enc_len);
-    } else {
-       /*
-        * If the length is 0, we allocate a 1-byte buffer, as
-        * "g_malloc()" returns NULL if passed 0 as an argument,
-        * and our caller expects us to return a pointer to a
-        * buffer.
-        */
-       *bits = g_malloc (1);
-    }
+/*--- ROSE ---*/
 
-    ptr = *bits;
-    while (asn1->offset < eoc) {
-        ret = asn1_octet_decode (asn1, (guchar *)ptr++);
-        if (ret != ASN1_ERR_NOERROR) {
-            g_free(*bits);
-            *bits = NULL;
-           return ret;
-       }
-    }
-    *len = ptr - *bits;
-    return ASN1_ERR_NOERROR;
+void rose_ctx_init(rose_ctx_t *rctx) {
+  memset(rctx, '\0', sizeof(*rctx));
+  rctx->signature = ROSE_CTX_SIGNATURE;
 }
 
-/*
- * NAME:        asn1_string_value_decode                       [API]
- * SYNOPSIS:    int asn1_string_value_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len,
- *                      guchar   **octets
- *                  )
- * DESCRIPTION: Decodes value portion of string (Octet String, various
- *              character string types)
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- *              octets:  pointer to variable we set to point to string,
- *                      which is '\0' terminated for ease of use as C-string
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_string_value_decode ( ASN1_SCK *asn1, int enc_len, guchar **octets)
-{
-    int          ret;
-    int          eoc;
-    guchar       *ptr;
-
-    /*
-     * First, make sure the entire string is in the tvbuff, and throw
-     * an exception if it isn't.  If the length is bogus, this should
-     * keep us from trying to allocate an immensely large buffer.
-     * (It won't help if the length is *valid* but immensely large,
-     * but that's another matter; in any case, that would happen only
-     * if we had an immensely large tvbuff....)
-     */
-    if (enc_len != 0)
-       tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
-    *octets = g_malloc (enc_len+1);
-
-    eoc = asn1->offset + enc_len;
-    ptr = *octets;
-    while (asn1->offset < eoc) {
-       ret = asn1_octet_decode (asn1, (guchar *)ptr++);
-       if (ret != ASN1_ERR_NOERROR) {
-           g_free(*octets);
-           *octets = NULL;
-           return ret;
-       }
-    }
-    *(guchar *)ptr = '\0';
-    return ASN1_ERR_NOERROR;
+gboolean rose_ctx_check_signature(rose_ctx_t *rctx) {
+  return rctx && (rctx->signature == ROSE_CTX_SIGNATURE);
 }
 
-/*
- * NAME:        asn1_string_decode                             [API]
- * SYNOPSIS:    int asn1_string_decode
- *                  (
- *                      ASN1_SCK  *asn1,
- *                      guchar    **octets,
- *                      guint     *str_len,
- *                      guint     *nbytes,
- *                      guint     expected_tag
- *                  )
- * DESCRIPTION: Decodes string (Octet String, various character string
- *              types)
- *              Parameters:
- *              asn1:         pointer to ASN1 socket.
- *              octets:       pointer to variable we set to point to string.
- *              str_len:      length of octet_string.
- *              nbytes:       number of bytes used to encode.
- *              expected_tag: tag expected for this type of string.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len,
-                       guint *nbytes, guint expected_tag)
-{
-    int          ret;
-    int          start;
-    int          enc_len;
-    guint        cls;
-    guint        con;
-    guint        tag;
-    gboolean     def;
-
-    start = asn1->offset;
-    ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
-    if (ret != ASN1_ERR_NOERROR)
-       goto done;
-    if (cls != ASN1_UNI || con != ASN1_PRI || tag != expected_tag) {
-       /* XXX - handle the constructed encoding? */
-       ret = ASN1_ERR_WRONG_TYPE;
-       goto done;
-    }
-    if (!def) {
-       ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
-       goto done;
-    }
-
-    ret = asn1_string_value_decode (asn1, enc_len, octets);
-    *str_len = enc_len;
-
-done:
-    *nbytes = asn1->offset - start;
-    return ret;
+void rose_ctx_clean_data(rose_ctx_t *rctx) {
+  memset(&rctx->d, '\0', sizeof(rctx->d));
+  rctx->d.code = -1;
 }
 
-/*
- * NAME:        asn1_octet_string_decode                             [API]
- * SYNOPSIS:    int asn1_octet_string_decode
- *                  (
- *                      ASN1_SCK  *asn1,
- *                      guchar    **octets,
- *                      guint     *str_len,
- *                      guint     *nbytes,
- *                  )
- * DESCRIPTION: Decodes Octet String.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              octets:  pointer to variable we set to point to string.
- *              str_len: length of octet_string.
- *              nbytes:  number of bytes used to encode.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_octet_string_decode ( ASN1_SCK *asn1, guchar **octets, guint *str_len,
-                       guint *nbytes)
-{
-    return asn1_string_decode(asn1, octets, str_len, nbytes, ASN1_OTS);
-}
+asn1_ctx_t *get_asn1_ctx(void *ptr) {
+  asn1_ctx_t *actx = (asn1_ctx_t*)ptr;
 
-/*
- * NAME:        asn1_subid_decode
- * SYNOPSIS:    int asn1_subid_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      subid_t  *subid
- *                  )
- * DESCRIPTION: Decodes Sub Identifier.
- *              Parameters:
- *              asn1:  pointer to ASN1 socket.
- *              subid: Sub Identifier.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_subid_decode ( ASN1_SCK *asn1, subid_t *subid)
-{
-    int    ret;
-    guchar ch;
+  if (!asn1_ctx_check_signature(actx))
+    actx = NULL;
 
-    *subid = 0;
-    do {
-        ret = asn1_octet_decode(asn1, &ch);
-        if (ret != ASN1_ERR_NOERROR)
-            return ret;
-        *subid <<= 7;
-        *subid |= ch & 0x7F;
-    } while ((ch & 0x80) == 0x80);
-    return ASN1_ERR_NOERROR;
+  return actx;
 }
 
-/*
- * NAME:        asn1_oid_value_decode                                [API]
- * SYNOPSIS:    int asn1_oid_value_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      int      enc_len,
- *                      subid_t  **oid,
- *                      guint    *len
- *                  )
- * DESCRIPTION: Decodes value portion of Object Identifier.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              enc_len: length of encoding of value.
- *              oid:     pointer to variable we set to Object Identifier.
- *              len:     Length of Object Identifier in gulongs.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_oid_value_decode ( ASN1_SCK *asn1, int enc_len, subid_t **oid, guint *len)
-{
-    int          ret;
-    int          eoc;
-    subid_t      subid;
-    guint        size;
-    subid_t      *optr;
+rose_ctx_t *get_rose_ctx(void *ptr) {
+  rose_ctx_t *rctx = (rose_ctx_t*)ptr;
+  asn1_ctx_t *actx = (asn1_ctx_t*)ptr;
 
-    /*
-     * First, make sure the entire string is in the tvbuff, and throw
-     * an exception if it isn't.  If the length is bogus, this should
-     * keep us from trying to allocate an immensely large buffer.
-     * (It won't help if the length is *valid* but immensely large,
-     * but that's another matter; in any case, that would happen only
-     * if we had an immensely large tvbuff....)
-     */
-    if (enc_len < 1) {
-       *oid = NULL;
-       return ASN1_ERR_LENGTH_MISMATCH;
-    }
-    tvb_ensure_bytes_exist(asn1->tvb, asn1->offset, enc_len);
+  if (!asn1_ctx_check_signature(actx))
+    actx = NULL;
 
-    eoc = asn1->offset + enc_len;
+  if (actx)
+    rctx = actx->rose_ctx;
 
-    size = enc_len + 1;
-    *oid = g_malloc(size * sizeof(gulong));
-    optr = *oid;
+  if (!rose_ctx_check_signature(rctx))
+    rctx = NULL;
 
-    ret = asn1_subid_decode (asn1, &subid);
-    if (ret != ASN1_ERR_NOERROR) {
-       g_free(*oid);
-       *oid = NULL;
-       return ret;
-    }
-    if (subid < 40) {
-       optr[0] = 0;
-       optr[1] = subid;
-    } else if (subid < 80) {
-       optr[0] = 1;
-       optr[1] = subid - 40;
-    } else {
-       optr[0] = 2;
-       optr[1] = subid - 80;
-    }
-    *len = 2;
-    optr += 2;
-    while (asn1->offset < eoc) {
-       if (++(*len) > size) {
-            g_free(*oid);
-            *oid = NULL;
-           return ASN1_ERR_WRONG_LENGTH_FOR_TYPE;
-       }
-       ret = asn1_subid_decode (asn1, optr++);
-       if (ret != ASN1_ERR_NOERROR) {
-            g_free(*oid);
-            *oid = NULL;
-           return ret;
-       }
-    }
-    return ASN1_ERR_NOERROR;
-}
-
-/*
- * NAME:        asn1_oid_decode                                [API]
- * SYNOPSIS:    int asn1_oid_decode
- *                  (
- *                      ASN1_SCK *asn1,
- *                      subid_t  **oid,
- *                      guint    *len,
- *                      guint    *nbytes
- *                  )
- * DESCRIPTION: Decodes Object Identifier.
- *              Parameters:
- *              asn1:   pointer to ASN1 socket.
- *              oid:    pointer to variable we set to Object Identifier.
- *              len:    Length of Object Identifier in gulongs.
- *              nbytes: number of bytes used to encode.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_oid_decode ( ASN1_SCK *asn1, subid_t **oid, guint *len, guint *nbytes)
-{
-    int          ret;
-    int          start;
-    guint        cls;
-    guint        con;
-    guint        tag;
-    gboolean     def;
-    guint        enc_len;
-
-    start = asn1->offset;
-    ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &enc_len);
-    if (ret != ASN1_ERR_NOERROR)
-       goto done;
-    if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) {
-       ret = ASN1_ERR_WRONG_TYPE;
-       goto done;
-    }
-    if (!def) {
-       ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
-       goto done;
-    }
-
-    ret = asn1_oid_value_decode (asn1, enc_len, oid, len);
-
-done:
-    *nbytes = asn1->offset - start;
-    return ret;
+  return rctx;
 }
 
-/*
- * NAME:        asn1_sequence_decode                             [API]
- * SYNOPSIS:    int asn1_sequence_decode
- *                  (
- *                      ASN1_SCK  *asn1,
- *                      guint     *seq_len,
- *                      guint     *nbytes
- *                  )
- * DESCRIPTION: Decodes header for SEQUENCE.
- *              Parameters:
- *              asn1:    pointer to ASN1 socket.
- *              seq_len: length of sequence.
- *              nbytes:  number of bytes used to encode header.
- * RETURNS:     ASN1_ERR value (ASN1_ERR_NOERROR on success)
- */
-int
-asn1_sequence_decode ( ASN1_SCK *asn1, guint *seq_len, guint *nbytes)
-{
-    int          ret;
-    int          start;
-    guint        cls;
-    guint        con;
-    guint        tag;
-    gboolean     def;
+double asn1_get_real(const guint8 *real_ptr, gint real_len) {
+  guint8 octet;
+  const guint8 *p;
+  guint8 *buf;
+  double val = 0;
 
-    start = asn1->offset;
-    ret = asn1_header_decode(asn1, &cls, &con, &tag,
-           &def, seq_len);
-    if (ret != ASN1_ERR_NOERROR)
-       goto done;
-    if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) {
-       ret = ASN1_ERR_WRONG_TYPE;
-       goto done;
-    }
-    if (!def) {
-       /* XXX - might some sequences have an indefinite length? */
-       ret = ASN1_ERR_LENGTH_NOT_DEFINITE;
-       goto done;
+  if (real_len < 1) return val;
+  octet = real_ptr[0];
+  p = real_ptr + 1;
+  real_len -= 1;
+  if (octet & 0x80) {  /* binary encoding */
+  } else if (octet & 0x40) {  /* SpecialRealValue */
+    switch (octet & 0x3F) {
+      case 0x00: val = HUGE_VAL; break;
+      case 0x01: val = -HUGE_VAL; break;
     }
-    ret = ASN1_ERR_NOERROR;
+  } else {  /* decimal encoding */
+    buf = ep_strndup(p, real_len);
+    val = atof(buf);
+  }
 
-done:
-    *nbytes = asn1->offset - start;
-    return ret;
-}
-
-/*
- * NAME:        asn1_err_to_str                             [API]
- * SYNOPSIS:    const char *asn1_err_to_str
- *                  (
- *                      int     err
- *                  )
- * DESCRIPTION: Returns the string corresponding to an ASN.1 library error.
- *              Parameters:
- *              err: the error code
- * RETURNS:     string for the error
- */
-const char *
-asn1_err_to_str(int err)
-{
-    const char   *errstr;
-    char         errstrbuf[14+1+1+11+1+1];     /* "Unknown error (%d)\0" */
-
-    switch (err) {
-
-    case ASN1_ERR_EOC_MISMATCH:
-       errstr = "EOC mismatch";
-       break;
-
-    case ASN1_ERR_WRONG_TYPE:
-       errstr = "Wrong type for that item";
-       break;
-
-    case ASN1_ERR_LENGTH_NOT_DEFINITE:
-       errstr = "Length was indefinite";
-       break;
-
-    case ASN1_ERR_LENGTH_MISMATCH:
-       errstr = "Length mismatch";
-       break;
-
-    case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
-       errstr = "Wrong length for that item's type";
-       break;
-
-    default:
-       g_snprintf(errstrbuf, sizeof errstrbuf, "Unknown error (%d)", err);
-       errstr = ep_strdup(errstrbuf);
-       break;
-    }
-    return errstr;
+  return val;
 }