Commit message: increased size of LTOSTR_MAX_SIZE to account for sign and null byte

This address an overflow found by Hanno Böck in DER decoding.
CVE: CVE-2015-2806
CWE: CWE-119
Vulnerability description: Stack-based buffer overflow in asn1_der_decoding in libtasn1 before 4.4 allows remote attackers to have unspecified impact via unknown vectors.

Project: libtasn1
File: parser_aux.c

_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
{
  if (node == NULL)
    return node;

  if (node->value)
    {
      if (node->value != node->small_value)
	free (node->value);
      node->value = NULL;
      node->value_len = 0;
    }

  if (!len)
    return node;

  node->value = value;
  node->value_len = len;

  return node;
}

Project: libtasn1
File: parser_aux.c

_asn1_set_right (asn1_node node, asn1_node right)
{
  if (node == NULL)
    return node;
  node->right = right;
  if (right)
    {
      right->left = node;
      if (right->up == NULL)
        right->up = node->up;
    }
  return node;
}

Project: libtasn1
File: parser_aux.c

_asn1_add_static_node (unsigned int type)
{
  list_type *listElement;
  asn1_node punt;

  punt = calloc (1, sizeof (struct asn1_node_st));
  if (punt == NULL)
    return NULL;

  listElement = malloc (sizeof (list_type));
  if (listElement == NULL)
    {
      free (punt);
      return NULL;
    }

  listElement->node = punt;
  listElement->next = firstElement;
  firstElement = listElement;

  punt->type = type;

  return punt;
}

Project: libtasn1
File: parser_aux.c

_asn1_find_up (asn1_node node)
{
  asn1_node p;

  if (node == NULL)
    return NULL;

  p = node;

  while ((p->left != NULL) && (p->left->right == p))
    p = p->left;

  return p->left;
}

Project: libtasn1
File: parser_aux.c

_asn1_remove_node (asn1_node node, unsigned int flags)
{
  if (node == NULL)
    return;

  if (node->value != NULL)
    {
      if (flags & ASN1_DELETE_FLAG_ZEROIZE)
        {
          safe_memset(node->value, 0, node->value_len);
        }

      if (node->value != node->small_value)
        free (node->value);
    }
  free (node);
}

Project: libtasn1
File: parser_aux.c

_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
{
  int len2;
  void *temp;

  if (node == NULL)
    return node;

  asn1_length_der (len, NULL, &len2);
  temp = malloc (len + len2);
  if (temp == NULL)
    return NULL;

  asn1_octet_der (value, len, temp, &len2);
  return _asn1_set_value_m (node, temp, len2);
}

Project: libtasn1
File: parser_aux.c

_asn1_set_name (asn1_node node, const char *name)
{
  unsigned int nsize;

  if (node == NULL)
    return node;

  if (name == NULL)
    {
      node->name[0] = 0;
      node->name_hash = hash_pjw_bare (node->name, 0);
      return node;
    }

  nsize = _asn1_str_cpy (node->name, sizeof (node->name), name);
  node->name_hash = hash_pjw_bare (node->name, nsize);

  return node;
}

Project: libtasn1
File: parser_aux.c

_asn1_delete_list_and_nodes (void)
{
  list_type *listElement;

  while (firstElement)
    {
      listElement = firstElement;
      firstElement = firstElement->next;
      _asn1_remove_node (listElement->node, 0);
      free (listElement);
    }
}

Project: libtasn1
File: parser_aux.c

_asn1_get_last_right (asn1_node node)
{
  asn1_node p;

  if (node == NULL)
    return NULL;
  p = node;
  while (p->right)
    p = p->right;
  return p;
}

Project: libtasn1
File: parser_aux.c

_asn1_cpy_name (asn1_node dst, asn1_node src)
{
  if (dst == NULL)
    return dst;

  if (src == NULL)
    {
      dst->name[0] = 0;
      dst->name_hash = hash_pjw_bare (dst->name, 0);
      return dst;
    }

  _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
  dst->name_hash = src->name_hash;

  return dst;
}

Project: libtasn1
File: parser_aux.c

