Description: fix denial of service and possible code execution via
 invalid ASN.1 data
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=ff3b5c68cc32e30d19edbbc3a962b2266029f3cc
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=b32eae0501626fa8f28d3746246cef853b6a631e
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=0e80d79db71747644394fe3472dad28cd3e7b00b
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=154909136c12cfa5c60732b7210827dfb1ec6aee
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=eb83e268099b92e046f4ec224c8296f7bb61f159
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=25d7f2dbb74fa5033117e52638f082b94b3ef5fa
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=37a16434131c6ad8745b9accefec5cecb4cbb5b7
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=df4b741dfc41c1930fd73a5c7968479196961508
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=cc10a8c5443c751d920cfaca1f104089e43296be
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=609d5c1366fb424f6150c4eed358d246e61cf204
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=6fee6745b1bd1a82f16ae9b607855a3e3ab39fc6
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=af0e8cd0bacf47ecce049165d3bc1ed9e861df1c
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=92541f56adbdb56bbc97b07c2e073bbcd9f11b4a
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=f245088c5bd6c7e9bea18e5601ee24d431531558
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=51612fca32dda445056ca9a7533bae258acd3ecb
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=02d59b37540609c0be510642a8eb0f72799ca6c6
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=44a4680d83fe4ff732e4e1b826c987bc5d67bd1c
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=53958290ab731c8486531a3bdef54a933533579d
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=045ac8d01857265f422d0d74ca99944f70c0b9e3
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=f09f2b9e497d0597f3372014838df08f81f653b4
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=6cd01f6f8f5fe4a85d4df3febec4d9133e360b72
Origin: backport, http://git.savannah.gnu.org/cgit/libtasn1.git/commit/?id=1c3ccb3e040bf13e342ee60bc23b21b97b11923f

Index: libtasn1-3-2.10/lib/decoding.c
===================================================================
--- libtasn1-3-2.10.orig/lib/decoding.c	2014-07-18 15:24:35.370387688 -0400
+++ libtasn1-3-2.10/lib/decoding.c	2014-07-18 15:26:23.454391724 -0400
@@ -32,8 +32,25 @@
 #include "structure.h"
 #include "element.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 asn1_retCode
-_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_TYPE node, char *ErrorDescription)
@@ -138,7 +155,7 @@
       /* Long form */
       punt = 1;
       ris = 0;
-      while (punt <= der_len && der[punt] & 128)
+      while (punt < der_len && der[punt] & 128)
 	{
 	  int last = ris;
 	  ris = ris * 128 + (der[punt++] & 0x7F);
@@ -186,8 +203,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;
     }
@@ -213,12 +229,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)
@@ -226,7 +241,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;
@@ -245,9 +263,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;
@@ -272,7 +292,7 @@
     return ASN1_GENERIC_ERROR;
   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;
@@ -334,19 +354,26 @@
 		  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;
 
   *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;
@@ -361,6 +388,7 @@
 {
   ASN1_TYPE p;
   int counter, len2, len3, is_tag_implicit;
+  int result;
   unsigned long tag, tag_implicit = 0;
   unsigned char class, class2, class_implicit = 0;
 
@@ -388,23 +416,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)
 		    {
@@ -441,11 +467,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))
 	{
@@ -463,18 +489,16 @@
     {
       if (type_field (node->type) == TYPE_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_field (node->type))
 	{
@@ -551,6 +575,9 @@
   counter += len2;
   *ret_len = counter;
   return ASN1_SUCCESS;
+
+cleanup:
+  return result;
 }
 
 static int
@@ -617,90 +644,102 @@
 			 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 asn1_retCode
-_asn1_get_octet_string (const unsigned char *der, ASN1_TYPE node, int *len)
+_asn1_get_octet_string (ASN1_TYPE 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;
 	}
 
@@ -715,9 +754,7 @@
 	  asn1_length_der (tot_len, temp, &len2);
 	  _asn1_set_value (node, temp, len2);
 
-	  tot_len += len2;
-
-	  ret = _asn1_extract_der_octet (node, der, *len);
+	  ret = _asn1_extract_der_octet (node, der, der_len);
 	  if (ret != ASN1_SUCCESS)
 	    return ret;
 
@@ -725,25 +762,29 @@
     }
   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;
-      if (len3 + len2 > *len)
-	return ASN1_DER_ERROR;
-      if (node)
-	_asn1_set_value (node, der, len3 + len2);
+
+      DECR_LEN(der_len, len3+len2);
       counter = len3 + len2;
+      if (node)
+	_asn1_set_value (node, der, counter);
     }
 
   *len = counter;
   return ASN1_SUCCESS;
 
