Plan 9 from Bell Labs’s /usr/web/sources/contrib/mospak/tls-1.2/libsec-x509-decoder-limits.diff

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


--- sys/src/libsec/port/x509.c
+++ sys/src/libsec/port/x509.c
@@ -151,14 +151,23 @@ static mpint	*asn1mpint(Elem *e);
 #define CLASS_MASK 0xC0
 #define MAXOBJIDLEN 20
 
-static int ber_decode(uchar** pp, uchar* pend, Elem* pelem);
+/*
+ * The decoders below recurse over attacker-supplied nesting, so bound
+ * the descent.  Each SEQUENCE or SET level costs two, each constructed
+ * string level one.
+ */
+enum {
+	MAXDEPTH	= 32,
+};
+
+static int ber_decode(uchar** pp, uchar* pend, Elem* pelem, int depth);
 static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr);
 static int length_decode(uchar** pp, uchar* pend, int* plength);
-static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval);
+static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval, int depth);
 static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint);
 static int uint7_decode(uchar** pp, uchar* pend, int* pint);
-static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes);
-static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist);
+static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes, int depth);
+static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist, int depth);
 static int enc(uchar** pp, Elem e, int lenonly);
 static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly);
 static void uint7_enc(uchar** pp, int num, int lenonly);
@@ -204,7 +213,7 @@ decode(uchar* a, int alen, Elem* pelem)
 {
 	uchar* p = a;
 
-	return  ber_decode(&p, &a[alen], pelem);
+	return  ber_decode(&p, &a[alen], pelem, 0);
 }
 
 /*
@@ -216,7 +225,7 @@ decode_seq(uchar* a, int alen, Elist** pelist)
 {
 	uchar* p = a;
 
-	return seq_decode(&p, &a[alen], -1, 1, pelist);
+	return seq_decode(&p, &a[alen], -1, 1, pelist, 0);
 }
 
 /*
@@ -233,7 +242,7 @@ decode_value(uchar* a, int alen, int kind, int isconst
 {
 	uchar* p = a;
 
-	return value_decode(&p, &a[alen], alen, kind, isconstr, pval);
+	return value_decode(&p, &a[alen], alen, kind, isconstr, pval, 0);
 }
 
 /*
@@ -251,7 +260,7 @@ static int
 
 /* Decode an ASN1 'Elem' (tag, length, value) */
 static int