_asn1_change_integer_value (asn1_node node)
{
  asn1_node p;
  unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
  unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
  int len;

  if (node == NULL)
    return ASN1_ELEMENT_NOT_FOUND;

  p = node;
  while (p)
    {
      if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
	  && (p->type & CONST_ASSIGN))
	{
	  if (p->value)
	    {
	      _asn1_convert_integer (p->value, val, sizeof (val), &len);
	      asn1_octet_der (val, len, val2, &len);
	      _asn1_set_value (p, val2, len);
	    }
	}

      if (p->down)
	{
	  p = p->down;
	}
      else
	{
	  if (p == node)
	    p = NULL;
	  else if (p->right)
	    p = p->right;
	  else
	    {
	      while (1)
		{
		  p = _asn1_get_up (p);
		  if (p == node)
		    {
		      p = NULL;
		      break;
		    }
		  if (p->right)
		    {
		      p = p->right;
		      break;
		    }
		}
	    }
	}
    }

  return ASN1_SUCCESS;
}

Project: libtasn1
File: parser_aux.c

_asn1_ltostr (long v, char str[LTOSTR_MAX_SIZE])
{
  long d, r;
  char temp[LTOSTR_MAX_SIZE];
  int count, k, start;

  if (v < 0)
    {
      str[0] = '-';
      start = 1;
      v = -v;
    }
  else
    start = 0;

  count = 0;
  do
    {
      d = v / 10;
      r = v - d * 10;
      temp[start + count] = '0' + (char) r;
      count++;
      v = d;
    }
  while (v && ((start+count) < LTOSTR_MAX_SIZE-1));

  for (k = 0; k < count; k++)
    str[k + start] = temp[start + count - k - 1];
  str[count + start] = 0;
  return str;
}

Project: libtasn1
File: parser_aux.c

_asn1_set_default_tag (asn1_node node)
{
  asn1_node p;

  if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
    return ASN1_ELEMENT_NOT_FOUND;

  p = node;
  while (p)
    {
      if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
	  !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
	{
	  if (node->type & CONST_EXPLICIT)
	    p->type |= CONST_EXPLICIT;
	  else
	    p->type |= CONST_IMPLICIT;
	}

      if (p->down)
	{
	  p = p->down;
	}
      else if (p->right)
	p = p->right;
      else
	{
	  while (1)
	    {
	      p = _asn1_get_up (p);
	      if (p == node)
		{
		  p = NULL;
		  break;
		}
	      if (p->right)
		{
		  p = p->right;
		  break;
		}
	    }
	}
    }

  return ASN1_SUCCESS;
}

Project: libtasn1
File: parser_aux.c

