--- /n/sources/plan9/sys/src/libsec/port/x509.c Tue Sep 17 10:50:09 2013 +++ /sys/src/libsec/port/x509.c Tue Apr 22 01:44:43 2025 @@ -149,14 +149,18 @@ #define CLASS_MASK 0xC0 #define MAXOBJIDLEN 20 -static int ber_decode(uchar** pp, uchar* pend, Elem* pelem); +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); @@ -202,7 +206,7 @@ { uchar* p = a; - return ber_decode(&p, &a[alen], pelem); + return ber_decode(&p, &a[alen], pelem, 0); } /* @@ -214,7 +218,7 @@ { uchar* p = a; - return seq_decode(&p, &a[alen], -1, 1, pelist); + return seq_decode(&p, &a[alen], -1, 1, pelist, 0); } /* @@ -231,7 +235,7 @@ { uchar* p = a; - return value_decode(&p, &a[alen], alen, kind, isconstr, pval); + return value_decode(&p, &a[alen], alen, kind, isconstr, pval, 0); } /* @@ -249,7 +253,7 @@ /* 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; @@ -257,15 +261,17 @@ Tag tag; Value val; + if(depth > Maxdepth) + return ASN_ETOOBIG; memset(pelem, 0, sizeof(*pelem)); 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); 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; @@ -331,7 +337,7 @@ /* 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; @@ -428,7 +434,7 @@ 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; @@ -500,7 +506,7 @@ 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 ; @@ -509,7 +515,7 @@ 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; @@ -530,7 +536,7 @@ 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); @@ -631,7 +637,7 @@ * 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; @@ -658,7 +664,7 @@ break; } pold = p; - err = ber_decode(&p, pend, &elem); + err = ber_decode(&p, pend, &elem, depth+1); if(err != ASN_OK) break; switch(elem.val.tag) { @@ -695,7 +701,7 @@ * 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; @@ -722,7 +728,7 @@ 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) { @@ -2171,7 +2177,7 @@ 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)