summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2015-03-04 14:02:59 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2015-03-04 14:50:01 +0100
commitb12bfa8932f44d1d1c25b4a2e385387a62dfbcc9 (patch)
tree6e293939894bc9a7a0adeb236f732eb9028f49c7
parentedaff43f27c3e1bcf8317ecee9f733a995602b72 (diff)
downloadlibtasn1-b12bfa8932f44d1d1c25b4a2e385387a62dfbcc9.tar.gz
Added asn1_decode_simple_ber()
-rw-r--r--lib/decoding.c181
-rw-r--r--lib/libtasn1.h7
-rw-r--r--lib/libtasn1.map1
3 files changed, 187 insertions, 2 deletions
diff --git a/lib/decoding.c b/lib/decoding.c
index e206b93..cd9f4d2 100644
--- a/lib/decoding.c
+++ b/lib/decoding.c
@@ -33,6 +33,7 @@
#include <limits.h>
#include <intprops.h>
+#define DEBUG
#ifdef DEBUG
# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
#else
@@ -2085,7 +2086,7 @@ asn1_expand_octet_string (asn1_node definitions, asn1_node * element,
* asn1_decode_simple_der:
* @etype: The type of the string to be encoded (ASN1_ETYPE_)
* @der: the encoded string
- * @der_len: the bytes of the encoded string
+ * @_der_len: the bytes of the encoded string
* @str: a pointer to the data
* @str_len: the length of the data
*
@@ -2096,11 +2097,12 @@ asn1_expand_octet_string (asn1_node definitions, asn1_node * element,
**/
int
asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
- unsigned int der_len, const unsigned char **str,
+ unsigned int _der_len, const unsigned char **str,
unsigned int *str_len)
{
int tag_len, len_len;
const unsigned char *p;
+ int der_len = _der_len;
unsigned char class;
unsigned long tag;
long ret;
@@ -2125,6 +2127,8 @@ asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
p += tag_len;
der_len -= tag_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
ret = asn1_get_length_der (p, der_len, &len_len);
if (ret < 0)
@@ -2132,9 +2136,182 @@ asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
p += len_len;
der_len -= len_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
*str_len = ret;
*str = p;
return ASN1_SUCCESS;
}
+
+static int append(uint8_t **dst, unsigned *dst_size, const uint8_t *src, unsigned src_size)
+{
+ *dst = realloc(*dst, *dst_size+src_size);
+ if (*dst == NULL)
+ return ASN1_MEM_ERROR;
+ memcpy(*dst + *dst_size, src, src_size);
+ *dst_size += src_size;
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_decode_simple_ber:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @der: the encoded string
+ * @_der_len: the bytes of the encoded string
+ * @str: a pointer to the data
+ * @str_len: the length of the data
+ * @ber_len: the total length occupied by BER (may be %NULL)
+ *
+ * Decodes a simple BER encoded type (e.g. a string, which is not constructed).
+ * The output is an allocated value of the data. This function works for
+ * OCTET STRINGS only.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ **/
+int
+asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, unsigned char **str,
+ unsigned int *str_len, unsigned int *ber_len)
+{
+ int tag_len, len_len;
+ const unsigned char *p;
+ int der_len = _der_len;
+ uint8_t *total = NULL;
+ unsigned total_size = 0;
+ unsigned char class;
+ unsigned long tag;
+ long ret;
+
+ if (ber_len) *ber_len = 0;
+
+ if (der == NULL || der_len == 0)
+ {
+ warn();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ if (ETYPE_OK (etype) == 0)
+ {
+ warn();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ /* doesn't handle constructed classes */
+ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
+ {
+ warn();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ p = der;
+ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
+ if (ret != ASN1_SUCCESS)
+ {
+ warn();
+ return ret;
+ }
+
+ if (ber_len) *ber_len += tag_len;
+
+ if (tag != ETYPE_TAG (etype))
+ {
+ warn();
+ return ASN1_DER_ERROR;
+ }
+
+ if (class == ASN1_CLASS_STRUCTURED)
+ {
+ p += tag_len;
+ der_len -= tag_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ ret = asn1_get_length_ber (p, der_len, &len_len);
+ if (ret < 0)
+ {
+ warn();
+ return ASN1_DER_ERROR;
+ }
+
+ p += len_len;
+ der_len -= len_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ if (ber_len) *ber_len += ret + len_len;
+
+ /* decode the available octet strings */
+ do
+ {
+ uint8_t *out = NULL;
+ unsigned out_len;
+ unsigned tmp_len;
+
+ ret = asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len);
+ if (ret != ASN1_SUCCESS)
+ {
+ free(total);
+ return ret;
+ }
+
+ p += tmp_len;
+ der_len -= tmp_len;
+
+ if (der_len < 2)
+ {
+ free(total);
+ return ASN1_DER_ERROR;
+ }
+
+ if (out_len > 0)
+ {
+ ret = append(&total, &total_size, out, out_len);
+ free(out);
+ if (ret != ASN1_SUCCESS)
+ {
+ free(total);
+ return ret;
+ }
+ }
+
+ if (p[0] == 0 && p[1] == 0) /* EOC */
+ break;
+ }
+ while(1);
+ }
+ else if (class == ETYPE_CLASS(etype))
+ {
+ p += tag_len;
+ der_len -= tag_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ ret = asn1_get_length_der (p, der_len, &len_len);
+ if (ret < 0)
+ {
+ warn();
+ return ASN1_DER_ERROR;
+ }
+
+ p += len_len;
+ der_len -= len_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ if (ber_len)
+ *ber_len += len_len + ret;
+
+ ret = append(&total, &total_size, p, ret);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+ }
+ else
+ return ASN1_DER_ERROR;
+
+ *str = total;
+ *str_len = total_size;
+
+ return ASN1_SUCCESS;
+}
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index ca21a0c..1e9a61e 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -330,6 +330,13 @@ extern "C"
const unsigned char **str,
unsigned int *str_len);
+ extern ASN1_API
+ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int der_len,
+ unsigned char **str,
+ unsigned int *str_len,
+ unsigned int *ber_len);
+
extern ASN1_API int
asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
unsigned int str_len, unsigned char *tl,
diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 6424219..d5ffa9e 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -56,6 +56,7 @@ LIBTASN1_0_3
asn1_read_value_type;
asn1_delete_structure2;
asn1_dup_node;
+ asn1_decode_simple_ber;
local:
*;
};