Blob Blame History Raw
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 <limits.h>
 #include <intprops.h>
 
+#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;
 }
 
 /**