diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-04-09 08:17:22 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-04-09 08:17:22 +0200 |
commit | 3e01143ad960a2693bee91b26a91d3b23d04bb3c (patch) | |
tree | d3118dcfd23c789f75a3e7c323ef69f7a7a1f367 | |
parent | 259278197b6bfcadf333cda9e98ac330f88057f0 (diff) | |
download | gnutls-3e01143ad960a2693bee91b26a91d3b23d04bb3c.tar.gz |
minitasn1: updated to latest git version
-rw-r--r-- | lib/minitasn1/coding.c | 15 | ||||
-rw-r--r-- | lib/minitasn1/decoding.c | 581 | ||||
-rw-r--r-- | lib/minitasn1/element.c | 26 | ||||
-rw-r--r-- | lib/minitasn1/element.h | 8 | ||||
-rw-r--r-- | lib/minitasn1/int.h | 30 | ||||
-rw-r--r-- | lib/minitasn1/libtasn1.h | 7 | ||||
-rw-r--r-- | lib/minitasn1/parser_aux.c | 51 | ||||
-rw-r--r-- | lib/minitasn1/parser_aux.h | 13 | ||||
-rw-r--r-- | lib/minitasn1/structure.c | 34 |
9 files changed, 409 insertions, 356 deletions
diff --git a/lib/minitasn1/coding.c b/lib/minitasn1/coding.c index 2dd80ba419..0c0f69c5ce 100644 --- a/lib/minitasn1/coding.c +++ b/lib/minitasn1/coding.c @@ -443,7 +443,9 @@ asn1_bit_der (const unsigned char *str, int bit_len, len_byte++; asn1_length_der (len_byte + 1, der, &len_len); der[len_len] = len_pad; - memcpy (der + len_len + 1, str, len_byte); + + if (str) + memcpy (der + len_len + 1, str, len_byte); der[len_len + len_byte] &= bit_mask[len_pad]; *der_len = len_byte + len_len + 1; } @@ -628,7 +630,7 @@ _asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, tag_der, &tag_len); *max_len -= tag_len; - if (*max_len >= 0) + if (der && *max_len >= 0) memcpy (der + *counter, tag_der, tag_len); *counter += tag_len; @@ -680,7 +682,7 @@ _asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, } *max_len -= tag_len; - if (*max_len >= 0) + if (der && *max_len >= 0) memcpy (der + *counter, tag_der, tag_len); *counter += tag_len; @@ -1018,6 +1020,9 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, int err; unsigned char *der = ider; + if (ErrorDescription) + ErrorDescription[0] = 0; + node = asn1_find_node (element, name); if (node == NULL) return ASN1_ELEMENT_NOT_FOUND; @@ -1248,7 +1253,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, continue; } else - p = _asn1_get_up (p); + p = _asn1_find_up (p); move = UP; } if (move == UP) @@ -1323,7 +1328,7 @@ asn1_der_coding (asn1_node element, const char *name, void *ider, int *len, move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } *len = counter; diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c index 42ddc6be03..e5513a38b0 100644 --- a/lib/minitasn1/decoding.c +++ b/lib/minitasn1/decoding.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2014 Free Software Foundation, Inc. + * Copyright (C) 2002-2016 Free Software Foundation, Inc. * * This file is part of LIBTASN1. * @@ -43,6 +43,9 @@ #define HAVE_TWO(x) (x>=2?1:0) +#define DECODE_FLAG_HAVE_TAG 1 +#define DECODE_FLAG_INDEFINITE (1<<1) + #define DECR_LEN(l, s) do { \ l -= s; \ if (l < 0) { \ @@ -55,6 +58,17 @@ static int _asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len); +static 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, + unsigned dflags); + +static int +_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, + unsigned int _der_len, const unsigned char **str, + unsigned int *str_len, unsigned dflags); + static void _asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) { @@ -236,13 +250,15 @@ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) /** * asn1_get_octet_der: * @der: DER data to decode containing the OCTET SEQUENCE. - * @der_len: Length of DER data to decode. - * @ret_len: Output variable containing the length of the DER data. + * @der_len: The length of the @der data to decode. + * @ret_len: Output variable containing the encoded length of the DER data. * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. * @str_size: Length of pre-allocated output buffer. - * @str_len: Output variable containing the length of the OCTET SEQUENCE. + * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE. * - * Extract an OCTET SEQUENCE from DER data. + * Extract an OCTET SEQUENCE from DER data. Note that this function + * expects the DER data past the tag field, i.e., the length and + * content octets. * * Returns: Returns %ASN1_SUCCESS on success, or an error. **/ @@ -275,9 +291,23 @@ asn1_get_octet_der (const unsigned char *der, int der_len, return ASN1_SUCCESS; } -/* Returns ASN1_SUCCESS on success or an error code on error. - * type should be one of ASN1_ETYPE_GENERALIZED_TIME or ASN1_ETYPE_UTC_TIME. - */ + +/*- + * _asn1_get_time_der: + * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME + * @der: DER data to decode containing the time + * @der_len: Length of DER data to decode. + * @ret_len: Output variable containing the length of the DER data. + * @str: Pre-allocated output buffer to put the textual time in. + * @str_size: Length of pre-allocated output buffer. + * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER + * + * Performs basic checks in the DER encoded time object and returns its textual form. + * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime + * and YYMMDD000000Z for UTCTime. + * + * Returns: %ASN1_SUCCESS on success, or an error. + -*/ static int _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len, char *str, int str_size, unsigned flags) @@ -329,7 +359,7 @@ _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *r } warn(); - return ASN1_DER_ERROR; + return ASN1_DER_ERROR; } } @@ -346,8 +376,20 @@ _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *r return ASN1_SUCCESS; } -static int -_asn1_get_objectid_der (const unsigned char *der, int der_len, int *ret_len, +/** + * asn1_get_objectid_der: + * @der: DER data to decode containing the OBJECT IDENTIFIER + * @der_len: Length of DER data to decode. + * @ret_len: Output variable containing the length of the DER data. + * @str: Pre-allocated output buffer to put the textual object id in. + * @str_size: Length of pre-allocated output buffer. + * + * Converts a DER encoded object identifier to its textual form. + * + * Returns: %ASN1_SUCCESS on success, or an error. + **/ +int +asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, char *str, int str_size) { int len_len, len, k; @@ -419,7 +461,7 @@ _asn1_get_objectid_der (const unsigned char *der, int der_len, int *ret_len, * * Extract a BIT SEQUENCE from DER data. * - * Returns: Return %ASN1_SUCCESS on success, or an error. + * Returns: %ASN1_SUCCESS on success, or an error. **/ int asn1_get_bit_der (const unsigned char *der, int der_len, @@ -454,10 +496,12 @@ asn1_get_bit_der (const unsigned char *der, int der_len, return ASN1_SUCCESS; } - +/* tag_len: the total tag length (explicit+inner) + * inner_tag_len: the inner_tag length + */ static int _asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, - int *ret_len, unsigned flags) + int *tag_len, int *inner_tag_len, unsigned flags) { asn1_node p; int counter, len2, len3, is_tag_implicit; @@ -568,7 +612,9 @@ _asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, unsigned type = type_field (node->type); if (type == ASN1_ETYPE_TAG) { - *ret_len = 0; + *tag_len = 0; + if (inner_tag_len) + *inner_tag_len = 0; return ASN1_SUCCESS; } @@ -628,7 +674,9 @@ _asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, } counter += len2; - *ret_len = counter; + *tag_len = counter; + if (inner_tag_len) + *inner_tag_len = len2; return ASN1_SUCCESS; cleanup: @@ -637,7 +685,7 @@ cleanup: static int extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len, - int *ret_len, unsigned flags) + int *ret_len, int *inner_len, unsigned flags) { asn1_node p; int ris = ASN1_DER_ERROR; @@ -647,7 +695,7 @@ int ris = ASN1_DER_ERROR; p = node->down; while (p) { - ris = _asn1_extract_tag_der (p, der, der_len, ret_len, flags); + ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags); if (ris == ASN1_SUCCESS) break; p = p->right; @@ -657,7 +705,7 @@ int ris = ASN1_DER_ERROR; return ris; } else - return _asn1_extract_tag_der (node, der, der_len, ret_len, flags); + return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags); } static int @@ -678,7 +726,7 @@ _asn1_delete_not_used (asn1_node node) { p2 = _asn1_find_left (p); if (!p2) - p2 = _asn1_get_up (p); + p2 = _asn1_find_up (p); } asn1_delete_structure (&p); p = p2; @@ -701,7 +749,7 @@ _asn1_delete_not_used (asn1_node node) { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == node) { p = NULL; @@ -720,167 +768,6 @@ _asn1_delete_not_used (asn1_node node) } static int -_asn1_extract_der_octet (asn1_node node, const unsigned char *der, - int der_len, unsigned flags) -{ - int len2, len3; - int counter, counter_end; - int result; - - len2 = asn1_get_length_der (der, der_len, &len3); - if (len2 < -1) - return ASN1_DER_ERROR; - - counter = len3 + 1; - DECR_LEN(der_len, len3); - - if (len2 == -1) - counter_end = der_len - 2; - else - counter_end = der_len; - - while (counter < counter_end) - { - DECR_LEN(der_len, 1); - len2 = asn1_get_length_der (der + counter, der_len, &len3); - - if (IS_ERR(len2, flags)) - { - warn(); - return ASN1_DER_ERROR; - } - - if (len2 >= 0) - { - DECR_LEN(der_len, len2+len3); - _asn1_append_value (node, der + counter + len3, len2); - } - else - { /* indefinite */ - DECR_LEN(der_len, len3); - result = - _asn1_extract_der_octet (node, der + counter + len3, - der_len, flags); - if (result != ASN1_SUCCESS) - return result; - len2 = 0; - } - - counter += len2 + len3 + 1; - } - - return ASN1_SUCCESS; - -cleanup: - return result; -} - -static int -_asn1_get_octet_string (asn1_node node, const unsigned char *der, int der_len, - int *len, unsigned flags) -{ - int len2, len3, counter, tot_len, indefinite; - int result; - int orig_der_len = der_len; - - counter = 0; - - if (*(der - 1) & ASN1_CLASS_STRUCTURED) - { - tot_len = 0; - - indefinite = asn1_get_length_der (der, der_len, &len3); - if (IS_ERR(indefinite, flags)) - { - warn(); - return ASN1_DER_ERROR; - } - - counter += len3; - DECR_LEN(der_len, len3); - - if (indefinite >= 0) - indefinite += len3; - - while (1) - { - if (indefinite == -1) - { - if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0)) - { - counter += 2; - DECR_LEN(der_len, 2); - break; - } - } - else if (counter >= indefinite) - break; - - DECR_LEN(der_len, 1); - if (der[counter] != ASN1_TAG_OCTET_STRING) - { - warn(); - return ASN1_DER_ERROR; - } - - counter++; - - len2 = asn1_get_length_der (der + counter, der_len, &len3); - if (len2 <= 0) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(der_len, len3 + len2); - counter += len3 + len2; - - tot_len += len2; - } - - /* copy */ - if (node) - { - unsigned char temp[ASN1_MAX_LENGTH_SIZE]; - int ret; - - len2 = sizeof (temp); - - asn1_length_der (tot_len, temp, &len2); - _asn1_set_value (node, temp, len2); - - ret = _asn1_extract_der_octet (node, der, orig_der_len, flags); - if (ret != ASN1_SUCCESS) - { - warn(); - return ret; - } - - } - } - else - { /* NOT STRUCTURED */ - len2 = asn1_get_length_der (der, der_len, &len3); - if (len2 < 0) - { - warn(); - return ASN1_DER_ERROR; - } - - DECR_LEN(der_len, len3+len2); - counter = len3 + len2; - if (node) - _asn1_set_value (node, der, counter); - } - - *len = counter; - return ASN1_SUCCESS; - -cleanup: - return result; -} - -static int _asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len) { @@ -982,11 +869,14 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, asn1_node node, p, p2, p3; char temp[128]; int counter, len2, len3, len4, move, ris, tlen; - asn1_node ptail = NULL; + struct node_tail_cache_st tcache = {NULL, NULL}; unsigned char class; unsigned long tag; int tag_len; int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; + int inner_tag_len; + unsigned char *ptmp; + const unsigned char *ptag; const unsigned char *der = ider; node = *element; @@ -1010,12 +900,13 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, while (1) { tag_len = 0; + inner_tag_len = 0; ris = ASN1_SUCCESS; if (move != UP) { if (p->type & CONST_SET) { - p2 = _asn1_get_up (p); + p2 = _asn1_find_up (p); len2 = p2->tmp_ival; if (len2 == -1) { @@ -1047,7 +938,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { ris = extract_tag_der_recursive (p2, der + counter, - ider_len, &len2, flags); + ider_len, &len2, NULL, flags); if (ris == ASN1_SUCCESS) { p2->type &= ~CONST_NOT_USED; @@ -1071,7 +962,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) { - p2 = _asn1_get_up (p); + p2 = _asn1_find_up (p); len2 = p2->tmp_ival; if (counter == len2) { @@ -1097,7 +988,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { ris = extract_tag_der_recursive (p->down, der + counter, - ider_len, &len2, flags); + ider_len, &len2, NULL, flags); if (ris == ASN1_SUCCESS) { @@ -1134,7 +1025,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) { - p2 = _asn1_get_up (p); + p2 = _asn1_find_up (p); len2 = p2->tmp_ival; if ((len2 != -1) && (counter > len2)) @@ -1144,7 +1035,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, if (ris == ASN1_SUCCESS) ris = extract_tag_der_recursive (p, der + counter, ider_len, - &tag_len, flags); + &tag_len, &inner_tag_len, flags); if (ris != ASN1_SUCCESS) { @@ -1224,7 +1115,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, break; case ASN1_ETYPE_OBJECT_ID: result = - _asn1_get_objectid_der (der + counter, ider_len, &len2, + asn1_get_object_id_der (der + counter, ider_len, &len2, temp, sizeof (temp)); if (result != ASN1_SUCCESS) { @@ -1262,15 +1153,51 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, move = RIGHT; break; case ASN1_ETYPE_OCTET_STRING: - result = _asn1_get_octet_string (p, der + counter, ider_len, &len3, flags); - if (result != ASN1_SUCCESS) + if (counter < inner_tag_len) { + result = ASN1_DER_ERROR; warn(); goto cleanup; - } + } + + ptag = der + counter - inner_tag_len; + if (flags & ASN1_DECODE_FLAG_STRICT_DER || !(ptag[0] & ASN1_CLASS_STRUCTURED)) + { + len2 = + asn1_get_length_der (der + counter, ider_len, &len3); + if (len2 < 0) + { + result = ASN1_DER_ERROR; + warn(); + goto cleanup; + } + + DECR_LEN(ider_len, len3+len2); + + _asn1_set_value (p, der + counter, len3 + len2); + counter += len3 + len2; + } + else + { + unsigned dflags = 0, vlen, ber_len; + + if (ptag[0] & ASN1_CLASS_STRUCTURED) + dflags |= DECODE_FLAG_INDEFINITE; - DECR_LEN(ider_len, len3); - counter += len3; + result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags); + if (result != ASN1_SUCCESS) + { + warn(); + goto cleanup; + } + + DECR_LEN(ider_len, ber_len); + + _asn1_set_value_lv (p, ptmp, vlen); + + counter += ber_len; + free(ptmp); + } move = RIGHT; break; case ASN1_ETYPE_GENERALSTRING: @@ -1377,14 +1304,15 @@ 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, &ptail); - p = ptail; + _asn1_append_sequence_set (p, &tcache); + p = tcache.tail; move = RIGHT; continue; } p->tmp_ival = 0; - ptail = NULL; /* finished decoding this structure */ + tcache.tail = NULL; /* finished decoding this structure */ + tcache.head = NULL; DECR_LEN(ider_len, 2); counter += 2; } @@ -1392,14 +1320,15 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* definite length method */ if (len2 > counter) { - _asn1_append_sequence_set (p, &ptail); - p = ptail; + _asn1_append_sequence_set (p, &tcache); + p = tcache.tail; move = RIGHT; continue; } p->tmp_ival = 0; - ptail = NULL; /* finished decoding this structure */ + tcache.tail = NULL; /* finished decoding this structure */ + tcache.head = NULL; if (len2 != counter) { @@ -1437,7 +1366,7 @@ 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, &ptail); + _asn1_append_sequence_set (p, &tcache); p = p2; } } @@ -1553,7 +1482,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } _asn1_delete_not_used (*element); @@ -1766,7 +1695,7 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) break; } - p3 = _asn1_get_up (p); + p3 = _asn1_find_up (p); if (!p3) { @@ -1786,8 +1715,8 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) (p3->value == NULL)) { - p3 = _asn1_get_up (p); - p3 = _asn1_get_up (p3); + p3 = _asn1_find_up (p); + p3 = _asn1_find_up (p3); if (!p3) { @@ -1922,7 +1851,7 @@ asn1_expand_any_defined_by (asn1_node definitions, asn1_node * element) { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == *element) { p = NULL; @@ -2082,23 +2011,24 @@ asn1_expand_octet_string (asn1_node definitions, asn1_node * element, return retCode; } -/** - * asn1_decode_simple_der: +/*- + * _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 * @str: a pointer to the data * @str_len: the length of the data + * @dflags: DECODE_FLAG_* * * Decodes a simple DER encoded type (e.g. a string, which is not constructed). * The output is a pointer inside the @der. * * Returns: %ASN1_SUCCESS if successful or an error value. - **/ -int -asn1_decode_simple_der (unsigned int etype, const unsigned char *der, + -*/ +static int +_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, unsigned int _der_len, const unsigned char **str, - unsigned int *str_len) + unsigned int *str_len, unsigned dflags) { int tag_len, len_len; const unsigned char *p; @@ -2110,25 +2040,33 @@ asn1_decode_simple_der (unsigned int etype, const unsigned char *der, if (der == NULL || der_len == 0) return ASN1_VALUE_NOT_VALID; - if (ETYPE_OK (etype) == 0) + if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0) return ASN1_VALUE_NOT_VALID; /* doesn't handle constructed classes */ - if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) + class = ETYPE_CLASS(etype); + if (class != ASN1_CLASS_UNIVERSAL) return ASN1_VALUE_NOT_VALID; p = der; - ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); - if (ret != ASN1_SUCCESS) - return ret; - if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) - return ASN1_DER_ERROR; + if (dflags & DECODE_FLAG_HAVE_TAG) + { + ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); + if (ret != ASN1_SUCCESS) + return ret; - p += tag_len; - der_len -= tag_len; - if (der_len <= 0) - return ASN1_DER_ERROR; + if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) + { + warn(); + return ASN1_DER_ERROR; + } + + 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) @@ -2145,9 +2083,30 @@ asn1_decode_simple_der (unsigned int etype, const unsigned char *der, return ASN1_SUCCESS; } +/** + * 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 + * @str: a pointer to the data + * @str_len: the length of the data + * + * Decodes a simple DER encoded type (e.g. a string, which is not constructed). + * The output is a pointer inside the @der. + * + * Returns: %ASN1_SUCCESS if successful or an error value. + **/ +int +asn1_decode_simple_der (unsigned int etype, const unsigned char *der, + unsigned int _der_len, const unsigned char **str, + unsigned int *str_len) +{ + return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG); +} + static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size) { - *dst = realloc(*dst, *dst_size+src_size); + *dst = _asn1_realloc(*dst, *dst_size+src_size); if (*dst == NULL) return ASN1_MEM_ERROR; memcpy(*dst + *dst_size, src, src_size); @@ -2155,25 +2114,27 @@ static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, u return ASN1_SUCCESS; } -/** - * asn1_decode_simple_ber: +/*- + * _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) + * @have_tag: whether a DER tag is included * * 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, + -*/ +static 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) + unsigned int *str_len, unsigned int *ber_len, + unsigned dflags) { int tag_len, len_len; const unsigned char *p; @@ -2183,8 +2144,9 @@ asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, unsigned char class; unsigned long tag; unsigned char *out = NULL; + const unsigned char *cout = NULL; unsigned out_len; - long ret; + long result; if (ber_len) *ber_len = 0; @@ -2200,53 +2162,52 @@ asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, return ASN1_VALUE_NOT_VALID; } - /* doesn't handle constructed classes */ - if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) + /* doesn't handle constructed + definite classes */ + class = ETYPE_CLASS (etype); + if (class != 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) + + if (dflags & DECODE_FLAG_HAVE_TAG) { - warn(); - return ret; - } + result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); + if (result != ASN1_SUCCESS) + { + warn(); + return result; + } - if (ber_len) *ber_len += tag_len; + if (tag != ETYPE_TAG (etype)) + { + warn(); + return ASN1_DER_ERROR; + } - if (tag != ETYPE_TAG (etype)) - { - warn(); - return ASN1_DER_ERROR; - } + p += tag_len; - p += tag_len; - der_len -= tag_len; - if (der_len <= 0) - return ASN1_DER_ERROR; + DECR_LEN(der_len, tag_len); - 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)) - { + if (ber_len) *ber_len += tag_len; + } + /* indefinite constructed */ + if (((dflags & DECODE_FLAG_INDEFINITE) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) + { len_len = 1; + + DECR_LEN(der_len, len_len); if (p[0] != 0x80) { warn(); - return ASN1_DER_ERROR; + result = ASN1_DER_ERROR; + goto cleanup; } p += len_len; - der_len -= len_len; - if (der_len <= 0) - return ASN1_DER_ERROR; if (ber_len) *ber_len += len_len; @@ -2255,38 +2216,48 @@ asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, { unsigned tmp_len; - ret = asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len); - if (ret != ASN1_SUCCESS) + result = asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len); + if (result != ASN1_SUCCESS) { - free(total); - return ret; + warn(); + goto cleanup; } + p += tmp_len; - der_len -= tmp_len; + DECR_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; - } + DECR_LEN(der_len, 2); /* we need the EOC */ if (out_len > 0) { - ret = append(&total, &total_size, out, out_len); - free(out); - if (ret != ASN1_SUCCESS) + result = append(&total, &total_size, out, out_len); + if (result != ASN1_SUCCESS) { - free(total); - return ret; + warn(); + goto cleanup; } } + free(out); + out = NULL; + if (p[0] == 0 && p[1] == 0) /* EOC */ { if (ber_len) *ber_len += 2; break; } + + /* no EOC */ + der_len += 2; + + if (der_len == 2) + { + warn(); + result = ASN1_DER_ERROR; + goto cleanup; + } } while(1); } @@ -2294,29 +2265,67 @@ asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, { if (ber_len) { - ret = asn1_get_length_der (p, der_len, &len_len); - if (ret < 0) + result = asn1_get_length_der (p, der_len, &len_len); + if (result < 0) { warn(); - return ASN1_DER_ERROR; + result = ASN1_DER_ERROR; + goto cleanup; } - *ber_len += ret + len_len; + *ber_len += result + 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; + result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags); + if (result != ASN1_SUCCESS) + { + warn(); + goto cleanup; + } - ret = append(&total, &total_size, out, out_len); - if (ret != ASN1_SUCCESS) - return ret; + result = append(&total, &total_size, cout, out_len); + if (result != ASN1_SUCCESS) + { + warn(); + goto cleanup; + } } else - return ASN1_DER_ERROR; + { + warn(); + result = ASN1_DER_ERROR; + goto cleanup; + } *str = total; *str_len = total_size; return ASN1_SUCCESS; +cleanup: + free(out); + free(total); + return result; +} + +/** + * 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) +{ + return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG); } diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c index 321302af06..dceb8ba83e 100644 --- a/lib/minitasn1/element.c +++ b/lib/minitasn1/element.c @@ -52,7 +52,7 @@ _asn1_hierarchical_name (asn1_node node, char *name, int name_size) _asn1_str_cat (name, name_size, "."); _asn1_str_cat (name, name_size, tmp_name); } - p = _asn1_get_up (p); + p = _asn1_find_up (p); } if (name[0] == 0) @@ -132,14 +132,14 @@ _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, * node. The new element will have a name of '?number', where number * is a monotonically increased serial number. * - * The last element in the list may be provided in @ptail, to avoid + * The last element in the list may be provided in @pcache, to avoid * traversing the list, an expensive operation in long lists. * - * On success it returns in @ptail the added element (which is the + * On success it returns in @pcache the added element (which is the * tail in the list of added elements). */ int -_asn1_append_sequence_set (asn1_node node, asn1_node *ptail) +_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) { asn1_node p, p2; char temp[LTOSTR_MAX_SIZE]; @@ -154,18 +154,24 @@ _asn1_append_sequence_set (asn1_node node, asn1_node *ptail) p = p->right; p2 = _asn1_copy_structure3 (p); - if (ptail == NULL || *ptail == NULL || (*ptail)->up != p->up) - while (p->right) { - p = p->right; + if (pcache == NULL || pcache->tail == NULL || pcache->head != node) + { + while (p->right) + { + p = p->right; + } } else { - p = *ptail; + p = pcache->tail; } _asn1_set_right (p, p2); - if (ptail) - *ptail = p2; + if (pcache) + { + pcache->head = node; + pcache->tail = p2; + } if (p->name[0] == 0) _asn1_str_cpy (temp, sizeof (temp), "?1"); diff --git a/lib/minitasn1/element.h b/lib/minitasn1/element.h index 65a4845699..4e45367415 100644 --- a/lib/minitasn1/element.h +++ b/lib/minitasn1/element.h @@ -23,7 +23,13 @@ #define _ELEMENT_H -int _asn1_append_sequence_set (asn1_node node, asn1_node *pcached); +struct node_tail_cache_st +{ + asn1_node head; /* the first element of the sequence */ + asn1_node tail; +}; + +int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached); int _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, diff --git a/lib/minitasn1/int.h b/lib/minitasn1/int.h index 8cc79cca2e..f1f13024e4 100644 --- a/lib/minitasn1/int.h +++ b/lib/minitasn1/int.h @@ -51,7 +51,6 @@ struct asn1_node_st unsigned int type; /* Node type */ unsigned char *value; /* Node value */ int value_len; - asn1_node up; /* Pointer to the parent node */ asn1_node down; /* Pointer to the son node */ asn1_node right; /* Pointer to the brother node */ asn1_node left; /* Pointer to the next list element */ @@ -98,9 +97,16 @@ typedef struct tag_and_class_st #define ETYPE_TAG(etype) (_asn1_tags[etype].tag) #define ETYPE_CLASS(etype) (_asn1_tags[etype].class) -#define ETYPE_OK(etype) ((etype != ASN1_ETYPE_INVALID && \ - etype <= _asn1_tags_size && \ - _asn1_tags[etype].desc != NULL)?1:0) +#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \ + (etype) <= _asn1_tags_size && \ + _asn1_tags[(etype)].desc != NULL)?1:0) + +#define ETYPE_IS_STRING(etype) ((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)?1:0) extern unsigned int _asn1_tags_size; extern const tag_and_class_st _asn1_tags[]; @@ -191,4 +197,20 @@ convert_old_type (unsigned int ntype) return ntype; } +static inline +void *_asn1_realloc(void *ptr, size_t size) +{ + void *ret; + + if (size == 0) + return ptr; + + ret = realloc(ptr, size); + if (ret == NULL) + { + free(ptr); + } + return ret; +} + #endif /* INT_H */ diff --git a/lib/minitasn1/libtasn1.h b/lib/minitasn1/libtasn1.h index 53cec5e6a1..aa9e8a480c 100644 --- a/lib/minitasn1/libtasn1.h +++ b/lib/minitasn1/libtasn1.h @@ -44,7 +44,7 @@ extern "C" { #endif -#define ASN1_VERSION "4.4" +#define ASN1_VERSION "4.8" #if defined(__GNUC__) && !defined(ASN1_INTERNAL_BUILD) # define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) @@ -374,6 +374,11 @@ extern "C" int *ret_len, unsigned char *str, int str_size, int *bit_len); + extern ASN1_API int + asn1_get_object_id_der (const unsigned char *der, + int der_len, int *ret_len, + char *str, int str_size); + /* Compatibility types */ typedef int asn1_retCode; /* type returned by libtasn1 functions */ diff --git a/lib/minitasn1/parser_aux.c b/lib/minitasn1/parser_aux.c index da9a388fe3..52700c6d0a 100644 --- a/lib/minitasn1/parser_aux.c +++ b/lib/minitasn1/parser_aux.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2014 Free Software Foundation, Inc. + * Copyright (C) 2000-2016 Free Software Foundation, Inc. * * This file is part of LIBTASN1. * @@ -316,39 +316,49 @@ _asn1_append_value (asn1_node node, const void *value, unsigned int len) { if (node == NULL) return node; - if (node->value != NULL && node->value != node->small_value) + + if (node->value == NULL) + return _asn1_set_value (node, value, len); + + if (len == 0) + return node; + + if (node->value == node->small_value) { - /* value is allocated */ + /* value is in node */ int prev_len = node->value_len; node->value_len += len; - node->value = realloc (node->value, node->value_len); + node->value = malloc (node->value_len); if (node->value == NULL) { node->value_len = 0; return NULL; } + + if (prev_len > 0) + memcpy (node->value, node->small_value, prev_len); + memcpy (&node->value[prev_len], value, len); return node; } - else if (node->value == node->small_value) + else /* if (node->value != NULL && node->value != node->small_value) */ { - /* value is in node */ + /* value is allocated */ int prev_len = node->value_len; node->value_len += len; - node->value = malloc (node->value_len); + + node->value = _asn1_realloc (node->value, node->value_len); if (node->value == NULL) { node->value_len = 0; return NULL; } - memcpy (node->value, node->small_value, prev_len); + memcpy (&node->value[prev_len], value, len); return node; } - else /* node->value == NULL */ - return _asn1_set_value (node, value, len); } /******************************************************************/ @@ -425,11 +435,7 @@ _asn1_set_right (asn1_node node, asn1_node right) return node; node->right = right; if (right) - { - right->left = node; - if (right->up == NULL) - right->up = node->up; - } + right->left = node; return node; } @@ -625,7 +631,7 @@ _asn1_change_integer_value (asn1_node node) { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == node) { p = NULL; @@ -753,7 +759,7 @@ _asn1_expand_object_id (asn1_node node) move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } @@ -786,6 +792,9 @@ _asn1_expand_object_id (asn1_node node) { if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) { + if (p4->value == NULL) + return ASN1_VALUE_NOT_FOUND; + if (name2[0]) _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), @@ -825,7 +834,7 @@ _asn1_expand_object_id (asn1_node node) move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } return ASN1_SUCCESS; @@ -895,7 +904,7 @@ _asn1_type_set_config (asn1_node node) move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } return ASN1_SUCCESS; @@ -992,7 +1001,7 @@ _asn1_check_identifier (asn1_node node) { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == node) { p = NULL; @@ -1052,7 +1061,7 @@ _asn1_set_default_tag (asn1_node node) { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == node) { p = NULL; diff --git a/lib/minitasn1/parser_aux.h b/lib/minitasn1/parser_aux.h index 437f1c863f..10b864b0f5 100644 --- a/lib/minitasn1/parser_aux.h +++ b/lib/minitasn1/parser_aux.h @@ -58,14 +58,6 @@ char *_asn1_ltostr (long v, char str[LTOSTR_MAX_SIZE]); asn1_node _asn1_find_up (asn1_node node); -inline static asn1_node _asn1_get_up(asn1_node node) -{ - if (node && node->up) - return node->up; - else - return _asn1_find_up(node); -} - int _asn1_change_integer_value (asn1_node node); int _asn1_expand_object_id (asn1_node node); @@ -108,10 +100,7 @@ _asn1_set_down (asn1_node node, asn1_node down) return node; node->down = down; if (down) - { - down->left = node; - down->up = node; - } + down->left = node; return node; } diff --git a/lib/minitasn1/structure.c b/lib/minitasn1/structure.c index ffb6aa5092..01715b138b 100644 --- a/lib/minitasn1/structure.c +++ b/lib/minitasn1/structure.c @@ -134,7 +134,7 @@ _asn1_create_static_structure (asn1_node pointer, char *output_file_name, { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == pointer) { p = NULL; @@ -183,6 +183,8 @@ asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, int result; unsigned int type; + if (errorDescription) + errorDescription[0] = 0; if (*definitions != NULL) return ASN1_ELEMENT_NOT_EMPTY; @@ -221,7 +223,7 @@ asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, if (p_last == *definitions) break; - p_last = _asn1_get_up (p_last); + p_last = _asn1_find_up (p_last); if (p_last == NULL) break; @@ -321,7 +323,7 @@ asn1_delete_structure2 (asn1_node * structure, unsigned int flags) p2 = p->right; if (p != *structure) { - p3 = _asn1_get_up (p); + p3 = _asn1_find_up (p); _asn1_set_down (p3, p2); _asn1_remove_node (p, flags); p = p3; @@ -331,7 +333,7 @@ asn1_delete_structure2 (asn1_node * structure, unsigned int flags) p3 = _asn1_find_left (p); if (!p3) { - p3 = _asn1_get_up (p); + p3 = _asn1_find_up (p); if (p3) _asn1_set_down (p3, p2); else @@ -379,7 +381,7 @@ asn1_delete_element (asn1_node structure, const char *element_name) p3 = _asn1_find_left (source_node); if (!p3) { - p3 = _asn1_get_up (source_node); + p3 = _asn1_find_up (source_node); if (p3) _asn1_set_down (p3, p2); else if (source_node->right) @@ -441,8 +443,8 @@ _asn1_copy_structure3 (asn1_node source_node) else { move = UP; - p_s = _asn1_get_up (p_s); - p_d = _asn1_get_up (p_d); + p_s = _asn1_find_up (p_s); + p_d = _asn1_find_up (p_d); } } while (p_s != source_node); @@ -542,7 +544,7 @@ _asn1_type_choice_config (asn1_node node) move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } return ASN1_SUCCESS; @@ -593,7 +595,7 @@ _asn1_expand_identifier (asn1_node * node, asn1_node root) _asn1_set_right (p3, p2); else { - p3 = _asn1_get_up (p); + p3 = _asn1_find_up (p); if (p3) _asn1_set_down (p3, p2); else @@ -649,7 +651,7 @@ _asn1_expand_identifier (asn1_node * node, asn1_node root) move = UP; } if (move == UP) - p = _asn1_get_up (p); + p = _asn1_find_up (p); } return ASN1_SUCCESS; @@ -832,7 +834,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, fprintf (out, " value:0x"); if (len > 0) for (k = 0; k < len; k++) - fprintf (out, "%02x", (p->value)[k + len2]); + fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); } break; case ASN1_ETYPE_ENUMERATED: @@ -843,7 +845,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, fprintf (out, " value:0x"); if (len > 0) for (k = 0; k < len; k++) - fprintf (out, "%02x", (p->value)[k + len2]); + fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); } break; case ASN1_ETYPE_BOOLEAN: @@ -865,7 +867,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, fprintf (out, " value(%i):", (len - 1) * 8 - (p->value[len2])); for (k = 1; k < len; k++) - fprintf (out, "%02x", (p->value)[k + len2]); + fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); } } break; @@ -905,7 +907,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, fprintf (out, " value:"); if (len > 0) for (k = 0; k < len; k++) - fprintf (out, "%02x", (p->value)[k + len2]); + fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); } break; case ASN1_ETYPE_OBJECT_ID: @@ -920,7 +922,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, fprintf (out, " value:"); if (len2 > 0) for (k = 0; k < len2; k++) - fprintf (out, "%02x", (p->value)[k + len3]); + fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); } break; case ASN1_ETYPE_SET: @@ -1017,7 +1019,7 @@ asn1_print_structure (FILE * out, asn1_node structure, const char *name, { while (1) { - p = _asn1_get_up (p); + p = _asn1_find_up (p); if (p == root) { p = NULL; |