+cleanup:
+  return result;
 }
 
 static asn1_retCode
-_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;
 
@@ -751,12 +792,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;
@@ -765,36 +805,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.
  *
@@ -810,7 +858,7 @@
  *   name (*@ELEMENT deleted).
  **/
 asn1_retCode
-asn1_der_decoding (ASN1_TYPE * element, const void *ider, int len,
+asn1_der_decoding (ASN1_TYPE * element, const void *ider, int ider_len,
 		   char *errorDescription)
 {
   ASN1_TYPE node, p, p2, p3;
@@ -828,6 +876,7 @@
 
   if (node->type & CONST_OPTION)
     {
+      warn();
       asn1_delete_structure (element);
       return ASN1_GENERIC_ERROR;
     }
@@ -846,11 +895,12 @@
 	      len2 = 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;
 		    }
 		}
@@ -862,6 +912,7 @@
 		}
 	      else if (counter > len2)
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return ASN1_DER_ERROR;
 		}
@@ -873,7 +924,7 @@
 		      if (type_field (p2->type) != TYPE_CHOICE)
 			ris =
 			  _asn1_extract_tag_der (p2, der + counter,
-						 len - counter, &len2);
+						 ider_len, &len2);
 		      else
 			{
 			  p3 = p2->down;
@@ -881,7 +932,7 @@
 			    {
 			      ris =
 				_asn1_extract_tag_der (p3, der + counter,
-						       len - counter, &len2);
+						       ider_len, &len2);
 			      if (ris == ASN1_SUCCESS)
 				break;
 			      p3 = p3->right;
@@ -898,6 +949,7 @@
 		}
 	      if (p2 == NULL)
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return ASN1_DER_ERROR;
 		}
@@ -929,12 +981,10 @@
 	    {
 	      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)
@@ -946,6 +996,7 @@
 		    }
 		  else if (ris == ASN1_ERROR_TYPE_ANY)
 		    {
+                      warn();
 		      asn1_delete_structure (element);
 		      return ASN1_ERROR_TYPE_ANY;
 		    }
@@ -960,6 +1011,7 @@
 		{
 		  if (!(p->type & CONST_OPTION))
 		    {
+                      warn();
 		      asn1_delete_structure (element);
 		      return ASN1_DER_ERROR;
 		    }
@@ -972,13 +1024,15 @@
 	    {
 	      p2 = _asn1_find_up (p);
 	      len2 = _asn1_strtol (p2->value, NULL, 10);
+
 	      if ((len2 != -1) && (counter > len2))
 		ris = ASN1_TAG_ERROR;
 	    }
 
 	  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)
@@ -996,12 +1050,16 @@
 		  if (errorDescription != NULL)
 		    _asn1_error_description_tag_error (p, errorDescription);
 
+                  warn();
 		  asn1_delete_structure (element);
 		  return ASN1_TAG_ERROR;
 		}
 	    }
 	  else
-	    counter += len2;
+	    {
+	      DECR_LEN(ider_len, len2);
+	      counter += len2;
+	    }
 	}
 
       if (ris == ASN1_SUCCESS)
@@ -1009,8 +1067,10 @@
 	  switch (type_field (p->type))
 	    {
 	    case TYPE_NULL:
+	      DECR_LEN(ider_len, 1);
 	      if (der[counter])
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return ASN1_DER_ERROR;
 		}
@@ -1018,8 +1078,11 @@
 	      move = RIGHT;
 	      break;
 	    case TYPE_BOOLEAN:
+	      DECR_LEN(ider_len, 2);
+
 	      if (der[counter++] != 1)
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return ASN1_DER_ERROR;
 		}
