diff options
Diffstat (limited to 'lib/decoding.c')
-rw-r--r-- | lib/decoding.c | 92 |
1 files changed, 60 insertions, 32 deletions
diff --git a/lib/decoding.c b/lib/decoding.c index 1069e44..05dc236 100644 --- a/lib/decoding.c +++ b/lib/decoding.c @@ -43,12 +43,19 @@ #define HAVE_TWO(x) (x>=2?1:0) +/* Decoding flags (dflags) used in several decoding functions. + * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag + * DECODE_FLAG_INDEFINITE: The provided buffer is of indefinite encoding (useful + * when no tags are present). + * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings. + * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings. + * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings. + * This is the maximum levels of recursion possible to prevent stack + * exhaustion. + */ + #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) @@ -121,7 +128,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) { @@ -161,7 +168,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. * @@ -244,9 +251,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; } @@ -336,10 +343,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++) @@ -366,14 +373,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); @@ -391,7 +398,8 @@ _asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *r * @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. + * Converts a DER encoded object identifier to its textual form. This + * function expects the DER object identifier without the tag. * * Returns: %ASN1_SUCCESS on success, or an error. **/ @@ -402,7 +410,7 @@ asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, int len_len, len, k; int leading; char temp[LTOSTR_MAX_SIZE]; - unsigned long val, val1; + uint64_t val, val1; *ret_len = 0; if (str && str_size > 0) @@ -1147,8 +1155,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); @@ -1192,15 +1200,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); @@ -1311,7 +1319,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; @@ -1327,7 +1340,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; @@ -1368,12 +1386,27 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* indefinite length method */ p->tmp_ival = -1; } + p2 = p->down; + if (p2 == NULL) + { + result = ASN1_DER_ERROR; + warn(); + goto cleanup; + } + while ((type_field (p2->type) == ASN1_ETYPE_TAG) || (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; } } @@ -1432,8 +1465,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); @@ -1468,7 +1501,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) @@ -1539,11 +1572,6 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); } -#define FOUND 1 -#define SAME_BRANCH 2 -#define OTHER_BRANCH 3 -#define EXIT 4 - /** * asn1_der_decoding_element: * @structure: pointer to an ASN1 structure @@ -2263,8 +2291,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; |