Charles.Forsyth20060303a828770d19 years agoHistory
1030 lines · 21.9 KB · Brainfuck
RawDownload
implement ASN1; include "sys.m";	sys: Sys; include "asn1.m"; # MasksTAG_MASK : con 16r1F;CONSTR_MASK : con 16r20;CLASS_MASK : con 16rC0; # Decoding errorsOK, ESHORT, ETOOBIG, EVALLEN, ECONSTR, EPRIM, EINVAL, EUNIMPL: con iota; debug : con 0; init(){	sys = load Sys Sys->PATH;} # Decode the whole array as a BER encoding of an ASN1 type.# If there's an error, the return string will contain the error.# Depending on the error, the returned elem may or may not# be nil.decode(a: array of byte) : (string, ref Elem){	(ecode, i, elem) := ber_decode(a, 0, len a);	return (errstr(ecode, i, len a), elem);} # Like decode, but continue decoding after first element# of array ends.decode_seq(a: array of byte) : (string, list of ref Elem){	(ecode, i, elist) := seq_decode(a, 0, len a, -1, 1);	return (errstr(ecode, i, len a), elist);} # Decode the whole array as a BER encoding of an ASN1 value,# (i.e., the part after the tag and length).# Assume the value is encoded as universal tag "kind".# The constr arg is 1 if the value is constructed, 0 if primitive.# If there's an error, the return string will contain the error.# Depending on the error, the returned value may or may not# be nil.decode_value(a: array of byte, kind, constr: int) : (string, ref Value){	n := len a;	(ecode, i, val) := value_decode(a, 0, n, n, kind, constr);	return (errstr(ecode, i, len a), val);} # The rest of the decoding routines take the array (a), the# starting position (i), and the ending position +1 (n).# They return (err code, new i, [... varies]). # for debuggingber_ind := "";ber_ind_save := ""; # Decode an ASN1 (tag, length, value).ber_decode(a: array of byte, i, n: int) : (int, int, ref Elem){	if(debug) {		ber_ind_save = ber_ind;		ber_ind = ber_ind + "  ";		sys->print("%sber_decode, byte %d\n", ber_ind, i);	}	err, length: int;	tag : Tag;	val : ref Value;	elem : ref Elem = nil;	(err, i, tag) = tag_decode(a, i, n);	if(err == OK) {		(err, i, length) = length_decode(a, i, n);		if(err == OK) {			if(debug)				sys->print("%sgot tag %s, length %d, now at byte %d\n",						ber_ind, tag.tostring(), length, i);			if(tag.class == Universal)				(err, i, val) = value_decode(a, i, n, length, tag.num, tag.constr);			else				(err, i, val) = value_decode(a, i, n, length, OCTET_STRING, 0);			if(val != nil)				elem = ref Elem(tag, val);		}	}	if(debug) {		sys->print("%send ber_decode, byte %d\n", ber_ind, i);		if(val != nil) {			sys->print("%sdecode result:\n", ber_ind);			print_elem(elem);		}		if(err != OK)			sys->print("%serror: %s\n", ber_ind, errstr(err, i, i));		ber_ind = ber_ind_save;	}	return (err, i, elem);} # Decode a tag field.  As well as Tag, return an int that# is 1 if the type is constructed, 0 if not.tag_decode(a: array of byte, i, n: int) : (int, int, Tag){	err := OK;	class, num, constr: int;	if(n-i >= 2) {		v := int a[i++];		class = v & CLASS_MASK;		if(v & CONSTR_MASK)			constr = 1;		else			constr = 0;		num = v & TAG_MASK;		if(num == TAG_MASK)			# long tag number			(err, i, num) = uint7_decode(a, i, n);	}	else		err = ESHORT;	return (err, i, Tag(class, num, constr));} # Decode a length field.  Assume it fits in a Limbo int.# If "indefinite length", return -1.length_decode(a: array of byte, i, n: int) : (int, int, int){	err := OK;	num := 0;	if(i < n) {		v := int a[i++];		if(v & 16r80)			return int_decode(a, i, n, v&16r7F, 1);		else if(v == 16r80)			num = -1;		else			num = v;	}	else		err = ESHORT;	return (err, i, num);} # Decode a value according to the encoding of the Universal# type with number "kind" and constructed/primitive according# to "constr", with given length (may be -1, for "indefinite").value_decode(a: array of byte, i, n, length, kind, constr: int) : (int, int, ref Value){	err := OK;	val : ref Value;	va : array of byte;	if(length == -1) {		if(!constr)			err = EINVAL;	}	else if(i+length > n)		err = EVALLEN;	if(err != OK)		return (err, i, nil);	case kind {	0 =>		# marker for end of indefinite constructions		if(length == 0)			val = ref Value.EOC;		else			err = EINVAL;	BOOLEAN =>		if(constr)			err = ECONSTR;		else if(length != 1)			err = EVALLEN;		else {			val = ref Value.Bool(int a[0]);			i++;		}	INTEGER or ENUMERATED =>		if(constr)			err = ECONSTR;		else if(length <= 4) {			num : int;			(err, i, num) = int_decode(a, i, i+length, length, 0);			if(err == OK)				val = ref Value.Int(num);		}		else {			va = array[length] of byte;			va[0:] = a[i:i+length];			val = ref Value.BigInt(va);			i += length;		}	BIT_STRING =>		if(constr) {			if(length == -1 && i+2 <= n && a[i] == byte 0 && a[i+1] == byte 0) {				val = ref Value.BitString(0, nil);				i += 2;			}			else				# TODO: recurse and concat results				err = EUNIMPL;		}		else {			if(length < 2) {				if(length == 1 && a[0] == byte 0) {					val = ref Value.BitString(0, nil);					i ++;				}				else					err = EINVAL;			}			else {				bitsunused := int a[i];				if(bitsunused > 7)					err = EINVAL;				else if(length > 16r0FFFFFFF)					err = ETOOBIG;				else {					va = array[length-1] of byte;					va[0:] = a[i+1:i+length];					val = ref Value.BitString(bitsunused, va);					i += length;				}			}		}	OCTET_STRING or ObjectDescriptor =>		(err, i, va) = octet_decode(a, i, n, length, constr);		if(err == OK)			val = ref Value.Octets(va);	NULL =>		if(constr)			err = ECONSTR;		else if(length != 0)			err = EVALLEN;		else			val = ref Value.Null;	OBJECT_ID =>		if(constr)			err = ECONSTR;		else if (length == 0)			err = EVALLEN;		else {			subids : list of int = nil;			iend := i+length;			while(i < iend) {				x : int;				(err, i, x) = uint7_decode(a, i, n);				if(err != OK)					break;				subids = x :: subids;			}			if(err == OK) {				if(i != iend)					err = EVALLEN;				else {					m := len subids;					ia := array[m+1] of int;					while(subids != nil) {						y := hd subids;						subids = tl subids;						if(m == 1) {							ia[1] = y % 40;							ia[0] = y / 40;						}						else							ia[m--] = y;					}					val = ref Value.ObjId(ref Oid(ia));				}			}		}	EXTERNAL or EMBEDDED_PDV =>		# TODO: parse this internally		va = array[length] of byte;		va[0:] = a[i:i+length];		val = ref Value.Other(va);		i += length;	REAL =>		# let the appl decode, with math module		if(constr)			err = ECONSTR;		else {			va = array[length] of byte;			va[0:] = a[i:i+length];			val = ref Value.Real(va);			i += length;		}	SEQUENCE or SET=>		vl : list of ref Elem;		(err, i, vl) = seq_decode(a, i, n, length, constr);		if(err == OK) {			if(kind == SEQUENCE)				val = ref Value.Seq(vl);			else				val = ref Value.Set(vl);		}	NumericString or PrintableString or TeletexString	or VideotexString or IA5String or UTCTime	or GeneralizedTime or GraphicString or VisibleString	or GeneralString or UniversalString or BMPString =>		(err, i, va) = octet_decode(a, i, n, length, constr);		if(err == OK)			# sometimes wrong: need to do char set conversion			val = ref Value.String(string va);			* =>		va = array[length] of byte;		va[0:] = a[i:i+length];		val = ref Value.Other(va);		i += length;	}	return (err, i, val);} # Decode an int in format where count bytes are# concatenated to form value.# Although ASN1 allows any size integer, we return# an error if the result doesn't fit in a Limbo int.# If unsigned is not set, make sure to propagate sign bit.int_decode(a: array of byte, i, n, count, unsigned: int) : (int, int, int){	err := OK;	num := 0;	if(n-i >= count) {		if((count > 4) || (unsigned && count == 4 && (int a[i] & 16r80)))			err = ETOOBIG;		else {			if(!unsigned && count > 0 && count < 4 && (int a[i] & 16r80))				num = -1;		# all bits set			for(j := 0; j < count; j++) {				v := int a[i++];				num = (num << 8) | v;			}		}	}	else		err = ESHORT;	return (err, i, num);} # Decode an unsigned int in format where each# byte except last has high bit set, and remaining# seven bits of each byte are concatenated to form value.# Although ASN1 allows any size integer, we return# an error if the result doesn't fit in a Limbo int.uint7_decode(a: array of byte, i, n: int) : (int, int, int){	err := OK;	num := 0;	more := 1;	while(more && i < n) {		v := int a[i++];		if(num & 16r7F000000) {			err = ETOOBIG;			break;		}		num <<= 7;		more = v & 16r80;		num |= (v & 16r7F);	}	if(n == i)		err = ESHORT;	return (err, i, num);} # Decode an octet string, recursively if constr.# We've already checked that length==-1 implies constr==1,# and otherwise that specified length fits within a[i..n].octet_decode(a: array of byte, i, n, length, constr: int) : (int, int, array of byte){	err := OK;	va : array of byte;	if(length >= 0 && !constr) {		va = array[length] of byte;		va[0:] = a[i:i+length];		i += length;	}	else {		# constructed, either definite or indefinite length		lva : list of array of byte = nil;		elem : ref Elem;		istart := i;		totbytes := 0;	    cloop:		for(;;) {			if(length >= 0 && i >= istart+length) {				if(i != istart+length)					err = EVALLEN;				break cloop;			}			oldi := i;			(err, i, elem) = ber_decode(a, i, n);			if(err != OK)				break;			pick v := elem.val {				Octets =>					lva = v.bytes :: lva;					totbytes += len v.bytes;				EOC =>					if(length != -1) {						i = oldi;						err = EINVAL;					}					break cloop;				* =>					i = oldi;					err = EINVAL;					break cloop;			}		}		if(err == OK) {			va = array[totbytes] of byte;			j := totbytes;			while(lva != nil) {				x := hd lva;				lva = tl lva;				m := len x;				va[j-m:] = x[0:];				j -= m;			}		}	}	return (err, i, va);} # Decode a sequence or set.# We've already checked that length==-1 implies constr==1,# and otherwise that specified length fits within a[i..n].seq_decode(a : array of byte, i, n, length, constr: int) : (int, int, list of ref Elem){	err := OK;	ans : list of ref Elem = nil;	if(!constr)		err = EPRIM;	else {		# constructed, either definite or indefinite length		lve : list of ref Elem = nil;		elem : ref Elem;		istart := i;	    cloop:		for(;;) {			if(length >= 0 && i >= istart+length) {				if(i != istart+length)					err = EVALLEN;				break cloop;			}			oldi := i;			(err, i, elem) = ber_decode(a, i, n);			if(err != OK)				break;			pick v := elem.val {				EOC =>					if(length != -1) {						i = oldi;						err = EINVAL;					}					break cloop;				* =>					lve = elem :: lve;			}		}		if(err == OK) {			# reverse back to original order			while(lve != nil) {				e := hd lve;				lve = tl lve;				ans = e :: ans;			}		}	}	return (err, i, ans);} # Encode e by BER rulesencode(e: ref Elem) : (string, array of byte){	(err, n) := enc(nil, e, 0, 1);	if(err != "")		return (err, nil);	b := array[n] of byte;	enc(b, e, 0, 0);	return ("", b);} # Encode e into array b, only putting in bytes if !lenonly.# Start at loc i, return index after.enc(b: array of byte, e: ref Elem, i, lenonly: int) : (string, int){	(err, vlen, constr) := val_enc(b, e, 0, 1);	if(err != "")		return (err, i);	tag := e.tag;	v := tag.class | constr;	if(tag.num < 31) {		if(!lenonly)			b[i] = byte (v | tag.num);		i++;	}	else {		if(!lenonly)

Lines 1–500 of 1030.