@@ -1032,72 +1095,96 @@
 	    case TYPE_INTEGER:
 	    case TYPE_ENUMERATED:
 	      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;
-	      if (len2 + len3 > len - counter)
-		return ASN1_DER_ERROR;
+		{
+                  warn();
+		  return ASN1_DER_ERROR;
+		}
+	      DECR_LEN(ider_len, len3+len2);
+
 	      _asn1_set_value (p, der + counter, len3 + len2);
 	      counter += len3 + len2;
 	      move = RIGHT;
 	      break;
 	    case TYPE_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)
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return result;
 		}
 
+	      DECR_LEN(ider_len, len2);
+
 	      tlen = strlen (temp);
 	      if (tlen > 0)
 		_asn1_set_value (p, temp, tlen + 1);
+
 	      counter += len2;
 	      move = RIGHT;
 	      break;
 	    case TYPE_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)
 		{
+                  warn();
 		  asn1_delete_structure (element);
 		  return result;
 		}
+
+	      DECR_LEN(ider_len, len2);
+
 	      tlen = strlen (temp);
 	      if (tlen > 0)
 		_asn1_set_value (p, temp, tlen + 1);
+
 	      counter += len2;
 	      move = RIGHT;
 	      break;
 	    case TYPE_OCTET_STRING:
-	      len3 = len - counter;
-	      ris = _asn1_get_octet_string (der + counter, p, &len3);
+	      ris = _asn1_get_octet_string (p, der + counter, ider_len, &len3);
 	      if (ris != ASN1_SUCCESS)
-		return ris;
+	        {
+                  warn();
+		  return ris;
+		}
+
+	      DECR_LEN(ider_len, len3);
 	      counter += len3;
 	      move = RIGHT;
 	      break;
 	    case TYPE_GENERALSTRING:
 	      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;
-	      if (len3 + len2 > len - counter)
-		return ASN1_DER_ERROR;
+	        {
+                  warn();
+		  return ASN1_DER_ERROR;
+		}
+
 	      _asn1_set_value (p, der + counter, len3 + len2);
+
+	      DECR_LEN(ider_len, len3 + len2);
 	      counter += len3 + len2;
 	      move = RIGHT;
 	      break;
 	    case TYPE_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;
-	      if (len3 + len2 > len - counter)
-		return ASN1_DER_ERROR;
+		{
+		  warn();
+		  return ASN1_DER_ERROR;
+		}
+
+	      DECR_LEN(ider_len, len3+len2);
+
 	      _asn1_set_value (p, der + counter, len3 + len2);
 	      counter += len3 + len2;
 	      move = RIGHT;
@@ -1110,22 +1197,20 @@
 		  _asn1_set_value (p, NULL, 0);
 		  if (len2 == -1)
 		    {		/* indefinite length method */
-		      if (len - counter + 1 > 0)
-			{
-			  if ((der[counter]) || der[counter + 1])
-			    {
-			      asn1_delete_structure (element);
-			      return ASN1_DER_ERROR;
-			    }
+		      DECR_LEN(ider_len, 2);
+		      if ((der[counter]) || der[counter + 1])
+		        {
+                          warn();
+			  asn1_delete_structure (element);
+			  return ASN1_DER_ERROR;
 			}
-		      else
-			return ASN1_DER_ERROR;
 		      counter += 2;
 		    }
 		  else
 		    {		/* definite length method */
 		      if (len2 != counter)
 			{
+			  warn();
 			  asn1_delete_structure (element);
 			  return ASN1_DER_ERROR;
 			}
@@ -1135,9 +1220,14 @@
 	      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)
-		    return ASN1_DER_ERROR;
+		    {
+		      warn();
+		      return ASN1_DER_ERROR;
+		    }
+
+	          DECR_LEN(ider_len, len2);
 		  counter += len2;
 		  if (len3 > 0)
 		    {
@@ -1177,9 +1267,7 @@
 		  len2 = strtol (p->value, NULL, 10);
 		  if (len2 == -1)
 		    {		/* indefinite length method */
-		      if ((counter + 2) > len)
-			return ASN1_DER_ERROR;
-		      if ((der[counter]) || der[counter + 1])
+		      if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1]))
 			{
 			  _asn1_append_sequence_set (p);
 			  p = p->down;
@@ -1188,7 +1276,9 @@
 			  move = RIGHT;
 			  continue;
 			}
