diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2015-03-04 14:02:59 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2015-03-04 14:50:01 +0100 |
commit | b12bfa8932f44d1d1c25b4a2e385387a62dfbcc9 (patch) | |
tree | 6e293939894bc9a7a0adeb236f732eb9028f49c7 | |
parent | edaff43f27c3e1bcf8317ecee9f733a995602b72 (diff) | |
download | libtasn1-b12bfa8932f44d1d1c25b4a2e385387a62dfbcc9.tar.gz |
Added asn1_decode_simple_ber()
-rw-r--r-- | lib/decoding.c | 181 | ||||
-rw-r--r-- | lib/libtasn1.h | 7 | ||||
-rw-r--r-- | lib/libtasn1.map | 1 |
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: *; }; |