summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2014-08-20 21:34:53 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2014-08-20 21:37:07 +0200
commit2e1b0636c38153623b40944d26df23cb8b05072b (patch)
treef8c13a3cf65e09c5d54eaecd9db0ec3ae4d81e4f
parent0b0de9bf1a1e7f87a19d2823a8fa7d83ec41532a (diff)
downloadlibtasn1-2e1b0636c38153623b40944d26df23cb8b05072b.tar.gz
Added decoding flag ASN1_DECODE_FLAG_STRICT_DER
-rw-r--r--lib/decoding.c65
-rw-r--r--lib/libtasn1.h4
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