_asn1_expand_object_id (asn1_node node)
{
  asn1_node p, p2, p3, p4, p5;
  char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
  int move, tlen;

  if (node == NULL)
    return ASN1_ELEMENT_NOT_FOUND;

  _asn1_str_cpy (name_root, sizeof (name_root), node->name);

  p = node;
  move = DOWN;

  while (!((p == node) && (move == UP)))
    {
      if (move != UP)
	{
	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
	      && (p->type & CONST_ASSIGN))
	    {
	      p2 = p->down;
	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
		{
		  if (p2->value && !isdigit (p2->value[0]))
		    {
		      _asn1_str_cpy (name2, sizeof (name2), name_root);
		      _asn1_str_cat (name2, sizeof (name2), ".");
		      _asn1_str_cat (name2, sizeof (name2),
				     (char *) p2->value);
		      p3 = asn1_find_node (node, name2);
		      if (!p3
			  || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
			  || !(p3->type & CONST_ASSIGN))
			return ASN1_ELEMENT_NOT_FOUND;
		      _asn1_set_down (p, p2->right);
		      _asn1_remove_node (p2, 0);
		      p2 = p;
		      p4 = p3->down;
		      while (p4)
			{
			  if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
			    {
			      p5 =
				_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
			      _asn1_set_name (p5, p4->name);
			      if (p4->value)
			        {
			          tlen = _asn1_strlen (p4->value);
			          if (tlen > 0)
			            _asn1_set_value (p5, p4->value, tlen + 1);
			        }
			      if (p2 == p)
				{
				  _asn1_set_right (p5, p->down);
				  _asn1_set_down (p, p5);
				}
			      else
				{
				  _asn1_set_right (p5, p2->right);
				  _asn1_set_right (p2, p5);
				}
			      p2 = p5;
			    }
			  p4 = p4->right;
			}
		      move = DOWN;
		      continue;
		    }
		}
	    }
	  move = DOWN;
	}
      else
	move = RIGHT;

      if (move == DOWN)
	{
	  if (p->down)
	    p = p->down;
	  else
	    move = RIGHT;
	}

      if (p == node)
	{
	  move = UP;
	  continue;
	}

      if (move == RIGHT)
	{
	  if (p->right)
	    p = p->right;
	  else
	    move = UP;
	}
      if (move == UP)
	p = _asn1_get_up (p);
    }


  /*******************************/
  /*       expand DEFAULT        */
  /*******************************/
  p = node;
  move = DOWN;

  while (!((p == node) && (move == UP)))
    {
      if (move != UP)
	{
	  if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
	      (p->type & CONST_DEFAULT))
	    {
	      p2 = p->down;
	      if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
		{
		  _asn1_str_cpy (name2, sizeof (name2), name_root);
		  _asn1_str_cat (name2, sizeof (name2), ".");
		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
		  p3 = asn1_find_node (node, name2);
		  if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
		      || !(p3->type & CONST_ASSIGN))
		    return ASN1_ELEMENT_NOT_FOUND;
		  p4 = p3->down;
		  name2[0] = 0;
		  while (p4)
		    {
		      if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
			{
			  if (name2[0])
			    _asn1_str_cat (name2, sizeof (name2), ".");
			  _asn1_str_cat (name2, sizeof (name2),
					 (char *) p4->value);
			}
		      p4 = p4->right;
		    }
		  tlen = strlen (name2);
		  if (tlen > 0)
		    _asn1_set_value (p2, name2, tlen + 1);
		}
	    }
	  move = DOWN;
	}
      else
	move = RIGHT;

      if (move == DOWN)
	{
	  if (p->down)
	    p = p->down;
	  else
	    move = RIGHT;
	}

      if (p == node)
	{
	  move = UP;
	  continue;
	}

      if (move == RIGHT)
	{
	  if (p->right)
	    p = p->right;
	  else
	    move = UP;
	}
      if (move == UP)
	p = _asn1_get_up (p);
    }

  return ASN1_SUCCESS;
}

Project: libtasn1
File: parser_aux.c

_asn1_check_identifier (asn1_node node)
{
  asn1_node p, p2;
  char name2[ASN1_MAX_NAME_SIZE * 2 + 2];

  if (node == NULL)
    return ASN1_ELEMENT_NOT_FOUND;

  p = node;
  while (p)
    {
      if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
	{
	  _asn1_str_cpy (name2, sizeof (name2), node->name);
	  _asn1_str_cat (name2, sizeof (name2), ".");
	  _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
	  p2 = asn1_find_node (node, name2);
	  if (p2 == NULL)
	    {
	      if (p->value)
		_asn1_strcpy (_asn1_identifierMissing, p->value);
	      else
		_asn1_strcpy (_asn1_identifierMissing, "(null)");
	      return ASN1_IDENTIFIER_NOT_FOUND;
	    }
	}
      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
	       (p->type & CONST_DEFAULT))
	{
	  p2 = p->down;
	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
	    {
	      _asn1_str_cpy (name2, sizeof (name2), node->name);
	      _asn1_str_cat (name2, sizeof (name2), ".");
	      _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
	      _asn1_strcpy (_asn1_identifierMissing, p2->value);
	      p2 = asn1_find_node (node, name2);
	      if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
		  !(p2->type & CONST_ASSIGN))
		return ASN1_IDENTIFIER_NOT_FOUND;
	      else
		_asn1_identifierMissing[0] = 0;
	    }
	}
      else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
	       (p->type & CONST_ASSIGN))
	{
	  p2 = p->down;
	  if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
	    {
	      if (p2->value && !isdigit (p2->value[0]))
		{
		  _asn1_str_cpy (name2, sizeof (name2), node->name);
		  _asn1_str_cat (name2, sizeof (name2), ".");
		  _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
		  _asn1_strcpy (_asn1_identifierMissing, p2->value);
		  p2 = asn1_find_node (node, name2);
		  if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
		      || !(p2->type & CONST_ASSIGN))
		    return ASN1_IDENTIFIER_NOT_FOUND;
		  else
		    _asn1_identifierMissing[0] = 0;
		}
	    }
	}

      if (p->down)
	{
	  p = p->down;
	}
      else if (p->right)
	p = p->right;
      else
	{
	  while (1)
	    {
	      p = _asn1_get_up (p);
	      if (p == node)
		{
		  p = NULL;
		  break;
		}
	      if (p->right)
		{
		  p = p->right;
		  break;
		}
	    }
	}
    }

  return ASN1_SUCCESS;
}

