summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/minitasn1/decoding.c185
-rw-r--r--lib/minitasn1/libtasn1.h9
-rw-r--r--lib/minitasn1/parser_aux.c9
3 files changed, 197 insertions, 6 deletions
diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c
index e206b93a25..7fbd93160f 100644
--- a/lib/minitasn1/decoding.c
+++ b/lib/minitasn1/decoding.c
@@ -2085,7 +2085,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 +2096,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 +2126,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 +2135,187 @@ 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 unsigned char *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 BER encoded type. The output is an allocated value
+ * of the data. This decodes BER STRINGS only. Other types are
+ * decoded as DER.
+ *
+ * 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;
+ unsigned char *out = NULL;
+ unsigned out_len;
+ 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;
+ }
+
+ p += tag_len;
+ der_len -= tag_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ if (class == ASN1_CLASS_STRUCTURED && (etype == ASN1_ETYPE_GENERALSTRING ||
+ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING ||
+ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING ||
+ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING ||
+ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING ||
+ etype == ASN1_ETYPE_OCTET_STRING))
+ {
+
+ len_len = 1;
+ if (p[0] != 0x80)
+ {
+ 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;
+
+ /* decode the available octet strings */
+ do
+ {
+ 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 (ber_len) *ber_len += tmp_len;
+
+ if (der_len < 2) /* we need the EOC */
+ {
+ 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 */
+ {
+ if (ber_len) *ber_len += 2;
+ break;
+ }
+ }
+ while(1);
+ }
+ else if (class == ETYPE_CLASS(etype))
+ {
+ if (ber_len)
+ {
+ ret = asn1_get_length_der (p, der_len, &len_len);
+ if (ret < 0)
+ {
+ warn();
+ return ASN1_DER_ERROR;
+ }
+ *ber_len += ret + len_len;
+ }
+
+ /* non-string values are decoded as DER */
+ ret = asn1_decode_simple_der(etype, der, _der_len, (const unsigned char**)&out, &out_len);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ ret = append(&total, &total_size, out, out_len);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+ }
+ else
+ return ASN1_DER_ERROR;
+
+ *str = total;
+ *str_len = total_size;
+
+ return ASN1_SUCCESS;
+}
diff --git a/lib/minitasn1/libtasn1.h b/lib/minitasn1/libtasn1.h
index 190443ca96..c0632c3b7f 100644
--- a/lib/minitasn1/libtasn1.h
+++ b/lib/minitasn1/libtasn1.h
@@ -44,7 +44,7 @@ extern "C"
{
#endif
-#define ASN1_VERSION "4.1"
+#define ASN1_VERSION "4.3"
#if defined(__GNUC__) && !defined(ASN1_INTERNAL_BUILD)
# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
@@ -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/minitasn1/parser_aux.c b/lib/minitasn1/parser_aux.c
index 4b150009aa..d3e9009d77 100644
--- a/lib/minitasn1/parser_aux.c
+++ b/lib/minitasn1/parser_aux.c
@@ -701,9 +701,12 @@ _asn1_expand_object_id (asn1_node node)
p5 =
_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
_asn1_set_name (p5, p4->name);
- tlen = _asn1_strlen (p4->value);
- if (tlen > 0)
- _asn1_set_value (p5, p4->value, tlen + 1);
+ if (p4->value)
+ {
+ tlen = _asn1_strlen (p4->value);
+ if (tlen > 0)
+ _asn1_set_value (p5, p4->value, tlen + 1);
+ }
if (p2 == p)
{
_asn1_set_right (p5, p->down);