diff -ur libtasn1-3.3/lib/decoding.c libtasn1-3.3.new/lib/decoding.c --- libtasn1-3.3/lib/decoding.c 2013-03-24 10:55:30.000000000 +0100 +++ libtasn1-3.3.new/lib/decoding.c 2014-05-29 11:03:39.837782788 +0200 @@ -33,8 +33,25 @@ #include #include +#ifdef DEBUG +# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) +#else +# define warn() +#endif + +#define HAVE_TWO(x) (x>=2?1:0) + +#define DECR_LEN(l, s) do { \ + l -= s; \ + if (l < 0) { \ + warn(); \ + result = ASN1_DER_ERROR; \ + goto cleanup; \ + } \ + } while (0) + static int -_asn1_get_indefinite_length_string (const unsigned char *der, int *len); +_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len); static void _asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) @@ -149,7 +166,7 @@ /* Long form */ punt = 1; ris = 0; - while (punt <= der_len && der[punt] & 128) + while (punt < der_len && der[punt] & 128) { if (INT_MULTIPLY_OVERFLOW (ris, 128)) @@ -206,8 +223,7 @@ ret = asn1_get_length_der (ber, ber_len, len); if (ret == -1) { /* indefinite length method */ - ret = ber_len; - err = _asn1_get_indefinite_length_string (ber + 1, &ret); + err = _asn1_get_indefinite_length_string (ber + 1, ber_len, &ret); if (err != ASN1_SUCCESS) return -3; } @@ -233,12 +249,11 @@ int *ret_len, unsigned char *str, int str_size, int *str_len) { - int len_len; + int len_len = 0; if (der_len <= 0) return ASN1_GENERIC_ERROR; - /* if(str==NULL) return ASN1_SUCCESS; */ *str_len = asn1_get_length_der (der, der_len, &len_len); if (*str_len < 0) @@ -246,7 +261,10 @@ *ret_len = *str_len + len_len; if (str_size >= *str_len) - memcpy (str, der + len_len, *str_len); + { + if (*str_len > 0 && str != NULL) + memcpy (str, der + len_len, *str_len); + } else { return ASN1_MEM_ERROR; @@ -265,9 +283,11 @@ if (der_len <= 0 || str == NULL) return ASN1_DER_ERROR; + str_len = asn1_get_length_der (der, der_len, &len_len); - if (str_len < 0 || str_size < str_len) + if (str_len <= 0 || str_size < str_len) return ASN1_DER_ERROR; + memcpy (str, der + len_len, str_len); str[str_len] = 0; *ret_len = str_len + len_len; @@ -293,7 +313,7 @@ len = asn1_get_length_der (der, der_len, &len_len); - if (len < 0 || len > der_len || len_len > der_len) + if (len <= 0 || len + len_len > der_len) return ASN1_DER_ERROR; val1 = der[len_len] / 40; @@ -355,10 +375,11 @@ int *ret_len, unsigned char *str, int str_size, int *bit_len) { - int len_len, len_byte; + int len_len = 0, len_byte; if (der_len <= 0) return ASN1_GENERIC_ERROR; + len_byte = asn1_get_length_der (der, der_len, &len_len) - 1; if (len_byte < 0) return ASN1_DER_ERROR; @@ -366,8 +387,14 @@ *ret_len = len_byte + len_len + 1; *bit_len = len_byte * 8 - der[len_len]; + if (*bit_len < 0) + return ASN1_DER_ERROR; + if (str_size >= len_byte) - memcpy (str, der + len_len + 1, len_byte); + { + if (len_byte > 0 && str) + memcpy (str, der + len_len + 1, len_byte); + } else { return ASN1_MEM_ERROR; @@ -382,6 +409,7 @@ { asn1_node p; int counter, len2, len3, is_tag_implicit; + int result; unsigned long tag, tag_implicit = 0; unsigned char class, class2, class_implicit = 0; @@ -409,23 +437,21 @@ if (p->type & CONST_EXPLICIT) { if (asn1_get_tag_der - (der + counter, der_len - counter, &class, &len2, + (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) return ASN1_DER_ERROR; - if (counter + len2 > der_len) - return ASN1_DER_ERROR; + DECR_LEN(der_len, len2); counter += len2; len3 = - asn1_get_length_ber (der + counter, der_len - counter, + asn1_get_length_ber (der + counter, der_len, &len2); if (len3 < 0) return ASN1_DER_ERROR; + DECR_LEN(der_len, len2); counter += len2; - if (counter > der_len) - return ASN1_DER_ERROR; if (!is_tag_implicit) { @@ -462,11 +488,11 @@ if (is_tag_implicit) { if (asn1_get_tag_der - (der + counter, der_len - counter, &class, &len2, + (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) return ASN1_DER_ERROR; - if (counter + len2 > der_len) - return ASN1_DER_ERROR; + + DECR_LEN(der_len, len2); if ((class != class_implicit) || (tag != tag_implicit)) { @@ -485,18 +511,16 @@ unsigned type = type_field (node->type); if (type == ASN1_ETYPE_TAG) { - counter = 0; - *ret_len = counter; + *ret_len = 0; return ASN1_SUCCESS; } if (asn1_get_tag_der - (der + counter, der_len - counter, &class, &len2, + (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) return ASN1_DER_ERROR; - if (counter + len2 > der_len) - return ASN1_DER_ERROR; + DECR_LEN(der_len, len2); switch (type) { @@ -546,6 +570,9 @@ counter += len2; *ret_len = counter; return ASN1_SUCCESS; + +cleanup: + return result; } static int @@ -612,97 +639,108 @@ int der_len) { int len2, len3; - int counter2, counter_end; + int counter, counter_end; + int result; len2 = asn1_get_length_der (der, der_len, &len3); if (len2 < -1) return ASN1_DER_ERROR; - counter2 = len3 + 1; + counter = len3 + 1; if (len2 == -1) counter_end = der_len - 2; else counter_end = der_len; - while (counter2 < counter_end) + while (counter < counter_end) { - len2 = asn1_get_length_der (der + counter2, der_len - counter2, &len3); + len2 = asn1_get_length_der (der + counter, der_len, &len3); if (len2 < -1) return ASN1_DER_ERROR; - if (len2 > 0) + if (len2 >= 0) { - _asn1_append_value (node, der + counter2 + len3, len2); + DECR_LEN(der_len, len2+len3); + _asn1_append_value (node, der + counter + len3, len2); } else { /* indefinite */ - - len2 = - _asn1_extract_der_octet (node, der + counter2 + len3, - der_len - counter2 - len3); - if (len2 < 0) - return len2; + DECR_LEN(der_len, len3); + result = + _asn1_extract_der_octet (node, der + counter + len3, + der_len); + if (result != ASN1_SUCCESS) + return result; + len2 = 0; } - counter2 += len2 + len3 + 1; + DECR_LEN(der_len, 1); + counter += len2 + len3 + 1; } return ASN1_SUCCESS; + +cleanup: + return result; } static int -_asn1_get_octet_string (const unsigned char *der, asn1_node node, int *len) +_asn1_get_octet_string (asn1_node node, const unsigned char *der, int der_len, int *len) { int len2, len3, counter, tot_len, indefinite; + int result; counter = 0; if (*(der - 1) & ASN1_CLASS_STRUCTURED) { tot_len = 0; - indefinite = asn1_get_length_der (der, *len, &len3); + indefinite = asn1_get_length_der (der, der_len, &len3); if (indefinite < -1) return ASN1_DER_ERROR; counter += len3; + DECR_LEN(der_len, len3); + if (indefinite >= 0) indefinite += len3; while (1) { - if (counter > (*len)) - return ASN1_DER_ERROR; - if (indefinite == -1) { - if ((der[counter] == 0) && (der[counter + 1] == 0)) + 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) return ASN1_DER_ERROR; counter++; - len2 = asn1_get_length_der (der + counter, *len - counter, &len3); + len2 = asn1_get_length_der (der + counter, der_len, &len3); if (len2 <= 0) return ASN1_DER_ERROR; + DECR_LEN(der_len, len3 + len2); counter += len3 + len2; + tot_len += len2; } /* copy */ if (node) { - unsigned char temp[DER_LEN]; + unsigned char temp[ASN1_MAX_LENGTH_SIZE]; int ret; len2 = sizeof (temp); @@ -710,7 +748,7 @@ asn1_length_der (tot_len, temp, &len2); _asn1_set_value (node, temp, len2); - ret = _asn1_extract_der_octet (node, der, *len); + ret = _asn1_extract_der_octet (node, der, der_len); if (ret != ASN1_SUCCESS) return ret; @@ -718,10 +756,11 @@ } else { /* NOT STRUCTURED */ - len2 = asn1_get_length_der (der, *len, &len3); + len2 = asn1_get_length_der (der, der_len, &len3); if (len2 < 0) return ASN1_DER_ERROR; + DECR_LEN(der_len, len3+len2); counter = len3 + len2; if (node) _asn1_set_value (node, der, counter); @@ -730,12 +769,16 @@ *len = counter; return ASN1_SUCCESS; +cleanup: + return result; } static int -_asn1_get_indefinite_length_string (const unsigned char *der, int *len) +_asn1_get_indefinite_length_string (const unsigned char *der, + int der_len, int *len) { int len2, len3, counter, indefinite; + int result; unsigned long tag; unsigned char class; @@ -743,12 +786,11 @@ while (1) { - if ((*len) < counter) - return ASN1_DER_ERROR; - - if ((der[counter] == 0) && (der[counter + 1] == 0)) + if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0)) { counter += 2; + DECR_LEN(der_len, 2); + indefinite--; if (indefinite <= 0) break; @@ -757,36 +799,44 @@ } if (asn1_get_tag_der - (der + counter, *len - counter, &class, &len2, + (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS) return ASN1_DER_ERROR; - if (counter + len2 > *len) - return ASN1_DER_ERROR; + + DECR_LEN(der_len, len2); counter += len2; - len2 = asn1_get_length_der (der + counter, *len - counter, &len3); + + len2 = asn1_get_length_der (der + counter, der_len, &len3); if (len2 < -1) return ASN1_DER_ERROR; + if (len2 == -1) { indefinite++; counter += 1; + DECR_LEN(der_len, 1); } else { counter += len2 + len3; + DECR_LEN(der_len, len2+len3); } } *len = counter; return ASN1_SUCCESS; +cleanup: + return result; } + + /** * asn1_der_decoding: * @element: pointer to an ASN1 structure. * @ider: vector that contains the DER encoding. - * @len: number of bytes of *@ider: @ider[0]..@ider[len-1]. + * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. * @errorDescription: null-terminated string contains details when an * error occurred. * @@ -802,7 +852,7 @@ * name (*@ELEMENT deleted). **/ int -asn1_der_decoding (asn1_node * element, const void *ider, int len, +asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, char *errorDescription) { asn1_node node, p, p2, p3; @@ -824,6 +874,7 @@ if (node->type & CONST_OPTION) { result = ASN1_GENERIC_ERROR; + warn(); goto cleanup; } @@ -841,11 +892,12 @@ len2 = _asn1_strtol (p2->value, NULL, 10); if (len2 == -1) { - if (!der[counter] && !der[counter + 1]) + if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) { p = p2; move = UP; counter += 2; + DECR_LEN(ider_len, 2); continue; } } @@ -858,6 +910,7 @@ else if (counter > len2) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } p2 = p2->down; @@ -868,7 +921,7 @@ if (type_field (p2->type) != ASN1_ETYPE_CHOICE) ris = _asn1_extract_tag_der (p2, der + counter, - len - counter, &len2); + ider_len, &len2); else { p3 = p2->down; @@ -876,7 +929,7 @@ { ris = _asn1_extract_tag_der (p3, der + counter, - len - counter, &len2); + ider_len, &len2); if (ris == ASN1_SUCCESS) break; p3 = p3->right; @@ -894,6 +947,7 @@ if (p2 == NULL) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } } @@ -924,12 +978,9 @@ { while (p->down) { - if (counter < len) - ris = + ris = _asn1_extract_tag_der (p->down, der + counter, - len - counter, &len2); - else - ris = ASN1_DER_ERROR; + ider_len, &len2); if (ris == ASN1_SUCCESS) { while (p->down->right) @@ -942,6 +993,7 @@ else if (ris == ASN1_ERROR_TYPE_ANY) { result = ASN1_ERROR_TYPE_ANY; + warn(); goto cleanup; } else @@ -956,6 +1008,7 @@ if (!(p->type & CONST_OPTION)) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } } @@ -973,7 +1026,7 @@ if (ris == ASN1_SUCCESS) ris = - _asn1_extract_tag_der (p, der + counter, len - counter, &len2); + _asn1_extract_tag_der (p, der + counter, ider_len, &len2); if (ris != ASN1_SUCCESS) { if (p->type & CONST_OPTION) @@ -992,11 +1045,15 @@ _asn1_error_description_tag_error (p, errorDescription); result = ASN1_TAG_ERROR; + warn(); goto cleanup; } } else - counter += len2; + { + DECR_LEN(ider_len, len2); + counter += len2; + } } if (ris == ASN1_SUCCESS) @@ -1004,18 +1061,23 @@ switch (type_field (p->type)) { case ASN1_ETYPE_NULL: + DECR_LEN(ider_len, 1); if (der[counter]) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } counter++; move = RIGHT; break; case ASN1_ETYPE_BOOLEAN: + DECR_LEN(ider_len, 2); + if (der[counter++] != 1) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } if (der[counter++] == 0) @@ -1027,50 +1089,68 @@ case ASN1_ETYPE_INTEGER: case ASN1_ETYPE_ENUMERATED: len2 = - asn1_get_length_der (der + counter, len - counter, &len3); + 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; move = RIGHT; break; case ASN1_ETYPE_OBJECT_ID: result = - _asn1_get_objectid_der (der + counter, len - counter, &len2, + _asn1_get_objectid_der (der + counter, ider_len, &len2, temp, sizeof (temp)); if (result != ASN1_SUCCESS) - goto cleanup; + { + warn(); + goto cleanup; + } + + DECR_LEN(ider_len, len2); tlen = strlen (temp); if (tlen > 0) _asn1_set_value (p, temp, tlen + 1); + counter += len2; move = RIGHT; break; case ASN1_ETYPE_GENERALIZED_TIME: case ASN1_ETYPE_UTC_TIME: result = - _asn1_get_time_der (der + counter, len - counter, &len2, temp, + _asn1_get_time_der (der + counter, ider_len, &len2, temp, sizeof (temp) - 1); if (result != ASN1_SUCCESS) - goto cleanup; + { + warn(); + goto cleanup; + } + + DECR_LEN(ider_len, len2); tlen = strlen (temp); if (tlen > 0) _asn1_set_value (p, temp, tlen); + counter += len2; move = RIGHT; break; case ASN1_ETYPE_OCTET_STRING: - len3 = len - counter; - result = _asn1_get_octet_string (der + counter, p, &len3); + result = _asn1_get_octet_string (p, der + counter, ider_len, &len3); if (result != ASN1_SUCCESS) - goto cleanup; + { + warn(); + goto cleanup; + } + DECR_LEN(ider_len, len3); counter += len3; move = RIGHT; break; @@ -1085,13 +1165,16 @@ case ASN1_ETYPE_VISIBLE_STRING: case ASN1_ETYPE_BIT_STRING: len2 = - asn1_get_length_der (der + counter, len - counter, &len3); + 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; move = RIGHT; @@ -1104,18 +1187,12 @@ _asn1_set_value (p, NULL, 0); if (len2 == -1) { /* indefinite length method */ - if (len - counter + 1 > 0) - { - if ((der[counter]) || der[counter + 1]) - { - result = ASN1_DER_ERROR; - goto cleanup; - } - } - else - { - result = ASN1_DER_ERROR; - goto cleanup; + DECR_LEN(ider_len, 2); + if ((der[counter]) || der[counter + 1]) + { + result = ASN1_DER_ERROR; + warn(); + goto cleanup; } counter += 2; } @@ -1124,6 +1201,7 @@ if (len2 != counter) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } } @@ -1132,13 +1210,17 @@ else { /* move==DOWN || move==RIGHT */ len3 = - asn1_get_length_der (der + counter, len - counter, &len2); + asn1_get_length_der (der + counter, ider_len, &len2); if (len3 < -1) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } + + DECR_LEN(ider_len, len2); counter += len2; + if (len3 > 0) { _asn1_ltostr (counter + len3, temp); @@ -1177,13 +1259,7 @@ len2 = _asn1_strtol (p->value, NULL, 10); if (len2 == -1) { /* indefinite length method */ - if ((counter + 2) > len) - { - result = ASN1_DER_ERROR; - goto cleanup; - } - - if ((der[counter]) || der[counter + 1]) + if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) { _asn1_append_sequence_set (p); p = p->down; @@ -1192,7 +1268,9 @@ move = RIGHT; continue; } + _asn1_set_value (p, NULL, 0); + DECR_LEN(ider_len, 2); counter += 2; } else @@ -1206,10 +1284,12 @@ move = RIGHT; continue; } + _asn1_set_value (p, NULL, 0); if (len2 != counter) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } } @@ -1217,12 +1297,15 @@ else { /* move==DOWN || move==RIGHT */ len3 = - asn1_get_length_der (der + counter, len - counter, &len2); + asn1_get_length_der (der + counter, ider_len, &len2); if (len3 < -1) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } + + DECR_LEN(ider_len, len2); counter += len2; if (len3) { @@ -1251,46 +1334,59 @@ break; case ASN1_ETYPE_ANY: if (asn1_get_tag_der - (der + counter, len - counter, &class, &len2, + (der + counter, ider_len, &class, &len2, &tag) != ASN1_SUCCESS) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } - if (counter + len2 > len) - { - result = ASN1_DER_ERROR; - goto cleanup; - } + DECR_LEN(ider_len, len2); + len4 = asn1_get_length_der (der + counter + len2, - len - counter - len2, &len3); + ider_len, &len3); if (len4 < -1) { result = ASN1_DER_ERROR; + warn(); goto cleanup; } - if (len4 != -1) + if (len4 != -1) /* definite */ { len2 += len4; + + DECR_LEN(ider_len, len4+len3); _asn1_set_value_lv (p, der + counter, len2 + len3); counter += len2 + len3; } - else + else /* == -1 */ { /* indefinite length */ + ider_len += len2; /* undo DECR_LEN */ + + if (counter == 0) + { + result = ASN1_DER_ERROR; + warn(); + goto cleanup; + } + /* Check indefinite lenth method in an EXPLICIT TAG */ if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80)) indefinite = 1; else indefinite = 0; - len2 = len - counter; result = - _asn1_get_indefinite_length_string (der + counter, &len2); + _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); if (result != ASN1_SUCCESS) - goto cleanup; + { + warn(); + goto cleanup; + } + DECR_LEN(ider_len, len2); _asn1_set_value_lv (p, der + counter, len2); counter += len2; @@ -1298,6 +1394,7 @@ an indefinite length method. */ if (indefinite) { + DECR_LEN(ider_len, 2); if (!der[counter] && !der[counter + 1]) { counter += 2; @@ -1305,6 +1402,7 @@ else { result = ASN1_DER_ERROR; + warn(); goto cleanup; } } @@ -1340,8 +1438,9 @@ _asn1_delete_not_used (*element); - if (counter != len) + if (ider_len != 0) { + warn(); result = ASN1_DER_ERROR; goto cleanup; } @@ -1374,6 +1473,9 @@ * decoding procedure, the *@STRUCTURE is deleted and set equal to * %NULL. * + * This function is deprecated and may just be an alias to asn1_der_decoding + * in future versions. Use asn1_der_decoding() instead. + * * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND * if ELEMENT is %NULL or @elementName == NULL, and * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't @@ -1737,15 +1839,14 @@ move = RIGHT; break; case ASN1_ETYPE_OCTET_STRING: - len3 = len - counter; if (state == FOUND) { - result = _asn1_get_octet_string (der + counter, p, &len3); + result = _asn1_get_octet_string (p, der + counter, len-counter, &len3); if (p == nodeFound) state = EXIT; } else - result = _asn1_get_octet_string (der + counter, NULL, &len3); + result = _asn1_get_octet_string (NULL, der + counter, len-counter, &len3); if (result != ASN1_SUCCESS) goto cleanup; @@ -1987,9 +2088,8 @@ else indefinite = 0; - len2 = len - counter; result = - _asn1_get_indefinite_length_string (der + counter, &len2); + _asn1_get_indefinite_length_string (der + counter, len-counter, &len2); if (result != ASN1_SUCCESS) goto cleanup; @@ -2160,7 +2260,7 @@ * asn1_der_decoding_startEnd: * @element: pointer to an ASN1 element * @ider: vector that contains the DER encoding. - * @len: number of bytes of *@ider: @ider[0]..@ider[len-1] + * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1] * @name_element: an element of NAME structure. * @start: the position of the first byte of NAME_ELEMENT decoding * (@ider[*start]) @@ -2182,14 +2282,14 @@ * doesn't match the structure ELEMENT. **/ int -asn1_der_decoding_startEnd (asn1_node element, const void *ider, int len, +asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, const char *name_element, int *start, int *end) { asn1_node node, node_to_find, p, p2, p3; int counter, len2, len3, len4, move, ris; unsigned char class; unsigned long tag; - int indefinite; + int indefinite, result = ASN1_DER_ERROR; const unsigned char *der = ider; node = element; @@ -2205,7 +2305,7 @@ if (node_to_find == node) { *start = 0; - *end = len - 1; + *end = ider_len - 1; return ASN1_SUCCESS; } @@ -2228,16 +2328,20 @@ { p2 = _asn1_find_up (p); if (p2 == NULL) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } len2 = _asn1_strtol (p2->value, NULL, 10); if (len2 == -1) { - if (!der[counter] && !der[counter + 1]) + if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) { p = p2; move = UP; counter += 2; + DECR_LEN(ider_len, 2); continue; } } @@ -2248,7 +2352,10 @@ continue; } else if (counter > len2) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } p2 = p2->down; @@ -2259,7 +2366,7 @@ if (type_field (p2->type) != ASN1_ETYPE_CHOICE) ris = _asn1_extract_tag_der (p2, der + counter, - len - counter, &len2); + ider_len, &len2); else { p3 = p2->down; @@ -2268,7 +2375,7 @@ ris = _asn1_extract_tag_der (p3, der + counter, - len - counter, &len2); + ider_len, &len2); } if (ris == ASN1_SUCCESS) { @@ -2280,7 +2387,10 @@ p2 = p2->right; } if (p2 == NULL) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } } if (p == node_to_find) @@ -2290,10 +2400,13 @@ { p = p->down; if (p == NULL) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } ris = - _asn1_extract_tag_der (p, der + counter, len - counter, + _asn1_extract_tag_der (p, der + counter, ider_len, &len2); if (p == node_to_find) *start = counter; @@ -2301,7 +2414,7 @@ if (ris == ASN1_SUCCESS) ris = - _asn1_extract_tag_der (p, der + counter, len - counter, &len2); + _asn1_extract_tag_der (p, der + counter, ider_len, &len2); if (ris != ASN1_SUCCESS) { if (p->type & CONST_OPTION) @@ -2315,11 +2428,15 @@ } else { + warn(); return ASN1_TAG_ERROR; } } else - counter += len2; + { + DECR_LEN(ider_len, len2); + counter += len2; + } } if (ris == ASN1_SUCCESS) @@ -2327,22 +2444,36 @@ switch (type_field (p->type)) { case ASN1_ETYPE_NULL: + DECR_LEN(ider_len, 1); + if (der[counter]) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } counter++; move = RIGHT; break; case ASN1_ETYPE_BOOLEAN: - if (der[counter++] != 1) - return ASN1_DER_ERROR; - counter++; + DECR_LEN(ider_len, 2); + + if (der[counter] != 1) + { + warn(); + return ASN1_DER_ERROR; + } + + counter += 2; move = RIGHT; break; case ASN1_ETYPE_OCTET_STRING: - len3 = len - counter; - ris = _asn1_get_octet_string (der + counter, NULL, &len3); + ris = _asn1_get_octet_string (NULL, der + counter, ider_len, &len3); if (ris != ASN1_SUCCESS) - return ris; + { + warn(); + return ris; + } + DECR_LEN(ider_len, len3); counter += len3; move = RIGHT; break; @@ -2362,9 +2493,14 @@ case ASN1_ETYPE_VISIBLE_STRING: case ASN1_ETYPE_BIT_STRING: len2 = - asn1_get_length_der (der + counter, len - counter, &len3); + asn1_get_length_der (der + counter, ider_len, &len3); if (len2 < 0) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } + + DECR_LEN(ider_len, len3 + len2); counter += len3 + len2; move = RIGHT; break; @@ -2373,10 +2509,16 @@ if (move != UP) { len3 = - asn1_get_length_der (der + counter, len - counter, &len2); + asn1_get_length_der (der + counter, ider_len, &len2); if (len3 < -1) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } + + DECR_LEN(ider_len, len2); counter += len2; + if (len3 == 0) move = RIGHT; else @@ -2384,8 +2526,11 @@ } else { - if (!der[counter] && !der[counter + 1]) /* indefinite length method */ - counter += 2; + if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */ + { + counter += 2; + DECR_LEN(ider_len, 2); + } move = RIGHT; } break; @@ -2394,13 +2539,26 @@ if (move != UP) { len3 = - asn1_get_length_der (der + counter, len - counter, &len2); + asn1_get_length_der (der + counter, ider_len, &len2); if (len3 < -1) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } + + DECR_LEN(ider_len, len2); counter += len2; - if ((len3 == -1) && !der[counter] && !der[counter + 1]) - counter += 2; - else if (len3) + + if (len3 == -1) + { + if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) + { + DECR_LEN(ider_len, 2); + counter += 2; + } + } + + if (len3) { p2 = p->down; while ((type_field (p2->type) == ASN1_ETYPE_TAG) || @@ -2411,52 +2569,79 @@ } else { - if (!der[counter] && !der[counter + 1]) /* indefinite length method */ - counter += 2; + if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */ + { + DECR_LEN(ider_len, 2); + counter += 2; + } } move = RIGHT; break; case ASN1_ETYPE_ANY: if (asn1_get_tag_der - (der + counter, len - counter, &class, &len2, + (der + counter, ider_len, &class, &len2, &tag) != ASN1_SUCCESS) - return ASN1_DER_ERROR; - if (counter + len2 > len) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } + + DECR_LEN(ider_len, len2); len4 = asn1_get_length_der (der + counter + len2, - len - counter - len2, &len3); + ider_len, &len3); if (len4 < -1) - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } if (len4 != -1) { - counter += len2 + len4 + len3; + DECR_LEN(ider_len, len3 + len4); + counter += len2 + len3 + len4; } else { /* indefinite length */ /* Check indefinite lenth method in an EXPLICIT TAG */ + ider_len += len2; /* undo DECR_LEN */ + + if (counter == 0) + { + result = ASN1_DER_ERROR; + warn(); + goto cleanup; + } + if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80)) indefinite = 1; else indefinite = 0; - len2 = len - counter; ris = - _asn1_get_indefinite_length_string (der + counter, &len2); + _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); if (ris != ASN1_SUCCESS) - return ris; + { + warn(); + return ris; + } counter += len2; + DECR_LEN(ider_len, len2); /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with an indefinite length method. */ if (indefinite) { + DECR_LEN(ider_len, 2); + if (!der[counter] && !der[counter + 1]) counter += 2; else - return ASN1_DER_ERROR; + { + warn(); + return ASN1_DER_ERROR; + } } } move = RIGHT; @@ -2494,7 +2679,11 @@ p = _asn1_find_up (p); } + warn(); return ASN1_ELEMENT_NOT_FOUND; + +cleanup: + return result; } /**