forsyth20121205-174063a80cc13 years agoHistory
4125 lines · 89.9 KB · Brainfuck
RawDownload
implement X509; include "sys.m";	sys				: Sys; include "asn1.m";	asn1				: ASN1;	Elem, Tag, Value, Oid,	Universal, Context,	BOOLEAN,	INTEGER,	BIT_STRING,	OCTET_STRING,	OBJECT_ID,	SEQUENCE,	UTCTime,	IA5String,	GeneralString,	GeneralizedTime			: import asn1; include "keyring.m";	keyring				: Keyring;	IPint, DESstate	: import keyring; include "security.m";	random				: Random; include "daytime.m";	daytime				: Daytime; include "pkcs.m";	pkcs				: PKCS; include "x509.m"; X509_DEBUG 				: con 0;logfd 					: ref Sys->FD; TAG_MASK 				: con 16r1F;CONSTR_MASK 				: con 16r20;CLASS_MASK 				: con 16rC0; # object identifiers objIdTab = array [] of {	id_at =>			Oid(array [] of {2,5,4}),	id_at_commonName => 		Oid(array [] of {2,5,4,3}),	id_at_countryName => 		Oid(array [] of {2,5,4,6}),	id_at_localityName => 		Oid(array [] of {2,5,4,7}), 	id_at_stateOrProvinceName => 	Oid(array [] of {2,5,4,8}),	id_at_organizationName =>	Oid(array [] of {2,5,4,10}),	id_at_organizationalUnitName => Oid(array [] of {2,5,4,11}), 	id_at_userPassword =>		Oid(array [] of {2,5,4,35}),	id_at_userCertificate =>	Oid(array [] of {2,5,4,36}),	id_at_cAcertificate =>		Oid(array [] of {2,5,4,37}),	id_at_authorityRevocationList =>					Oid(array [] of {2,5,4,38}),	id_at_certificateRevocationList =>					Oid(array [] of {2,5,4,39}),	id_at_crossCertificatePair =>	Oid(array [] of {2,5,4,40}),# 	id_at_crossCertificatePair => 	Oid(array [] of {2,5,4,58}),	id_at_supportedAlgorithms =>	Oid(array [] of {2,5,4,52}),	id_at_deltaRevocationList =>	Oid(array [] of {2,5,4,53}), 	id_ce =>			Oid(array [] of {2,5,29}),	id_ce_subjectDirectoryAttributes =>					Oid(array [] of {2,5,29,9}),	id_ce_subjectKeyIdentifier =>	Oid(array [] of {2,5,29,14}),	id_ce_keyUsage =>		Oid(array [] of {2,5,29,15}),	id_ce_privateKeyUsage =>	Oid(array [] of {2,5,29,16}),	id_ce_subjectAltName =>		Oid(array [] of {2,5,29,17}),	id_ce_issuerAltName =>		Oid(array [] of {2,5,29,18}),	id_ce_basicConstraints =>	Oid(array [] of {2,5,29,19}),	id_ce_cRLNumber =>		Oid(array [] of {2,5,29,20}),	id_ce_reasonCode =>		Oid(array [] of {2,5,29,21}),	id_ce_instructionCode =>	Oid(array [] of {2,5,29,23}),	id_ce_invalidityDate =>		Oid(array [] of {2,5,29,24}),	id_ce_deltaCRLIndicator =>	Oid(array [] of {2,5,29,27}),	id_ce_issuingDistributionPoint =>					Oid(array [] of {2,5,29,28}),	id_ce_certificateIssuer =>	Oid(array [] of {2,5,29,29}),	id_ce_nameConstraints =>	Oid(array [] of {2,5,29,30}),	id_ce_cRLDistributionPoint =>	Oid(array [] of {2,5,29,31}),	id_ce_certificatePolicies =>	Oid(array [] of {2,5,29,32}),	id_ce_policyMapping =>		Oid(array [] of {2,5,29,33}),	id_ce_authorityKeyIdentifier =>					Oid(array [] of {2,5,29,35}),	id_ce_policyConstraints	=>	Oid(array [] of {2,5,29,36}), #	id_mr =>			Oid(array [] of {2,5,?}),# 	id_mr_certificateMatch =>	Oid(array [] of {2,5,?,35}),# 	id_mr_certificatePairExactMatch	=>#					Oid(array [] of {2,5,?,36}),# 	id_mr_certificatePairMatch =>	Oid(array [] of {2,5,?,37}),# 	id_mr_certificateListExactMatch	=>#					Oid(array [] of {2,5,?,38}),# 	id_mr_certificateListMatch =>	Oid(array [] of {2,5,?,39}),# 	id_mr_algorithmidentifierMatch =>#					Oid(array [] of {2,5,?,40})}; # [public] init(): string{	sys = load Sys Sys->PATH; 	if(X509_DEBUG)		logfd = sys->fildes(1); 	keyring = load Keyring Keyring->PATH;	if(keyring == nil)		return sys->sprint("load %s: %r", Keyring->PATH); 	random = load Random Random->PATH;	if(random == nil)		return sys->sprint("load %s: %r", Random->PATH); 	daytime = load Daytime Daytime->PATH;	if(daytime == nil)		return sys->sprint("load %s: %r", Daytime->PATH); 	asn1 = load ASN1 ASN1->PATH;	if(asn1 == nil)		return sys->sprint("load %s: %r", ASN1->PATH);	asn1->init(); 	pkcs = load PKCS PKCS->PATH;	if(pkcs == nil)		return sys->sprint("load %s: %r", PKCS->PATH);	if((e := pkcs->init()) != nil)		return sys->sprint("pkcs: %s", e); 	return nil;} # [private] log(s: string){	if(X509_DEBUG)		sys->fprint(logfd, "x509: %s\n", s);} ## SIGNED { ToBeSigned } ::= SEQUENCE {##	toBeSigned	ToBeSigned,##	COMPONENTS OF	SIGNATURE { ToBeSigned }}#### SIGNATURE {OfSignature} ::= SEQUENCE {##	algorithmIdentifier	AlgorithmIdentifier,##	encrypted	ENCRYPTED { HASHED { OfSignature }}}#### ENCRYPTED { ToBeEnciphered }	::= BIT STRING ( CONSTRAINED BY {##	-- must be the result of applying an encipherment procedure --##	-- to the BER-encoded octets of a value of -- ToBeEnciphered } ) # [public] Signed.decode(a: array of byte): (string, ref Signed){parse:	for(;;) {		# interpret the enclosing structure		(ok, tag, i, n) := der_dec1(a, 0, len a);		if(!ok || n != len a || !tag.constr || 			tag.class != Universal || tag.num != SEQUENCE)			break parse;		s := ref Signed;		# SIGNED sequence		istart := i;		(ok, tag, i, n) = der_dec1(a, i, len a);		if(!ok || n == len a)			break parse;		s.tobe_signed = a[istart:n];		# AlgIdentifier		istart = n;		(ok, tag, i, n) = der_dec1(a, n, len a);		if(!ok || n == len a 			|| !tag.constr || tag.class != Universal || tag.num != SEQUENCE) {			if(X509_DEBUG)				log("signed: der data: " + 				sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", 				ok, n, tag.constr, tag.class, tag.num));			break parse;		}		(ok, s.alg) = decode_algid(a[istart:n]);		if(!ok) {			if(X509_DEBUG)				log("signed: alg identifier: syntax error");			break;				}		# signature		(ok, tag, i, n) = der_dec1(a, n, len a);		if(!ok || n != len a			|| tag.constr || tag.class != Universal || tag.num != BIT_STRING) {			if(X509_DEBUG)				log("signed: signature: " + 				sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d", 				ok, n, tag.constr, tag.class, tag.num));			break parse;		}		s.signature = a[i:n];		# to the end of no error been found		return ("", s);	}	return ("signed: syntax error", nil);} # [public]# der encoding of signed data Signed.encode(s: self ref Signed): (string, array of byte){	(err, e_dat) := asn1->decode(s.tobe_signed); # why?	if(err != "")		return (err, nil);	e_alg := pack_alg(s.alg);	e_sig := ref Elem(			Tag(Universal, BIT_STRING, 0), 			ref Value.BitString(0,s.signature) # DER encode of BIT STRING		);	all := ref Elem(			Tag(Universal, SEQUENCE, 1), 			ref Value.Seq(e_dat::e_alg::e_sig::nil)		);	return asn1->encode(all);} # [public] Signed.sign(s: self ref Signed, sk: ref PrivateKey, hash: int): (string, array of byte){	# we require tobe_signed has 0 bits of padding		if(int s.tobe_signed[0] != 0)		return ("syntax error", nil);	pick key := sk {	RSA =>		(err, signature) := pkcs->rsa_sign(s.tobe_signed, key.sk, hash);		s.signature = signature;		# TODO: add AlgIdentifier based on public key and hash		return (err, signature);	DSS =>		# TODO: hash s.tobe_signed for signing		(err, signature) := pkcs->dss_sign(s.tobe_signed, key.sk);		s.signature = signature;		return (err, signature);	DH =>		return ("cannot sign using DH algorithm", nil);	}	return ("sign: failed", nil);} # [public]# hash algorithm should be MD2, MD4, MD5 or SHA Signed.verify(s: self ref Signed, pk: ref PublicKey, hash: int): int{	ok := 0; 	pick key := pk {	RSA =>		ok = pkcs->rsa_verify(s.tobe_signed, s.signature, key.pk, hash);	DSS =>			# TODO: hash s.tobe_signed for verifying		ok = pkcs->dss_verify(s.tobe_signed, s.signature, key.pk);	DH =>		# simply failure	} 	return ok;} # [public] Signed.tostring(s: self ref Signed): string{	str := "Signed"; 	str += "\nToBeSigned: " + bastr(s.tobe_signed);	str += "\nAlgorithm: " + s.alg.tostring();	str += "\nSignature: " + bastr(s.signature); 	return str + "\n";} # DER# a) the definite form of length encoding shall be used, encoded in the minimum number of #    octets;# b) for string types, the constructed form of encoding shall not be used;# c) if the value of a type is its default value, it shall be absent;# d) the components of a Set type shall be encoded in ascending order of their tag value;# e) the components of a Set-of type shall be encoded in ascending order of their octet value;# f) if the value of a Boolean type is true, the encoding shall have its contents octet #    set to "FF"16;# g) each unused bits in the final octet of the encoding of a Bit String value, if there are #    any, shall be set to zero;# h) the encoding of a Real type shall be such that bases 8, 10, and 16 shall not be used, #    and the binary scaling factor shall be zero. # [private]# decode ASN1 one record at a time and return (err, tag, start of data, # end of data) for indefinite length, the end of data is same as 'n' der_dec1(a: array of byte, i, n: int): (int, Tag, int, int){	length: int;	tag: Tag;	ok := 1;	(ok, i, tag) = der_dectag(a, i, n);	if(ok) {		(ok, i, length) = der_declen(a, i, n);		if(ok) {			if(length == -1) {				if(!tag.constr)					ok = 0;				length = n - i;			}			else {				if(i+length > n)					ok = 0;			}		}	}	if(!ok && X509_DEBUG)		log("der_dec1: syntax error");	return (ok, tag, i, i+length);} # [private]# der tag decode der_dectag(a: array of byte, i, n: int): (int, int, Tag){	ok := 1;	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			(ok, i, num) = uint7_decode(a, i, n);	}	else		ok = 0;	if(!ok && X509_DEBUG)		log("der_declen: syntax error");	return (ok, i, Tag(class, num, constr));} # [private] int_decode(a: array of byte, i, n, count, unsigned: int): (int, int, int){	ok := 1;	num := 0;	if(n-i >= count) {		if((count > 4) || (unsigned && count == 4 && (int a[i] & 16r80)))			ok = 1;		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		ok = 0;	if(!ok && X509_DEBUG)		log("int_decode: syntax error");	return (ok, i, num);}  # [private] uint7_decode(a: array of byte, i, n: int) : (int, int, int){	ok := 1;	num := 0;	more := 1;	while(more && i < n) {		v := int a[i++];		if(num & 16r7F000000) {			ok = 0;			break;		}		num <<= 7;		more = v & 16r80;		num |= (v & 16r7F);	}	if(n == i)		ok = 0;	if(!ok && X509_DEBUG)		log("uint7_decode: syntax error");	return (ok, i, num);}  # [private]# der length decode - the definite form of length encoding shall be used, encoded # in the minimum number of octets der_declen(a: array of byte, i, n: int): (int, int, int){	ok := 1;	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) # indefinite length			ok = 0;		else			num = v;	}	else		ok = 0;	if(!ok && X509_DEBUG)		log("der_declen: syntax error");	return (ok, i, num);} # [private]# parse der encoded algorithm identifier decode_algid(a: array of byte): (int, ref AlgIdentifier){	(err, el) := asn1->decode(a);	if(err != "") {		if(X509_DEBUG)			log("decode_algid: " + err);		return (0, nil);	}	return parse_alg(el);}  ## TBS (Public Key) Certificate is signed by Certificate Authority and contains ## information of public key usage (as a comparison of Certificate Revocation List ## and Attribute Certificate). # [public]# constructs a certificate by parsing a der encoded certificate# returns error if parsing is failed or nil if parsing is ok certsyn(s: string): (string, ref Certificate){	if(0)		sys->fprint(sys->fildes(2), "cert: %s\n", s);	return ("certificate syntax: "+s, nil);} #	Certificate ::= SEQUENCE {#		certificateInfo CertificateInfo,#		signatureAlgorithm AlgorithmIdentifier,#		signature BIT STRING }##	CertificateInfo ::= SEQUENCE {#		version [0] INTEGER DEFAULT v1 (0),#		serialNumber INTEGER,#		signature AlgorithmIdentifier,#		issuer Name,#		validity Validity,#		subject Name,#		subjectPublicKeyInfo SubjectPublicKeyInfo }#	(version v2 has two more fields, optional unique identifiers for#  issuer and subject; since we ignore these anyway, we won't parse them)##	Validity ::= SEQUENCE {#		notBefore UTCTime,#		notAfter UTCTime }##	SubjectPublicKeyInfo ::= SEQUENCE {#		algorithm AlgorithmIdentifier,#		subjectPublicKey BIT STRING }##	AlgorithmIdentifier ::= SEQUENCE {#		algorithm OBJECT IDENTIFER,#		parameters ANY DEFINED BY ALGORITHM OPTIONAL }##	Name ::= SEQUENCE OF RelativeDistinguishedName##	RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue##	AttributeTypeAndValue ::= SEQUENCE {#		type OBJECT IDENTIFER,#		value DirectoryString }#	(selected attributes have these Object Ids:#		commonName {2 5 4 3}#		countryName {2 5 4 6}#		localityName {2 5 4 7}#		stateOrProvinceName {2 5 4 8}#		organizationName {2 5 4 10}

Lines 1–500 of 4125.