-ber_decode(uchar** pp, uchar* pend, Elem* pelem)
+ber_decode(uchar** pp, uchar* pend, Elem* pelem, int depth)
 {
 	int err;
 	int isconstr;
@@ -260,17 +269,19 @@ ber_decode(uchar** pp, uchar* pend, Elem* pelem)
 	Value val;
 	uchar* start;
 
+	if(depth > MAXDEPTH)
+		return ASN_ETOOBIG;
 	start = *pp;
 	err = tag_decode(pp, pend, &tag, &isconstr);
 	if(err == ASN_OK) {
 		err = length_decode(pp, pend, &length);
 		if(err == ASN_OK) {
 			if(tag.class == Universal) {
-				err = value_decode(pp, pend, length, tag.num, isconstr, &val);
+				err = value_decode(pp, pend, length, tag.num, isconstr, &val, depth);
 				if(val.tag == VSeq || val.tag == VSet)
 					setmalloctag(val.u.seqval, getcallerpc(&pp));
 			}else
-				err = value_decode(pp, pend, length, OCTET_STRING, 0, &val);
+				err = value_decode(pp, pend, length, OCTET_STRING, 0, &val, depth);
 			if(err == ASN_OK) {
 				pelem->tag = tag;
 				pelem->val = val;
@@ -338,7 +349,7 @@ static int
 
 /* Decode a value field  */
 static int
-value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval)
+value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval, int depth)
 {
 	int err;
 	Bytes* va;
@@ -435,7 +446,7 @@ value_decode(uchar** pp, uchar* pend, int length, int 
 
 	case OCTET_STRING:
 	case ObjectDescriptor:
-		err = octet_decode(&p, pend, length, isconstr, &va);
+		err = octet_decode(&p, pend, length, isconstr, &va, depth+1);
 		if(err == ASN_OK) {
 			pval->tag = VOctets;
 			pval->u.octetsval = va;
@@ -507,7 +518,7 @@ value_decode(uchar** pp, uchar* pend, int length, int 
 		break;
 
 	case SEQUENCE:
-		err = seq_decode(&p, pend, length, isconstr, &vl);
+		err = seq_decode(&p, pend, length, isconstr, &vl, depth+1);
 		setmalloctag(vl, getcallerpc(&pp));
 		if(err == ASN_OK) {
 			pval->tag = VSeq ;
@@ -516,7 +527,7 @@ value_decode(uchar** pp, uchar* pend, int length, int 
 		break;
 
 	case SETOF:
-		err = seq_decode(&p, pend, length, isconstr, &vl);
+		err = seq_decode(&p, pend, length, isconstr, &vl, depth+1);
 		setmalloctag(vl, getcallerpc(&pp));
 		if(err == ASN_OK) {
 			pval->tag = VSet;
@@ -537,7 +548,7 @@ value_decode(uchar** pp, uchar* pend, int length, int 
 	case UniversalString:
 	case BMPString:
 		/* TODO: figure out when character set conversion is necessary */
-		err = octet_decode(&p, pend, length, isconstr, &va);
+		err = octet_decode(&p, pend, length, isconstr, &va, depth+1);
 		if(err == ASN_OK) {
 			pval->tag = VString;
 			pval->u.stringval = (char*)emalloc(va->len+1);
@@ -640,7 +651,7 @@ static int
  * and otherwise that specified length fits within (*pp..pend)
  */
 static int
-octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes)
+octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes, int depth)
 {
 	int err;
 	uchar* p;
@@ -667,12 +678,13 @@ octet_decode(uchar** pp, uchar* pend, int length, int 
 				break;
 			}
 			pold = p;
-			err = ber_decode(&p, pend, &elem);
+			err = ber_decode(&p, pend, &elem, depth);
 			if(err != ASN_OK)
 				break;
 			switch(elem.val.tag) {
 			case VOctets:
 				newans = catbytes(ans, elem.val.u.octetsval);
+				freevalfields(&elem.val);
 				freebytes(ans);
 				ans = newans;
 				break;
@@ -685,13 +697,17 @@ octet_decode(uchar** pp, uchar* pend, int length, int 
 				goto cloop_done;
 
 			default:
+				freevalfields(&elem.val);
 				p = pold;
 				err = ASN_EINVAL;
 				goto cloop_done;
 			}
 		}
 cloop_done:
-		;
+		if(err != ASN_OK) {
+			freebytes(ans);
+			ans = nil;
+		}
 	}
 	/* callers read va->len at once; an empty string is a Bytes of
 	 * length zero, not nil */
@@ -708,7 +724,7 @@ static int
  * and otherwise that specified length fits within (*p..pend)
  */
 static int
-seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist)
+seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist, int depth)
 {
 	int err;
 	uchar* p;
@@ -718,6 +734,7 @@ seq_decode(uchar** pp, uchar* pend, int length, int is
 	Elem elem;
 	Elist* lve;
 	Elist* lveold;
+	Elist* l;
 
 	err = ASN_OK;
 	ans = nil;
@@ -735,7 +752,7 @@ seq_decode(uchar** pp, uchar* pend, int length, int is
 				break;
 			}
 			pold = p;
-			err = ber_decode(&p, pend, &elem);
+			err = ber_decode(&p, pend, &elem, depth+1);
 			if(err != ASN_OK)
 				break;
 			if(elem.val.tag == VEOC) {
@@ -757,6 +774,11 @@ seq_decode(uchar** pp, uchar* pend, int length, int is
 				ans = lveold;
 			}
 		}
+		else {
+			for(l = lve; l != nil; l = l->tl)
+				freevalfields(&l->hd.val);
+			freeelist(lve);
+		}
 	}
 	*pp = p;
 	*pelist = ans;
@@ -2803,7 +2825,7 @@ digest_certinfo(Bytes *cert, DigestFun digestfun, ucha
 	   p+length < p)
 		return;
 	info = p;
-	if(ber_decode(&p, pend, &elem) != ASN_OK)
+	if(ber_decode(&p, pend, &elem, 0) != ASN_OK)
 		return;
 	freevalfields(&elem.val);
 	if(elem.tag.num != SEQUENCE)

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.