diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-01-09 11:39:58 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-01-09 11:40:17 +0100 |
commit | b21883d81ec59299312e786c49da6889e8bfb0f2 (patch) | |
tree | 7bf5d061adcbcb17ec870e62f3d79e50a9f15899 | |
parent | 838d7c3175c0504ac9b4facf857aa9163ad6e077 (diff) | |
download | gnutls-b21883d81ec59299312e786c49da6889e8bfb0f2.tar.gz |
libtasn1: updated to latest libtasn1 master branchtmp-gnutls_3_3_x-libtasn1-update
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r-- | lib/minitasn1/decoding.c | 80 | ||||
-rw-r--r-- | lib/minitasn1/element.c | 10 | ||||
-rw-r--r-- | lib/minitasn1/errors.c | 1 | ||||
-rw-r--r-- | lib/minitasn1/libtasn1.h | 7 | ||||
-rw-r--r-- | lib/minitasn1/parser_aux.c | 55 |
5 files changed, 105 insertions, 48 deletions
diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c index 2cd9ac359a..0ee35d3d09 100644 --- a/lib/minitasn1/decoding.c +++ b/lib/minitasn1/decoding.c @@ -45,6 +45,13 @@ #define DECODE_FLAG_HAVE_TAG 1 #define DECODE_FLAG_INDEFINITE (1<<1) +/* On indefinite string decoding, allow this maximum levels + * of recursion. Allowing infinite recursion, makes the BER + * decoder susceptible to stack exhaustion due to that recursion. + */ +#define DECODE_FLAG_LEVEL1 (1<<2) +#define DECODE_FLAG_LEVEL2 (1<<3) +#define DECODE_FLAG_LEVEL3 (1<<4) #define DECR_LEN(l, s) do { \ l -= s; \ @@ -114,7 +121,7 @@ asn1_get_length_der (const unsigned char *der, int der_len, int *len) k = der[0] & 0x7F; punt = 1; if (k) - { /* definite length method */ + { /* definite length method */ ans = 0; while (punt <= k && punt < der_len) { @@ -154,7 +161,7 @@ asn1_get_length_der (const unsigned char *der, int der_len, int *len) * @der_len: Length of DER data to decode. * @cls: Output variable containing decoded class. * @len: Output variable containing the length of the DER TAG data. - * @tag: Output variable containing the decoded tag. + * @tag: Output variable containing the decoded tag (may be %NULL). * * Decode the class and TAG from DER code. * @@ -237,9 +244,9 @@ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) long err; ret = asn1_get_length_der (ber, ber_len, len); - if (ret == -1) + if (ret == -1 && ber_len > 1) { /* indefinite length method */ - err = _asn1_get_indefinite_length_string (ber + 1, ber_len, &ret); + err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret); if (err != ASN1_SUCCESS) return -3; } @@ -329,10 +336,10 @@ _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *r if (str_len < 8) { warn(); - return ASN1_DER_ERROR; + return ASN1_TIME_ENCODING_ERROR; } - if (flags & ASN1_DECODE_FLAG_STRICT_DER) + if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME)) { p = &der[len_len]; for (i=0;i<(unsigned)(str_len-1);i++) @@ -359,14 +366,14 @@ _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *r } warn(); - return ASN1_DER_ERROR; + return ASN1_TIME_ENCODING_ERROR; } } if (sign_count == 0 && p[str_len-1] != 'Z') { warn(); - return ASN1_DER_ERROR; + return ASN1_TIME_ENCODING_ERROR; } } memcpy (str, der + len_len, str_len); @@ -1141,8 +1148,8 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if (result != ASN1_SUCCESS) { warn(); - goto cleanup; - } + goto cleanup; + } DECR_LEN(ider_len, len2); @@ -1186,15 +1193,15 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, dflags |= DECODE_FLAG_INDEFINITE; result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags); - if (result != ASN1_SUCCESS) + if (result != ASN1_SUCCESS) { warn(); goto cleanup; } - DECR_LEN(ider_len, ber_len); + DECR_LEN(ider_len, ber_len); - _asn1_set_value_lv (p, ptmp, vlen); + _asn1_set_value_lv (p, ptmp, vlen); counter += ber_len; free(ptmp); @@ -1305,7 +1312,12 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* indefinite length method */ if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) { - _asn1_append_sequence_set (p, &tcache); + result = _asn1_append_sequence_set (p, &tcache); + if (result != 0) + { + warn(); + goto cleanup; + } p = tcache.tail; move = RIGHT; continue; @@ -1321,7 +1333,12 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* definite length method */ if (len2 > counter) { - _asn1_append_sequence_set (p, &tcache); + result = _asn1_append_sequence_set (p, &tcache); + if (result != 0) + { + warn(); + goto cleanup; + } p = tcache.tail; move = RIGHT; continue; @@ -1375,7 +1392,14 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, || (type_field (p2->type) == ASN1_ETYPE_SIZE)) p2 = p2->right; if (p2->right == NULL) - _asn1_append_sequence_set (p, &tcache); + { + result = _asn1_append_sequence_set (p, &tcache); + if (result != 0) + { + warn(); + goto cleanup; + } + } p = p2; } } @@ -1434,8 +1458,8 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if (result != ASN1_SUCCESS) { warn(); - goto cleanup; - } + goto cleanup; + } DECR_LEN(ider_len, len2); _asn1_set_value_lv (p, der + counter, len2); @@ -1470,7 +1494,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if (p) { - p->end = counter - 1; + p->end = counter - 1; } if (p == node && move != DOWN) @@ -2199,7 +2223,8 @@ _asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, } /* indefinite constructed */ - if (((dflags & DECODE_FLAG_INDEFINITE) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) + if ((((dflags & DECODE_FLAG_INDEFINITE) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) && + !(dflags & DECODE_FLAG_LEVEL3)) { len_len = 1; @@ -2219,8 +2244,17 @@ _asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, do { unsigned tmp_len; + unsigned flags = DECODE_FLAG_HAVE_TAG; - result = asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len); + if (dflags & DECODE_FLAG_LEVEL1) + flags |= DECODE_FLAG_LEVEL2; + else if (dflags & DECODE_FLAG_LEVEL2) + flags |= DECODE_FLAG_LEVEL3; + else + flags |= DECODE_FLAG_LEVEL1; + + result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, + flags); if (result != ASN1_SUCCESS) { warn(); @@ -2250,8 +2284,8 @@ _asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, if (p[0] == 0 && p[1] == 0) /* EOC */ { if (ber_len) *ber_len += 2; - break; - } + break; + } /* no EOC */ der_len += 2; diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c index b7a0905efb..b09f82647f 100644 --- a/lib/minitasn1/element.c +++ b/lib/minitasn1/element.c @@ -128,7 +128,7 @@ _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, return ASN1_SUCCESS; } -/* Appends a new element into the sequent (or set) defined by this +/* Appends a new element into the sequence (or set) defined by this * node. The new element will have a name of '?number', where number * is a monotonically increased serial number. * @@ -753,7 +753,8 @@ asn1_write_value (asn1_node node_root, const char *name, * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough * to store the result, and in this case @len will contain the number of - * bytes needed. + * bytes needed. On the occasion that the stored data are of zero-length + * this function may return %ASN1_SUCCESS even if the provided @len is zero. **/ int asn1_read_value (asn1_node root, const char *name, void *ivalue, int *len) @@ -826,7 +827,8 @@ asn1_read_value (asn1_node root, const char *name, void *ivalue, int *len) * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough * to store the result, and in this case @len will contain the number of - * bytes needed. + * bytes needed. On the occasion that the stored data are of zero-length + * this function may return %ASN1_SUCCESS even if the provided @len is zero. **/ int asn1_read_value_type (asn1_node root, const char *name, void *ivalue, @@ -932,7 +934,7 @@ asn1_read_value_type (asn1_node root, const char *name, void *ivalue, { *len = 0; if (value) - value[0] = 0; + value[0] = 0; p = node->down; while (p) { diff --git a/lib/minitasn1/errors.c b/lib/minitasn1/errors.c index e9fa302605..fef45ae742 100644 --- a/lib/minitasn1/errors.c +++ b/lib/minitasn1/errors.c @@ -52,6 +52,7 @@ static const libtasn1_error_entry error_algorithms[] = { LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG), LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR), LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY), + LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR), {0, 0} }; diff --git a/lib/minitasn1/libtasn1.h b/lib/minitasn1/libtasn1.h index 5c4340f133..626b11ec67 100644 --- a/lib/minitasn1/libtasn1.h +++ b/lib/minitasn1/libtasn1.h @@ -44,7 +44,7 @@ extern "C" { #endif -#define ASN1_VERSION "4.9" +#define ASN1_VERSION "4.12" #if defined(__GNUC__) && !defined(ASN1_INTERNAL_BUILD) # define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) @@ -78,6 +78,7 @@ extern "C" #define ASN1_NAME_TOO_LONG 15 #define ASN1_ARRAY_ERROR 16 #define ASN1_ELEMENT_NOT_EMPTY 17 +#define ASN1_TIME_ENCODING_ERROR 18 /*************************************/ /* Constants used in asn1_visit_tree */ @@ -190,6 +191,8 @@ extern "C" #define ASN1_DECODE_FLAG_ALLOW_PADDING 1 /* This flag would ensure that no BER decoding takes place */ #define ASN1_DECODE_FLAG_STRICT_DER (1<<1) +/* This flag will tolerate Time encoding errors when in strict DER */ +#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2) struct asn1_data_node_st @@ -377,7 +380,7 @@ extern "C" extern ASN1_API int asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, - char *str, int str_size); + char *str, int str_size); /* Compatibility types */ diff --git a/lib/minitasn1/parser_aux.c b/lib/minitasn1/parser_aux.c index 2285b20f58..786ea640a4 100644 --- a/lib/minitasn1/parser_aux.c +++ b/lib/minitasn1/parser_aux.c @@ -84,7 +84,7 @@ _asn1_add_static_node (unsigned int type) * @name: null terminated string with the element's name to find. * * Searches for an element called @name starting from @pointer. The - * name is composed by differents identifiers separated by dots. When + * name is composed by different identifiers separated by dots. When * *@pointer has a name, the first identifier must be the name of * *@pointer, otherwise it must be the name of one child of *@pointer. * @@ -120,6 +120,9 @@ asn1_find_node (asn1_node pointer, const char *name) if (n_end) { nsize = n_end - n_start; + if (nsize >= sizeof(n)) + return NULL; + memcpy (n, n_start, nsize); n[nsize] = 0; n_start = n_end; @@ -158,6 +161,9 @@ asn1_find_node (asn1_node pointer, const char *name) if (n_end) { nsize = n_end - n_start; + if (nsize >= sizeof(n)) + return NULL; + memcpy (n, n_start, nsize); n[nsize] = 0; n_start = n_end; @@ -551,29 +557,33 @@ _asn1_delete_list_and_nodes (void) char * _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) { - int64_t d, r; + uint64_t d, r; char temp[LTOSTR_MAX_SIZE]; int count, k, start; + uint64_t val; if (v < 0) { str[0] = '-'; start = 1; - v = -v; + val = -((uint64_t)v); } else - start = 0; + { + val = v; + start = 0; + } count = 0; do { - d = v / 10; - r = v - d * 10; + d = val / 10; + r = val - d * 10; temp[start + count] = '0' + (char) r; count++; - v = d; + val = d; } - while (v && ((start+count) < LTOSTR_MAX_SIZE-1)); + while (val && ((start+count) < LTOSTR_MAX_SIZE-1)); for (k = 0; k < count; k++) str[k + start] = temp[start + count - k - 1]; @@ -637,7 +647,7 @@ _asn1_change_integer_value (asn1_node node) p = NULL; break; } - if (p->right) + if (p && p->right) { p = p->right; break; @@ -753,7 +763,7 @@ _asn1_expand_object_id (asn1_node node) if (move == RIGHT) { - if (p->right) + if (p && p->right) p = p->right; else move = UP; @@ -828,7 +838,7 @@ _asn1_expand_object_id (asn1_node node) if (move == RIGHT) { - if (p->right) + if (p && p->right) p = p->right; else move = UP; @@ -898,7 +908,7 @@ _asn1_type_set_config (asn1_node node) if (move == RIGHT) { - if (p->right) + if (p && p->right) p = p->right; else move = UP; @@ -945,7 +955,7 @@ _asn1_check_identifier (asn1_node node) if (p2 == NULL) { if (p->value) - _asn1_strcpy (_asn1_identifierMissing, p->value); + _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value); else _asn1_strcpy (_asn1_identifierMissing, "(null)"); return ASN1_IDENTIFIER_NOT_FOUND; @@ -958,9 +968,15 @@ _asn1_check_identifier (asn1_node node) if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) { _asn1_str_cpy (name2, sizeof (name2), node->name); - _asn1_str_cat (name2, sizeof (name2), "."); - _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); - _asn1_strcpy (_asn1_identifierMissing, p2->value); + if (p2->value) + { + _asn1_str_cat (name2, sizeof (name2), "."); + _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); + _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); + } + else + _asn1_strcpy (_asn1_identifierMissing, "(null)"); + p2 = asn1_find_node (node, name2); if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || !(p2->type & CONST_ASSIGN)) @@ -980,7 +996,8 @@ _asn1_check_identifier (asn1_node node) _asn1_str_cpy (name2, sizeof (name2), node->name); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); - _asn1_strcpy (_asn1_identifierMissing, p2->value); + _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); + p2 = asn1_find_node (node, name2); if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || !(p2->type & CONST_ASSIGN)) @@ -1007,7 +1024,7 @@ _asn1_check_identifier (asn1_node node) p = NULL; break; } - if (p->right) + if (p && p->right) { p = p->right; break; @@ -1067,7 +1084,7 @@ _asn1_set_default_tag (asn1_node node) p = NULL; break; } - if (p->right) + if (p && p->right) { p = p->right; break; |