diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2014-08-20 21:34:53 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2014-08-20 21:37:07 +0200 |
commit | 2e1b0636c38153623b40944d26df23cb8b05072b (patch) | |
tree | f8c13a3cf65e09c5d54eaecd9db0ec3ae4d81e4f | |
parent | 0b0de9bf1a1e7f87a19d2823a8fa7d83ec41532a (diff) | |
download | libtasn1-2e1b0636c38153623b40944d26df23cb8b05072b.tar.gz |
Added decoding flag ASN1_DECODE_FLAG_STRICT_DER
-rw-r--r-- | lib/decoding.c | 65 | ||||
-rw-r--r-- | lib/libtasn1.h | 4 |
2 files changed, 47 insertions, 22 deletions
diff --git a/lib/decoding.c b/lib/decoding.c index 8b88581..fd6ef5b 100644 --- a/lib/decoding.c +++ b/lib/decoding.c @@ -39,6 +39,8 @@ # define warn() #endif +#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0)) + #define HAVE_TWO(x) (x>=2?1:0) #define DECR_LEN(l, s) do { \ @@ -406,7 +408,7 @@ asn1_get_bit_der (const unsigned char *der, int der_len, static int _asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, - int *ret_len) + int *ret_len, unsigned flags) { asn1_node p; int counter, len2, len3, is_tag_implicit; @@ -445,8 +447,13 @@ _asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, DECR_LEN(der_len, len2); counter += len2; - len3 = - asn1_get_length_ber (der + counter, der_len, + if (flags & ASN1_DECODE_FLAG_STRICT_DER) + len3 = + asn1_get_length_der (der + counter, der_len, + &len2); + else + len3 = + asn1_get_length_ber (der + counter, der_len, &len2); if (len3 < 0) return ASN1_DER_ERROR; @@ -581,7 +588,7 @@ cleanup: static int extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len, - int *ret_len) + int *ret_len, unsigned flags) { asn1_node p; int ris = ASN1_DER_ERROR; @@ -591,7 +598,7 @@ int ris = ASN1_DER_ERROR; p = node->down; while (p) { - ris = _asn1_extract_tag_der (p, der, der_len, ret_len); + ris = _asn1_extract_tag_der (p, der, der_len, ret_len, flags); if (ris == ASN1_SUCCESS) break; p = p->right; @@ -601,7 +608,7 @@ int ris = ASN1_DER_ERROR; return ris; } else - return _asn1_extract_tag_der (node, der, der_len, ret_len); + return _asn1_extract_tag_der (node, der, der_len, ret_len, flags); } static int @@ -665,7 +672,7 @@ _asn1_delete_not_used (asn1_node node) static int _asn1_extract_der_octet (asn1_node node, const unsigned char *der, - int der_len) + int der_len, unsigned flags) { int len2, len3; int counter, counter_end; @@ -686,8 +693,11 @@ _asn1_extract_der_octet (asn1_node node, const unsigned char *der, { len2 = asn1_get_length_der (der + counter, der_len, &len3); - if (len2 < -1) - return ASN1_DER_ERROR; + if (IS_ERR(len2, flags)) + { + warn(); + return ASN1_DER_ERROR; + } if (len2 >= 0) { @@ -699,7 +709,7 @@ _asn1_extract_der_octet (asn1_node node, const unsigned char *der, DECR_LEN(der_len, len3); result = _asn1_extract_der_octet (node, der + counter + len3, - der_len); + der_len, flags); if (result != ASN1_SUCCESS) return result; len2 = 0; @@ -716,7 +726,8 @@ cleanup: } static int -_asn1_get_octet_string (asn1_node node, const unsigned char *der, int der_len, int *len) +_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; @@ -726,9 +737,13 @@ _asn1_get_octet_string (asn1_node node, const unsigned char *der, int der_len, i if (*(der - 1) & ASN1_CLASS_STRUCTURED) { tot_len = 0; + indefinite = asn1_get_length_der (der, der_len, &len3); - if (indefinite < -1) - return ASN1_DER_ERROR; + if (IS_ERR(indefinite, flags)) + { + warn(); + return ASN1_DER_ERROR; + } counter += len3; DECR_LEN(der_len, len3); @@ -777,7 +792,7 @@ _asn1_get_octet_string (asn1_node node, const unsigned char *der, int der_len, i asn1_length_der (tot_len, temp, &len2); _asn1_set_value (node, temp, len2); - ret = _asn1_extract_der_octet (node, der, der_len); + ret = _asn1_extract_der_octet (node, der, der_len, flags); if (ret != ASN1_SUCCESS) return ret; @@ -889,6 +904,9 @@ static void delete_unneeded_choice_fields(asn1_node p) * padding after the decoded DER data. Upon a successful return the value of * *@max_ider_len will be set to the number of bytes decoded. * + * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will + * not decode any BER-encoded elements. + * * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or * %ASN1_DER_ERROR if the der encoding doesn't match the structure @@ -966,7 +984,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); + ider_len, &len2, flags); if (ris == ASN1_SUCCESS) { p2->type &= ~CONST_NOT_USED; @@ -1016,7 +1034,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); + ider_len, &len2, flags); if (ris == ASN1_SUCCESS) { @@ -1062,7 +1080,8 @@ 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); + extract_tag_der_recursive (p, der + counter, ider_len, + &tag_len, flags); if (ris != ASN1_SUCCESS) { @@ -1180,7 +1199,7 @@ 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); + result = _asn1_get_octet_string (p, der + counter, ider_len, &len3, flags); if (result != ASN1_SUCCESS) { warn(); @@ -1248,7 +1267,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* move==DOWN || move==RIGHT */ len3 = asn1_get_length_der (der + counter, ider_len, &len2); - if (len3 < -1) + if (IS_ERR(len3, flags)) { result = ASN1_DER_ERROR; warn(); @@ -1331,7 +1350,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, { /* move==DOWN || move==RIGHT */ len3 = asn1_get_length_der (der + counter, ider_len, &len2); - if (len3 < -1) + if (IS_ERR(len3, flags)) { result = ASN1_DER_ERROR; warn(); @@ -1363,7 +1382,9 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, break; case ASN1_ETYPE_ANY: /* Check indefinite lenth method in an EXPLICIT TAG */ - if ((p->type & CONST_TAG) && tag_len == 2 && (der[counter - 1] == 0x80)) + + if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) && + tag_len == 2 && (der[counter - 1] == 0x80)) indefinite = 1; else indefinite = 0; @@ -1382,7 +1403,7 @@ asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, len4 = asn1_get_length_der (der + counter + len2, ider_len, &len3); - if (len4 < -1) + if (IS_ERR(len4, flags)) { result = ASN1_DER_ERROR; warn(); diff --git a/lib/libtasn1.h b/lib/libtasn1.h index 8f7ff0b..d36c99a 100644 --- a/lib/libtasn1.h +++ b/lib/libtasn1.h @@ -185,7 +185,11 @@ extern "C" #define ASN1_DELETE_FLAG_ZEROIZE 1 /* Flags used by asn1_der_decoding2(). */ + +/* This flag would allow arbitrary data past the DER data */ #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) struct asn1_data_node_st |