+
 		      _asn1_set_value (p, NULL, 0);
+		      DECR_LEN(ider_len, 2);
 		      counter += 2;
 		    }
 		  else
@@ -1202,9 +1292,11 @@
 			  move = RIGHT;
 			  continue;
 			}
+
 		      _asn1_set_value (p, NULL, 0);
 		      if (len2 != counter)
 			{
+			  warn();
 			  asn1_delete_structure (element);
 			  return ASN1_DER_ERROR;
 			}
@@ -1213,9 +1305,14 @@
 	      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)
-		    return ASN1_DER_ERROR;
+		    {
+		      warn();
+		      return ASN1_DER_ERROR;
+		    }
+
+		  DECR_LEN(ider_len, len2);
 		  counter += len2;
 		  if (len3)
 		    {
@@ -1244,41 +1341,57 @@
 	      break;
 	    case TYPE_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;
-	      if (len4 > len - counter + len2 + len3)
-		return ASN1_DER_ERROR;
-	      if (len4 != -1)
+		{
+		  warn();
+		  return ASN1_DER_ERROR;
+		}
+	      if (len4 != -1) /* definite */
 		{
 		  len2 += len4;
+
+	          DECR_LEN(ider_len, len4+len3);
 		  _asn1_set_value_octet (p, der + counter, len2 + len3);
 		  counter += len2 + len3;
 		}
-	      else
+	      else /* == -1 */
 		{		/* indefinite length */
+		  ider_len += len2; /* undo DECR_LEN */
+
+		  if (counter == 0)
+		    {
+                      warn();
+		      return ASN1_DER_ERROR;
+		    }
+
 		  /* 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;
 		  ris =
-		    _asn1_get_indefinite_length_string (der + counter, &len2);
+		    _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
 		  if (ris != ASN1_SUCCESS)
 		    {
+                      warn();
 		      asn1_delete_structure (element);
 		      return ris;
 		    }
 
+	          DECR_LEN(ider_len, len2);
 		  _asn1_set_value_octet (p, der + counter, len2);
 		  counter += len2;
 
@@ -1286,12 +1399,14 @@
 		     an indefinite length method. */
 		  if (indefinite)
 		    {
+	              DECR_LEN(ider_len, 2);
 		      if (!der[counter] && !der[counter + 1])
 			{
 			  counter += 2;
 			}
 		      else
 			{
+                          warn();
 			  asn1_delete_structure (element);
 			  return ASN1_DER_ERROR;
 			}
@@ -1328,13 +1443,17 @@
 
   _asn1_delete_not_used (*element);
 
-  if (counter != len)
+  if (ider_len != 0)
     {
+      warn();
       asn1_delete_structure (element);
       return ASN1_DER_ERROR;
     }
 
   return ASN1_SUCCESS;
+
+cleanup:
+  return result;
 }
 
 #define FOUND        1
@@ -1358,6 +1477,9 @@
  * decoding procedure, the *@STRUCTURE is deleted and set equal to
  * %ASN1_TYPE_EMPTY.
  *
+ * 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 %ASN1_TYPE_EMPTY or @elementName == NULL, and
  *   %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
@@ -1712,15 +1834,14 @@
 	      move = RIGHT;
 	      break;
 	    case TYPE_OCTET_STRING:
-	      len3 = len - counter;
 	      if (state == FOUND)
 		{
-		  ris = _asn1_get_octet_string (der + counter, p, &len3);
+		  ris = _asn1_get_octet_string (p, der + counter, len-counter, &len3);
 		  if (p == nodeFound)
 		    state = EXIT;
 		}
 	      else
-		ris = _asn1_get_octet_string (der + counter, NULL, &len3);
+		ris = _asn1_get_octet_string (NULL, der + counter, len-counter, &len3);
 
 	      if (ris != ASN1_SUCCESS)
 		return ris;
@@ -1939,9 +2060,8 @@
 		  else
 		    indefinite = 0;
 
-		  len2 = len - counter;
 		  ris =
-		    _asn1_get_indefinite_length_string (der + counter, &len2);
+		    _asn1_get_indefinite_length_string (der + counter, len-counter, &len2);
 		  if (ris != ASN1_SUCCESS)
 		    {
 		      asn1_delete_structure (structure);
@@ -2111,7 +2231,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])
@@ -2133,14 +2253,14 @@
  *   doesn't match the structure ELEMENT.
  **/
 asn1_retCode
-asn1_der_decoding_startEnd (ASN1_TYPE element, const void *ider, int len,
+asn1_der_decoding_startEnd (ASN1_TYPE element, const void *ider, int ider_len,
 			    const char *name_element, int *start, int *end)
 {
   ASN1_TYPE 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;
@@ -2156,7 +2276,7 @@
   if (node_to_find == node)
     {
       *start = 0;
-      *end = len - 1;
+      *end = ider_len - 1;
       return ASN1_SUCCESS;
     }
 
@@ -2178,11 +2298,12 @@
 	      len2 = 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;
 		    }
 		}
@@ -2193,7 +2314,10 @@
 		  continue;
 		}
 	      else if (counter > len2)
