Return error when a bit string indicates an invalid amount of bits left

(Imported from upstream's 5a1e8c67a90aead86ccc2dda324e8f897d1a044d)

Change-Id: Idfba7eb8244c1926e7921119767cb32605a74202
Reviewed-on: https://boringssl-review.googlesource.com/2836
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c
index 4917bda..5038455 100644
--- a/crypto/asn1/a_bitstr.c
+++ b/crypto/asn1/a_bitstr.c
@@ -118,11 +118,12 @@
 	ASN1_BIT_STRING *ret=NULL;
 	const unsigned char *p;
 	unsigned char *s;
-	int i;
+	int padding;
 
 	if (len < 1)
 		{
-		i=ASN1_R_STRING_TOO_SHORT;
+		OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
+			ASN1_R_STRING_TOO_SHORT);
 		goto err;
 		}
 
@@ -134,23 +135,31 @@
 		ret=(*a);
 
 	p= *pp;
-	i= *(p++);
+	padding = *(p++);
+	if (padding > 7)
+		{
+		OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
+			ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
+		goto err;
+		}
+
 	/* We do this to preserve the settings.  If we modify
 	 * the settings, via the _set_bit function, we will recalculate
 	 * on output */
 	ret->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
-	ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|(i&0x07)); /* set */
+	ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|padding); /* set */
 
 	if (len-- > 1) /* using one because of the bits left byte */
 		{
 		s=(unsigned char *)OPENSSL_malloc((int)len);
 		if (s == NULL)
 			{
-			i=ERR_R_MALLOC_FAILURE;
+			OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING,
+				ERR_R_MALLOC_FAILURE);
 			goto err;
 			}
 		memcpy(s,p,(int)len);
-		s[len-1]&=(0xff<<i);
+		s[len-1]&=(0xff<<padding);
 		p+=len;
 		}
 	else
@@ -164,7 +173,6 @@
 	*pp=p;
 	return(ret);
 err:
-	OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING, i);
 	if ((ret != NULL) && ((a == NULL) || (*a != ret)))
 		M_ASN1_BIT_STRING_free(ret);
 	return(NULL);
diff --git a/crypto/asn1/asn1_error.c b/crypto/asn1/asn1_error.c
index 87a7b64..5e9fcaa 100644
--- a/crypto/asn1/asn1_error.c
+++ b/crypto/asn1/asn1_error.c
@@ -130,6 +130,7 @@
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_TIME_VALUE), "ILLEGAL_TIME_VALUE"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_NOT_ASCII_FORMAT), "INTEGER_NOT_ASCII_FORMAT"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG), "INTEGER_TOO_LARGE_FOR_LONG"},
+  {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_BIT_STRING_BITS_LEFT), "INVALID_BIT_STRING_BITS_LEFT"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_BMPSTRING_LENGTH), "INVALID_BMPSTRING_LENGTH"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_DIGIT), "INVALID_DIGIT"},
   {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_MIME_TYPE), "INVALID_MIME_TYPE"},
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 038d4e2..a9864bc 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -1259,5 +1259,6 @@
 #define ASN1_R_WRONG_TAG 221
 #define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 222
 #define ASN1_R_TYPE_NOT_PRIMITIVE 223
+#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 224
 
 #endif