From bae1ad3427106dbfe5a0bb285cfa52a4b61b24f4 Mon Sep 17 00:00:00 2001
From: Emilia Kasper <emilia@openssl.org>
Date: Wed, 2 Jul 2014 19:02:33 +0200
Subject: [PATCH 10/10] Fix OID handling:

- Upon parsing, reject OIDs with invalid base-128 encoding.
- Always NUL-terminate the destination buffer in OBJ_obj2txt printing function.

CVE-2014-3508

Reviewed-by: Dr. Stephen Henson <steve@openssl.org>
Reviewed-by: Kurt Roeckx <kurt@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
---
 crypto/asn1/a_object.c   | 30 +++++++++++++++++++++---------
 crypto/objects/obj_dat.c | 16 +++++++++-------
 2 files changed, 30 insertions(+), 16 deletions(-)

Index: openssl-0.9.8o/crypto/asn1/a_object.c
===================================================================
--- openssl-0.9.8o.orig/crypto/asn1/a_object.c	2010-03-07 16:40:31.000000000 +0000
+++ openssl-0.9.8o/crypto/asn1/a_object.c	2014-08-06 19:40:22.090480888 +0000
@@ -285,16 +285,28 @@
 		ASN1_OBJECT_free(ret);
 	return(NULL);
 }
+
 ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
 	     long len)
 	{
 	ASN1_OBJECT *ret=NULL;
 	const unsigned char *p;
-	int i;
-	/* Sanity check OID encoding: can't have leading 0x80 in
-	 * subidentifiers, see: X.690 8.19.2
+	int i, length;
+
+	/* Sanity check OID encoding.
+	 * Need at least one content octet.
+	 * MSB must be clear in the last octet.
+	 * can't have leading 0x80 in subidentifiers, see: X.690 8.19.2
 	 */
-	for (i = 0, p = *pp + 1; i < len - 1; i++, p++)
+	if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
+	    p[len - 1] & 0x80)
+		{
+		ASN1err(ASN1_F_C2I_ASN1_OBJECT,ASN1_R_INVALID_OBJECT_ENCODING);
+		return NULL;
+		}
+	/* Now 0 < len <= INT_MAX, so the cast is safe. */
+	length = (int)len;
+	for (i = 0; i < length; i++, p++)
 		{
 		if (*p == 0x80 && (!i || !(p[-1] & 0x80)))
 			{
@@ -313,20 +325,20 @@
 	else	ret=(*a);
 
 	p= *pp;
-	if ((ret->data == NULL) || (ret->length < len))
+	if ((ret->data == NULL) || (ret->length < length))
 		{
 		if (ret->data != NULL) OPENSSL_free(ret->data);
-		ret->data=(unsigned char *)OPENSSL_malloc(len ? (int)len : 1);
+		ret->data=(unsigned char *)OPENSSL_malloc(length);
 		ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA;
 		if (ret->data == NULL)
 			{ i=ERR_R_MALLOC_FAILURE; goto err; }
 		}
-	memcpy(ret->data,p,(int)len);
-	ret->length=(int)len;
+	memcpy(ret->data,p,length);
+	ret->length=length;
 	ret->sn=NULL;
 	ret->ln=NULL;
 	/* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */
-	p+=len;
+	p+=length;
 
 	if (a != NULL) (*a)=ret;
 	*pp=p;
Index: openssl-0.9.8o/crypto/objects/obj_dat.c
===================================================================
--- openssl-0.9.8o.orig/crypto/objects/obj_dat.c	2009-11-10 01:00:37.000000000 +0000
+++ openssl-0.9.8o/crypto/objects/obj_dat.c	2014-08-06 19:36:39.959096721 +0000
@@ -444,11 +444,12 @@
 	unsigned char *p;
 	char tbuf[DECIMAL_SIZE(i)+DECIMAL_SIZE(l)+2];
 
-	if ((a == NULL) || (a->data == NULL)) {
-		buf[0]='\0';
-		return(0);
-	}
+	/* Ensure that, at every state, |buf| is NUL-terminated. */
+	if (buf && buf_len > 0)
+		buf[0] = '\0';
 
+	if ((a == NULL) || (a->data == NULL))
+		return(0);
 
 	if (!no_name && (nid=OBJ_obj2nid(a)) != NID_undef)
 		{
@@ -527,9 +528,10 @@
 				i=(int)(l/40);
 				l-=(long)(i*40);
 				}
-			if (buf && (buf_len > 0))
+			if (buf && (buf_len > 1))
 				{
 				*buf++ = i + '0';
+				*buf = '\0';
 				buf_len--;
 				}
 			n++;
@@ -544,9 +546,10 @@
 			i = strlen(bndec);
 			if (buf)
 				{
-				if (buf_len > 0)
+				if (buf_len > 1)
 					{
 					*buf++ = '.';
+					*buf = '\0';
 					buf_len--;
 					}
 				BUF_strlcpy(buf,bndec,buf_len);
@@ -786,4 +789,3 @@
 	OPENSSL_free(buf);
 	return(ok);
 	}
-