-		return ASN1_DER_ERROR;
+		{
+		  warn();
+		  return ASN1_DER_ERROR;
+		}
 	      p2 = p2->down;
 	      while (p2)
 		{
@@ -2202,13 +2326,13 @@
 		      if (type_field (p2->type) != TYPE_CHOICE)
 			ris =
 			  _asn1_extract_tag_der (p2, der + counter,
-						 len - counter, &len2);
+						 ider_len, &len2);
 		      else
 			{
 			  p3 = p2->down;
 			  ris =
 			    _asn1_extract_tag_der (p3, der + counter,
-						   len - counter, &len2);
+						   ider_len, &len2);
 			}
 		      if (ris == ASN1_SUCCESS)
 			{
@@ -2220,7 +2344,10 @@
 		  p2 = p2->right;
 		}
 	      if (p2 == NULL)
-		return ASN1_DER_ERROR;
+	        {
+		  warn();
+		  return ASN1_DER_ERROR;
+		}
 	    }
 
 	  if (p == node_to_find)
@@ -2230,7 +2357,7 @@
 	    {
 	      p = p->down;
 	      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;
@@ -2238,7 +2365,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)
@@ -2252,11 +2379,15 @@
 		}
 	      else
 		{
+		  warn();
 		  return ASN1_TAG_ERROR;
 		}
 	    }
 	  else
-	    counter += len2;
+	    {
+	      DECR_LEN(ider_len, len2);
+	      counter += len2;
+	    }
 	}
 
       if (ris == ASN1_SUCCESS)
@@ -2264,63 +2395,98 @@
 	  switch (type_field (p->type))
 	    {
 	    case TYPE_NULL:
+	      DECR_LEN(ider_len, 1);
+
 	      if (der[counter])
-		return ASN1_DER_ERROR;
+		{
+		  warn();
+		  return ASN1_DER_ERROR;
+		}
 	      counter++;
 	      move = RIGHT;
 	      break;
 	    case TYPE_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 TYPE_INTEGER:
 	    case TYPE_ENUMERATED:
 	      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;
 	    case TYPE_OBJECT_ID:
 	      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, len2 + len3);
 	      counter += len2 + len3;
 	      move = RIGHT;
 	      break;
 	    case TYPE_TIME:
 	      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, len2 + len3);
 	      counter += len2 + len3;
 	      move = RIGHT;
 	      break;
 	    case TYPE_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;
 	    case TYPE_GENERALSTRING:
 	      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;
 	    case TYPE_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;
@@ -2329,10 +2495,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
@@ -2340,8 +2512,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;
@@ -2350,13 +2525,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) == TYPE_TAG) ||
@@ -2367,52 +2555,78 @@
 		}
 	      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 TYPE_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)
+		    {
+                      warn();
+		      return ASN1_DER_ERROR;
+		    }
+
 		  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;
@@ -2450,7 +2664,11 @@
 	p = _asn1_find_up (p);
     }
 
+  warn();
   return ASN1_ELEMENT_NOT_FOUND;
+
+cleanup:
+  return result;
 }
 
 /**
