/* asn1.c
* Routines for ASN.1 BER dissection
*
- * $Id: asn1.c,v 1.8 2002/01/21 07:36:31 guy Exp $
+ * $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
/*
* MODULE INFORMATION
- * ------------------
+ * ------------------
* FILE NAME: g_asn1.c
* SYSTEM NAME: ASN1 Basic Encoding
* ORIGINAL AUTHOR(S): Dirk Wisse
* 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.
# include "config.h"
#endif
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
+#include <stdio.h>
-#ifdef HAVE_WINSOCK_H
-#include <winsock.h>
-#endif
+#include <limits.h>
#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
#include <epan/tvbuff.h>
#include "asn1.h"
* RETURNS: void
*/
-void
+void
asn1_close(ASN1_SCK *asn1, int *offset)
{
*offset = asn1->offset;
}
/*
- * NAME: asn1_tag_decode
- * SYNOPSIS: int asn1_tag_decode
+ * NAME: asn1_tag_get
+ * SYNOPSIS: int asn1_tag_get
* (
* ASN1_SCK *asn1,
* guint *tag
* )
- * DESCRIPTION: Decodes a tag.
+ * DESCRIPTION: Decodes a tag number, combining it with existing tag bits.
* RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
*/
-int
-asn1_tag_decode(ASN1_SCK *asn1, guint *tag)
+static int
+asn1_tag_get(ASN1_SCK *asn1, guint *tag)
{
int ret;
guchar ch;
- *tag = 0;
do {
ret = asn1_octet_decode (asn1, &ch);
if (ret != ASN1_ERR_NOERROR)
return ASN1_ERR_NOERROR;
}
+/*
+ * 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
int ret;
guchar ch;
+ *tag = 0;
ret = asn1_octet_decode (asn1, &ch);
if (ret != ASN1_ERR_NOERROR)
return ret;
return ASN1_ERR_NOERROR;
}
+/*
+ * 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;
+}
+
/*
* NAME: asn1_length_decode
* SYNOPSIS: int asn1_length_decode
{
int ret;
guchar ch;
-
+
if (eoc == -1) {
ret = asn1_octet_decode (asn1, &ch);
if (ret != ASN1_ERR_NOERROR)
int
asn1_null_decode ( ASN1_SCK *asn1, int enc_len)
{
+ int start_off = asn1->offset;
+
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;
+
return ASN1_ERR_NOERROR;
}
* (
* ASN1_SCK *asn1,
* int enc_len,
- * gboolean *bool
+ * gboolean *boolean
* )
* DESCRIPTION: Decodes Boolean.
* Parameters:
* RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
*/
int
-asn1_bool_decode ( ASN1_SCK *asn1, int enc_len, gboolean *bool)
+asn1_bool_decode ( ASN1_SCK *asn1, int enc_len, gboolean *boolean)
{
int ret;
guchar ch;
ret = asn1_octet_decode (asn1, &ch);
if (ret != ASN1_ERR_NOERROR)
return ret;
- *bool = ch ? TRUE : FALSE;
+ *boolean = ch ? TRUE : FALSE;
return ASN1_ERR_NOERROR;
}
* RETURNS: ASN1_ERR value (ASN1_ERR_NOERROR on success)
*/
int
-asn1_uint32_value_decode ( ASN1_SCK *asn1, int enc_len, guint *integer)
+asn1_uint32_value_decode ( ASN1_SCK *asn1, int enc_len, guint32 *integer)
{
int ret;
int eoc;
* )
* DESCRIPTION: Decodes Bit String.
* Parameters:
- * asn1: pointer to ASN1 socket.
- * eoc: offset of end of encoding, or -1 if indefinite.
- * bits: pointer to begin of Bit String.
- * size: Size of Bit String in characters.
- * len: Length of Bit String in characters.
- * unused: Number of unused bits in last character.
+ * 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 eoc, guchar **bits,
+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;
- *bits = g_malloc(eoc - asn1->offset);
+
+ /*
+ * 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);
+ }
+
+ ptr = *bits;
while (asn1->offset < eoc) {
- ret = asn1_octet_decode (asn1, (guchar *)bits++);
+ 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;
}
* Parameters:
* asn1: pointer to ASN1 socket.
* enc_len: length of encoding of value.
- * octets: pointer to variable we set to point to string.
+ * 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
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;
- *octets = g_malloc (enc_len);
ptr = *octets;
while (asn1->offset < eoc) {
ret = asn1_octet_decode (asn1, (guchar *)ptr++);
return ret;
}
}
+ *(guchar *)ptr = '\0';
return ASN1_ERR_NOERROR;
}
guint size;
subid_t *optr;
+ /*
+ * 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);
+
eoc = asn1->offset + enc_len;
+
size = enc_len + 1;
*oid = g_malloc(size * sizeof(gulong));
optr = *oid;
-
+
ret = asn1_subid_decode (asn1, &subid);
if (ret != ASN1_ERR_NOERROR) {
g_free(*oid);
*nbytes = asn1->offset - start;
return ret;
}
+
+/*
+ * NAME: asn1_err_to_str [API]
+ * SYNOPSIS: 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
+ */
+char *
+asn1_err_to_str(int err)
+{
+ 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:
+ snprintf(errstrbuf, sizeof errstrbuf, "Unknown error (%d)", err);
+ errstr = errstrbuf;
+ break;
+ }
+ return errstr;
+}