Project: libtasn1
File: parser_aux.c

_asn1_delete_list (void)
{
  list_type *listElement;

  while (firstElement)
    {
      listElement = firstElement;
      firstElement = firstElement->next;
      free (listElement);
    }
}

Project: libtasn1
File: parser_aux.c

_asn1_set_value (asn1_node node, const void *value, unsigned int len)
{
  if (node == NULL)
    return node;
  if (node->value)
    {
      if (node->value != node->small_value)
	free (node->value);
      node->value = NULL;
      node->value_len = 0;
    }

  if (!len)
    return node;

  if (len < sizeof (node->small_value))
    {
      node->value = node->small_value;
    }
  else
    {
      node->value = malloc (len);
      if (node->value == NULL)
	return NULL;
    }
  node->value_len = len;

  memcpy (node->value, value, len);
  return node;
}

Project: libtasn1
File: parser_aux.c

_asn1_append_value (asn1_node node, const void *value, unsigned int len)
{
  if (node == NULL)
    return node;
  if (node->value != NULL && node->value != node->small_value)
    {
      /* value is allocated */
      int prev_len = node->value_len;
      node->value_len += len;
      node->value = realloc (node->value, node->value_len);
      if (node->value == NULL)
	{
	  node->value_len = 0;
	  return NULL;
	}
      memcpy (&node->value[prev_len], value, len);

      return node;
    }
  else if (node->value == node->small_value)
    {
      /* value is in node */
      int prev_len = node->value_len;
      node->value_len += len;
      node->value = malloc (node->value_len);
      if (node->value == NULL)
	{
	  node->value_len = 0;
	  return NULL;
	}
      memcpy (node->value, node->small_value, prev_len);
      memcpy (&node->value[prev_len], value, len);

      return node;
    }
  else				/* node->value == NULL */
    return _asn1_set_value (node, value, len);
}

Project: libtasn1
File: parser_aux.c

_asn1_type_set_config (asn1_node node)
{
  asn1_node p, p2;
  int move;

  if (node == NULL)
    return ASN1_ELEMENT_NOT_FOUND;

  p = node;
  move = DOWN;

  while (!((p == node) && (move == UP)))
    {
      if (move != UP)
	{
	  if (type_field (p->type) == ASN1_ETYPE_SET)
	    {
	      p2 = p->down;
	      while (p2)
		{
		  if (type_field (p2->type) != ASN1_ETYPE_TAG)
		    p2->type |= CONST_SET | CONST_NOT_USED;
		  p2 = p2->right;
		}
	    }
	  move = DOWN;
	}
      else
	move = RIGHT;

      if (move == DOWN)
	{
	  if (p->down)
	    p = p->down;
	  else
	    move = RIGHT;
	}

      if (p == node)
	{
	  move = UP;
	  continue;
	}

      if (move == RIGHT)
	{
	  if (p->right)
	    p = p->right;
	  else
	    move = UP;
	}
      if (move == UP)
	p = _asn1_get_up (p);
    }

  return ASN1_SUCCESS;
}