xref: /inferno-os/appl/lib/crypt/x509.b (revision e373787f703bc6bc5586ca7d6c988b273aecc39d)
1implement X509;
2
3include "sys.m";
4	sys				: Sys;
5
6include "asn1.m";
7	asn1				: ASN1;
8	Elem, Tag, Value, Oid,
9	Universal, Context,
10	BOOLEAN,
11	INTEGER,
12	BIT_STRING,
13	OCTET_STRING,
14	OBJECT_ID,
15	SEQUENCE,
16	UTCTime,
17	IA5String,
18	GeneralString,
19	GeneralizedTime			: import asn1;
20
21include "keyring.m";
22	keyring				: Keyring;
23	IPint, DESstate	: import keyring;
24
25include "security.m";
26	random				: Random;
27
28include "daytime.m";
29	daytime				: Daytime;
30
31include "pkcs.m";
32	pkcs				: PKCS;
33
34include "x509.m";
35
36X509_DEBUG 				: con 0;
37logfd 					: ref Sys->FD;
38
39TAG_MASK 				: con 16r1F;
40CONSTR_MASK 				: con 16r20;
41CLASS_MASK 				: con 16rC0;
42
43# object identifiers
44
45objIdTab = array [] of {
46	id_at =>			Oid(array [] of {2,5,4}),
47	id_at_commonName => 		Oid(array [] of {2,5,4,3}),
48	id_at_countryName => 		Oid(array [] of {2,5,4,6}),
49	id_at_localityName => 		Oid(array [] of {2,5,4,7}),
50	id_at_stateOrProvinceName => 	Oid(array [] of {2,5,4,8}),
51	id_at_organizationName =>	Oid(array [] of {2,5,4,10}),
52	id_at_organizationalUnitName => Oid(array [] of {2,5,4,11}),
53	id_at_userPassword =>		Oid(array [] of {2,5,4,35}),
54	id_at_userCertificate =>	Oid(array [] of {2,5,4,36}),
55	id_at_cAcertificate =>		Oid(array [] of {2,5,4,37}),
56	id_at_authorityRevocationList =>
57					Oid(array [] of {2,5,4,38}),
58	id_at_certificateRevocationList =>
59					Oid(array [] of {2,5,4,39}),
60	id_at_crossCertificatePair =>	Oid(array [] of {2,5,4,40}),
61# 	id_at_crossCertificatePair => 	Oid(array [] of {2,5,4,58}),
62	id_at_supportedAlgorithms =>	Oid(array [] of {2,5,4,52}),
63	id_at_deltaRevocationList =>	Oid(array [] of {2,5,4,53}),
64
65	id_ce =>			Oid(array [] of {2,5,29}),
66	id_ce_subjectDirectoryAttributes =>
67					Oid(array [] of {2,5,29,9}),
68	id_ce_subjectKeyIdentifier =>	Oid(array [] of {2,5,29,14}),
69	id_ce_keyUsage =>		Oid(array [] of {2,5,29,15}),
70	id_ce_privateKeyUsage =>	Oid(array [] of {2,5,29,16}),
71	id_ce_subjectAltName =>		Oid(array [] of {2,5,29,17}),
72	id_ce_issuerAltName =>		Oid(array [] of {2,5,29,18}),
73	id_ce_basicConstraints =>	Oid(array [] of {2,5,29,19}),
74	id_ce_cRLNumber =>		Oid(array [] of {2,5,29,20}),
75	id_ce_reasonCode =>		Oid(array [] of {2,5,29,21}),
76	id_ce_instructionCode =>	Oid(array [] of {2,5,29,23}),
77	id_ce_invalidityDate =>		Oid(array [] of {2,5,29,24}),
78	id_ce_deltaCRLIndicator =>	Oid(array [] of {2,5,29,27}),
79	id_ce_issuingDistributionPoint =>
80					Oid(array [] of {2,5,29,28}),
81	id_ce_certificateIssuer =>	Oid(array [] of {2,5,29,29}),
82	id_ce_nameConstraints =>	Oid(array [] of {2,5,29,30}),
83	id_ce_cRLDistributionPoint =>	Oid(array [] of {2,5,29,31}),
84	id_ce_certificatePolicies =>	Oid(array [] of {2,5,29,32}),
85	id_ce_policyMapping =>		Oid(array [] of {2,5,29,33}),
86	id_ce_authorityKeyIdentifier =>
87					Oid(array [] of {2,5,29,35}),
88	id_ce_policyConstraints	=>	Oid(array [] of {2,5,29,36}),
89
90#	id_mr =>			Oid(array [] of {2,5,?}),
91# 	id_mr_certificateMatch =>	Oid(array [] of {2,5,?,35}),
92# 	id_mr_certificatePairExactMatch	=>
93#					Oid(array [] of {2,5,?,36}),
94# 	id_mr_certificatePairMatch =>	Oid(array [] of {2,5,?,37}),
95# 	id_mr_certificateListExactMatch	=>
96#					Oid(array [] of {2,5,?,38}),
97# 	id_mr_certificateListMatch =>	Oid(array [] of {2,5,?,39}),
98# 	id_mr_algorithmidentifierMatch =>
99#					Oid(array [] of {2,5,?,40})
100};
101
102# [public]
103
104init(): string
105{
106	sys = load Sys Sys->PATH;
107
108	if(X509_DEBUG)
109		logfd = sys->fildes(1);
110
111	keyring = load Keyring Keyring->PATH;
112	if(keyring == nil)
113		return sys->sprint("load %s: %r", Keyring->PATH);
114
115	random = load Random Random->PATH;
116	if(random == nil)
117		return sys->sprint("load %s: %r", Random->PATH);
118
119	daytime = load Daytime Daytime->PATH;
120	if(daytime == nil)
121		return sys->sprint("load %s: %r", Daytime->PATH);
122
123	asn1 = load ASN1 ASN1->PATH;
124	if(asn1 == nil)
125		return sys->sprint("load %s: %r", ASN1->PATH);
126	asn1->init();
127
128	pkcs = load PKCS PKCS->PATH;
129	if(pkcs == nil)
130		return sys->sprint("load %s: %r", PKCS->PATH);
131	if((e := pkcs->init()) != nil)
132		return sys->sprint("pkcs: %s", e);
133
134	return nil;
135}
136
137# [private]
138
139log(s: string)
140{
141	if(X509_DEBUG)
142		sys->fprint(logfd, "x509: %s\n", s);
143}
144
145## SIGNED { ToBeSigned } ::= SEQUENCE {
146##	toBeSigned	ToBeSigned,
147##	COMPONENTS OF	SIGNATURE { ToBeSigned }}
148##
149## SIGNATURE {OfSignature} ::= SEQUENCE {
150##	algorithmIdentifier	AlgorithmIdentifier,
151##	encrypted	ENCRYPTED { HASHED { OfSignature }}}
152##
153## ENCRYPTED { ToBeEnciphered }	::= BIT STRING ( CONSTRAINED BY {
154##	-- must be the result of applying an encipherment procedure --
155##	-- to the BER-encoded octets of a value of -- ToBeEnciphered } )
156
157# [public]
158
159Signed.decode(a: array of byte): (string, ref Signed)
160{
161parse:
162	for(;;) {
163		# interpret the enclosing structure
164		(ok, tag, i, n) := der_dec1(a, 0, len a);
165		if(!ok || n != len a || !tag.constr ||
166			tag.class != Universal || tag.num != SEQUENCE)
167			break parse;
168		s := ref Signed;
169		# SIGNED sequence
170		istart := i;
171		(ok, tag, i, n) = der_dec1(a, i, len a);
172		if(!ok || n == len a)
173			break parse;
174		s.tobe_signed = a[istart:n];
175		# AlgIdentifier
176		istart = n;
177		(ok, tag, i, n) = der_dec1(a, n, len a);
178		if(!ok || n == len a
179			|| !tag.constr || tag.class != Universal || tag.num != SEQUENCE) {
180			if(X509_DEBUG)
181				log("signed: der data: " +
182				sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d",
183				ok, n, tag.constr, tag.class, tag.num));
184			break parse;
185		}
186		(ok, s.alg) = decode_algid(a[istart:n]);
187		if(!ok) {
188			if(X509_DEBUG)
189				log("signed: alg identifier: syntax error");
190			break;
191		}
192		# signature
193		(ok, tag, i, n) = der_dec1(a, n, len a);
194		if(!ok || n != len a
195			|| tag.constr || tag.class != Universal || tag.num != BIT_STRING) {
196			if(X509_DEBUG)
197				log("signed: signature: " +
198				sys->sprint("ok=%d, n=%d, constr=%d, class=%d, num=%d",
199				ok, n, tag.constr, tag.class, tag.num));
200			break parse;
201		}
202		s.signature = a[i:n];
203		# to the end of no error been found
204		return ("", s);
205	}
206	return ("signed: syntax error", nil);
207}
208
209# [public]
210# der encoding of signed data
211
212Signed.encode(s: self ref Signed): (string, array of byte)
213{
214	(err, e_dat) := asn1->decode(s.tobe_signed); # why?
215	if(err != "")
216		return (err, nil);
217	e_alg := pack_alg(s.alg);
218	e_sig := ref Elem(
219			Tag(Universal, BIT_STRING, 0),
220			ref Value.BitString(0,s.signature) # DER encode of BIT STRING
221		);
222	all := ref Elem(
223			Tag(Universal, SEQUENCE, 1),
224			ref Value.Seq(e_dat::e_alg::e_sig::nil)
225		);
226	return asn1->encode(all);
227}
228
229# [public]
230
231Signed.sign(s: self ref Signed, sk: ref PrivateKey, hash: int): (string, array of byte)
232{
233	# we require tobe_signed has 0 bits of padding
234	if(int s.tobe_signed[0] != 0)
235		return ("syntax error", nil);
236	pick key := sk {
237	RSA =>
238		(err, signature) := pkcs->rsa_sign(s.tobe_signed, key.sk, hash);
239		s.signature = signature;
240		# TODO: add AlgIdentifier based on public key and hash
241		return (err, signature);
242	DSS =>
243		# TODO: hash s.tobe_signed for signing
244		(err, signature) := pkcs->dss_sign(s.tobe_signed, key.sk);
245		s.signature = signature;
246		return (err, signature);
247	DH =>
248		return ("cannot sign using DH algorithm", nil);
249	}
250	return ("sign: failed", nil);
251}
252
253# [public]
254# hash algorithm should be MD2, MD4, MD5 or SHA
255
256Signed.verify(s: self ref Signed, pk: ref PublicKey, hash: int): int
257{
258	ok := 0;
259
260	pick key := pk {
261	RSA =>
262		ok = pkcs->rsa_verify(s.tobe_signed, s.signature, key.pk, hash);
263	DSS =>
264		# TODO: hash s.tobe_signed for verifying
265		ok = pkcs->dss_verify(s.tobe_signed, s.signature, key.pk);
266	DH =>
267		# simply failure
268	}
269
270	return ok;
271}
272
273# [public]
274
275Signed.tostring(s: self ref Signed): string
276{
277	str := "Signed";
278
279	str += "\nToBeSigned: " + bastr(s.tobe_signed);
280	str += "\nAlgorithm: " + s.alg.tostring();
281	str += "\nSignature: " + bastr(s.signature);
282
283	return str + "\n";
284}
285
286# DER
287# a) the definite form of length encoding shall be used, encoded in the minimum number of
288#    octets;
289# b) for string types, the constructed form of encoding shall not be used;
290# c) if the value of a type is its default value, it shall be absent;
291# d) the components of a Set type shall be encoded in ascending order of their tag value;
292# e) the components of a Set-of type shall be encoded in ascending order of their octet value;
293# f) if the value of a Boolean type is true, the encoding shall have its contents octet
294#    set to "FF"16;
295# g) each unused bits in the final octet of the encoding of a Bit String value, if there are
296#    any, shall be set to zero;
297# h) the encoding of a Real type shall be such that bases 8, 10, and 16 shall not be used,
298#    and the binary scaling factor shall be zero.
299
300# [private]
301# decode ASN1 one record at a time and return (err, tag, start of data,
302# end of data) for indefinite length, the end of data is same as 'n'
303
304der_dec1(a: array of byte, i, n: int): (int, Tag, int, int)
305{
306	length: int;
307	tag: Tag;
308	ok := 1;
309	(ok, i, tag) = der_dectag(a, i, n);
310	if(ok) {
311		(ok, i, length) = der_declen(a, i, n);
312		if(ok) {
313			if(length == -1) {
314				if(!tag.constr)
315					ok = 0;
316				length = n - i;
317			}
318			else {
319				if(i+length > n)
320					ok = 0;
321			}
322		}
323	}
324	if(!ok && X509_DEBUG)
325		log("der_dec1: syntax error");
326	return (ok, tag, i, i+length);
327}
328
329# [private]
330# der tag decode
331
332der_dectag(a: array of byte, i, n: int): (int, int, Tag)
333{
334	ok := 1;
335	class, num, constr: int;
336	if(n-i >= 2) {
337		v := int a[i++];
338		class = v & CLASS_MASK;
339		if(v & CONSTR_MASK)
340			constr = 1;
341		else
342			constr = 0;
343		num = v & TAG_MASK;
344		if(num == TAG_MASK)
345			# long tag number
346			(ok, i, num) = uint7_decode(a, i, n);
347	}
348	else
349		ok = 0;
350	if(!ok && X509_DEBUG)
351		log("der_declen: syntax error");
352	return (ok, i, Tag(class, num, constr));
353}
354
355# [private]
356
357int_decode(a: array of byte, i, n, count, unsigned: int): (int, int, int)
358{
359	ok := 1;
360	num := 0;
361	if(n-i >= count) {
362		if((count > 4) || (unsigned && count == 4 && (int a[i] & 16r80)))
363			ok = 1;
364		else {
365			if(!unsigned && count > 0 && count < 4 && (int a[i] & 16r80))
366				num = -1;		# all bits set
367			for(j := 0; j < count; j++) {
368				v := int a[i++];
369				num = (num << 8) | v;
370			}
371		}
372	}
373	else
374		ok = 0;
375	if(!ok && X509_DEBUG)
376		log("int_decode: syntax error");
377	return (ok, i, num);
378}
379
380
381# [private]
382
383uint7_decode(a: array of byte, i, n: int) : (int, int, int)
384{
385	ok := 1;
386	num := 0;
387	more := 1;
388	while(more && i < n) {
389		v := int a[i++];
390		if(num & 16r7F000000) {
391			ok = 0;
392			break;
393		}
394		num <<= 7;
395		more = v & 16r80;
396		num |= (v & 16r7F);
397	}
398	if(n == i)
399		ok = 0;
400	if(!ok && X509_DEBUG)
401		log("uint7_decode: syntax error");
402	return (ok, i, num);
403}
404
405
406# [private]
407# der length decode - the definite form of length encoding shall be used, encoded
408# in the minimum number of octets
409
410der_declen(a: array of byte, i, n: int): (int, int, int)
411{
412	ok := 1;
413	num := 0;
414	if(i < n) {
415		v := int a[i++];
416		if(v & 16r80)
417			return int_decode(a, i, n, v&16r7F, 1);
418		else if(v == 16r80) # indefinite length
419			ok = 0;
420		else
421			num = v;
422	}
423	else
424		ok = 0;
425	if(!ok && X509_DEBUG)
426		log("der_declen: syntax error");
427	return (ok, i, num);
428}
429
430# [private]
431# parse der encoded algorithm identifier
432
433decode_algid(a: array of byte): (int, ref AlgIdentifier)
434{
435	(err, el) := asn1->decode(a);
436	if(err != "") {
437		if(X509_DEBUG)
438			log("decode_algid: " + err);
439		return (0, nil);
440	}
441	return parse_alg(el);
442}
443
444
445## TBS (Public Key) Certificate is signed by Certificate Authority and contains
446## information of public key usage (as a comparison of Certificate Revocation List
447## and Attribute Certificate).
448
449# [public]
450# constructs a certificate by parsing a der encoded certificate
451# returns error if parsing is failed or nil if parsing is ok
452
453certsyn(s: string): (string, ref Certificate)
454{
455	if(0)
456		sys->fprint(sys->fildes(2), "cert: %s\n", s);
457	return ("certificate syntax: "+s, nil);
458}
459
460#	Certificate ::= SEQUENCE {
461#		certificateInfo CertificateInfo,
462#		signatureAlgorithm AlgorithmIdentifier,
463#		signature BIT STRING }
464#
465#	CertificateInfo ::= SEQUENCE {
466#		version [0] INTEGER DEFAULT v1 (0),
467#		serialNumber INTEGER,
468#		signature AlgorithmIdentifier,
469#		issuer Name,
470#		validity Validity,
471#		subject Name,
472#		subjectPublicKeyInfo SubjectPublicKeyInfo }
473#	(version v2 has two more fields, optional unique identifiers for
474#  issuer and subject; since we ignore these anyway, we won't parse them)
475#
476#	Validity ::= SEQUENCE {
477#		notBefore UTCTime,
478#		notAfter UTCTime }
479#
480#	SubjectPublicKeyInfo ::= SEQUENCE {
481#		algorithm AlgorithmIdentifier,
482#		subjectPublicKey BIT STRING }
483#
484#	AlgorithmIdentifier ::= SEQUENCE {
485#		algorithm OBJECT IDENTIFER,
486#		parameters ANY DEFINED BY ALGORITHM OPTIONAL }
487#
488#	Name ::= SEQUENCE OF RelativeDistinguishedName
489#
490#	RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue
491#
492#	AttributeTypeAndValue ::= SEQUENCE {
493#		type OBJECT IDENTIFER,
494#		value DirectoryString }
495#	(selected attributes have these Object Ids:
496#		commonName {2 5 4 3}
497#		countryName {2 5 4 6}
498#		localityName {2 5 4 7}
499#		stateOrProvinceName {2 5 4 8}
500#		organizationName {2 5 4 10}
501#		organizationalUnitName {2 5 4 11}
502#	)
503#
504#	DirectoryString ::= CHOICE {
505#		teletexString TeletexString,
506#		printableString PrintableString,
507#		universalString UniversalString }
508#
509#  See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature.
510
511Certificate.decode(a: array of byte): (string, ref Certificate)
512{
513parse:
514	# break on error
515	for(;;) {
516		(err, all) := asn1->decode(a);
517		if(err != "")
518			return certsyn(err);
519		c := ref Certificate;
520
521		# certificate must be a ASN1 sequence
522		(ok, el) := all.is_seq();
523		if(!ok)
524			return certsyn("invalid certificate sequence");
525
526		if(len el == 3){	# ssl3.b uses CertificateInfo; others use Certificate  (TO DO: fix this botch)
527			certinfo := hd el;
528			sigalgid := hd tl el;
529			sigbits := hd tl tl el;
530
531			# certificate info is another ASN1 sequence
532			(ok, el) = certinfo.is_seq();
533			if(!ok || len el < 6)
534				return certsyn("invalid certificate info sequence");
535		}
536
537		c.version = 0; # set to default (v1)
538		(ok, c.version) = parse_version(hd el);
539		if(!ok)
540			return certsyn("can't parse version");
541		if(c.version > 0) {
542			el = tl el;
543			if(len el < 6)
544				break parse;
545		}
546		# serial number
547		(ok, c.serial_number) = parse_sernum(hd el);
548		if(!ok)
549			return certsyn("can't parse serial number");
550		el = tl el;
551		# signature algorithm
552		(ok, c.sig) = parse_alg(hd el);
553		if(!ok)
554			return certsyn("can't parse sigalg");
555		el = tl el;
556		# issuer
557		(ok, c.issuer) = parse_name(hd el);
558		if(!ok)
559			return certsyn("can't parse issuer");
560		el = tl el;
561		# validity
562		evalidity := hd el;
563		(ok, c.validity) = parse_validity(evalidity);
564		if(!ok)
565			return certsyn("can't parse validity");
566		el = tl el;
567		# Subject
568		(ok, c.subject) = parse_name(hd el);
569		if(!ok)
570			return certsyn("can't parse subject");
571		el = tl el;
572		# SubjectPublicKeyInfo
573		(ok, c.subject_pkinfo) = parse_pkinfo(hd el);
574		if(!ok)
575			return certsyn("can't parse subject pk info");
576		el = tl el;
577		# OPTIONAL for v2 and v3, must be in order
578		# issuer unique identifier
579		if(c.version == 0 && el != nil)
580			return certsyn("bad unique ID");
581		if(el != nil) {
582			if(c.version < 1) # at least v2
583				return certsyn("invalid v1 cert");
584			(ok, c.issuer_uid) = parse_uid(hd el, 1);
585			if(ok)
586				el = tl el;
587		}
588		# subject unique identifier
589		if(el != nil) {
590			if(c.version < 1) # v2 or v3
591				return certsyn("invalid v1 cert");
592			(ok, c.issuer_uid) = parse_uid(hd el, 2);
593			if(ok)
594				el = tl el;
595		}
596		# extensions
597		if(el != nil) {
598			if(c.version < 2) # must be v3
599				return certsyn("invalid v1/v2 cert");
600			e : ref Elem;
601			(ok, e) = is_context(hd el, 3);
602			if (!ok)
603				break parse;
604			(ok, c.exts) = parse_extlist(e);
605			if(!ok)
606				return certsyn("can't parse extension list");
607			el = tl el;
608		}
609		# must be no more left
610		if(el != nil)
611			return certsyn("unexpected data at end");
612		return ("", c);
613	}
614
615	return ("certificate: syntax error", nil);
616}
617
618# [public]
619# a der encoding of certificate data; returns (error, nil) tuple in failure
620
621Certificate.encode(c: self ref Certificate): (string, array of byte)
622{
623pack:
624	for(;;) {
625		el: list of ref Elem;
626		# always has a version packed
627		e_version := pack_version(c.version);
628		if(e_version == nil)
629			break pack;
630		el = e_version :: el;
631		# serial number
632		e_sernum := pack_sernum(c.serial_number);
633		if(e_sernum == nil)
634			break pack;
635		el = e_sernum :: el;
636		# algorithm
637		e_sig := pack_alg(c.sig);
638		if(e_sig == nil)
639			break pack;
640		el = e_sig :: el;
641		# issuer
642		e_issuer := pack_name(c.issuer);
643		if(e_issuer == nil)
644			break pack;
645		el = e_issuer :: el;
646		# validity
647		e_validity := pack_validity(c.validity);
648		if(e_validity == nil)
649			break pack;
650		el = e_validity :: el;
651		# subject
652		e_subject := pack_name(c.subject);
653		if(e_subject == nil)
654			break pack;
655		el = e_subject :: el;
656		# public key info
657		e_pkinfo := pack_pkinfo(c.subject_pkinfo);
658		if(e_pkinfo == nil)
659			break pack;
660		el = e_pkinfo :: el;
661		# issuer unique identifier
662		if(c.issuer_uid != nil) {
663			e_issuer_uid := pack_uid(c.issuer_uid);
664			if(e_issuer_uid == nil)
665				break pack;
666			el = e_issuer_uid :: el;
667		}
668		# subject unique identifier
669		if(c.subject_uid != nil) {
670			e_subject_uid := pack_uid(c.subject_uid);
671			if(e_subject_uid == nil)
672				break pack;
673			el = e_subject_uid :: el;
674		}
675		# extensions
676		if(c.exts != nil) {
677			e_exts := pack_extlist(c.exts);
678			if(e_exts == nil)
679				break pack;
680			el = e_exts :: el;
681		}
682		# SEQUENCE order is important
683		lseq: list of ref Elem;
684		while(el != nil) {
685			lseq = (hd el) :: lseq;
686			el = tl el;
687		}
688		all := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(lseq));
689		return asn1->encode(all);
690	}
691	return ("incompleted certificate; unable to pack", nil);
692}
693
694# [public]
695# converts content of a certificate as visible string
696
697Certificate.tostring(c: self ref Certificate): string
698{
699	s := "\tTBS Certificate";
700	s += "\n\tVersion:\n\t\t" + string c.version;
701	s += "\n\tSerialNumber:\n\t\t" + c.serial_number.iptostr(10);
702	s += "\n\tSignature: " + c.sig.tostring();
703	s += "\n\tIssuer: " + c.issuer.tostring();
704	s += "\n\tValidity: " + c.validity.tostring("local");
705	s += "\n\tSubject: " + c.subject.tostring();
706	s += "\n\tSubjectPKInfo: " + c.subject_pkinfo.tostring();
707	s += "\n\tIssuerUID: " + bastr(c.issuer_uid);
708	s += "\n\tSubjectUID: " + bastr(c.subject_uid);
709	s += "\n\tExtensions: ";
710	exts := c.exts;
711	while(exts != nil) {
712		s += "\t\t" + (hd exts).tostring();
713		exts = tl exts;
714	}
715	return s;
716}
717
718# [public]
719
720Certificate.is_expired(c: self ref Certificate, date: int): int
721{
722	if(date > c.validity.not_after || date < c.validity.not_before)
723		return 1;
724
725	return 0;
726}
727
728
729# [private]
730# version is optional marked by explicit context tag 0; no version is
731# required if default version (v1) is used
732
733parse_version(e: ref Elem): (int, int)
734{
735	ver := 0;
736	(ans, ec) := is_context(e, 0);
737	if(ans) {
738		ok := 0;
739		(ok, ver) = ec.is_int();
740		if(!ok || ver < 0 || ver > 2)
741			return (0, -1);
742	}
743	return (1, ver);
744}
745
746# [private]
747
748pack_version(v: int): ref Elem
749{
750	return ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(v));
751}
752
753# [private]
754
755parse_sernum(e: ref Elem): (int, ref IPint)
756{
757	(ok, a) := e.is_bigint();
758	if(ok)
759		return (1, IPint.bebytestoip(a));
760	if(X509_DEBUG)
761		log("parse_sernum: syntax error");
762	return (0, nil);
763}
764
765# [private]
766
767pack_sernum(sn: ref IPint): ref Elem
768{
769	return ref Elem(Tag(Universal, INTEGER, 0), ref Value.BigInt(sn.iptobebytes()));
770}
771
772# [private]
773
774parse_alg(e: ref Elem): (int, ref AlgIdentifier)
775{
776parse:
777	for(;;) {
778		(ok, el) := e.is_seq();
779		if(!ok || el == nil)
780			break parse;
781		oid: ref Oid;
782		(ok, oid) = (hd el).is_oid();
783		if(!ok)
784			break parse;
785		el = tl el;
786		params: array of byte;
787		if(el != nil) {
788			# TODO: determine the object type based on oid
789			# 	then parse params
790			#unused: int;
791			#(ok, unused, params) = (hd el).is_bitstring();
792			#if(!ok || unused || tl el != nil)
793			#	break parse;
794		}
795		return (1, ref AlgIdentifier(oid, params));
796	}
797	if(X509_DEBUG)
798		log("parse_alg: syntax error");
799	return (0, nil);
800}
801
802# [private]
803
804pack_alg(a: ref AlgIdentifier): ref Elem
805{
806	if(a.oid != nil) {
807		el: list of ref Elem;
808		el = ref Elem(Tag(Universal, ASN1->OBJECT_ID, 0), ref Value.ObjId(a.oid)) :: nil;
809		if(a.parameter != nil)  {
810			el = ref Elem(
811				Tag(Universal, BIT_STRING, 0),
812				ref Value.BitString(0, a.parameter)
813			) :: el;
814		}
815		return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
816	}
817	return nil;
818}
819
820# [private]
821
822parse_name(e: ref Elem): (int, ref Name)
823{
824parse:
825	for(;;) {
826		(ok, el) := e.is_seq();
827		if(!ok)
828			break parse;
829		lrd: list of ref RDName;
830		while(el != nil) {
831			rd: ref RDName;
832			(ok, rd) = parse_rdname(hd el);
833			if(!ok)
834				break parse;
835			lrd = rd :: lrd;
836			el = tl el;
837		}
838		# SEQUENCE
839		l: list of ref RDName;
840		while(lrd != nil) {
841			l = (hd lrd) :: l;
842			lrd = tl lrd;
843		}
844		return (1, ref Name(l));
845	}
846	if(X509_DEBUG)
847		log("parse_name: syntax error");
848	return (0, nil);
849}
850
851# [private]
852
853pack_name(n: ref Name): ref Elem
854{
855	el: list of ref Elem;
856
857	lrd := n.rd_names;
858	while(lrd != nil) {
859		rd := pack_rdname(hd lrd);
860		if(rd == nil)
861			return nil;
862		el = rd :: el;
863		lrd = tl lrd;
864	}
865	# reverse order
866	l: list of ref Elem;
867	while(el != nil) {
868		l = (hd el) :: l;
869		el = tl el;
870	}
871
872	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(l));
873}
874
875# [private]
876
877parse_rdname(e: ref Elem): (int, ref RDName)
878{
879parse:
880	for(;;) {
881		(ok, el) := e.is_set(); # unordered
882		if(!ok)
883			break parse;
884		lava: list of ref AVA;
885		while(el != nil) {
886			ava: ref AVA;
887			(ok, ava) = parse_ava(hd el);
888			if(!ok)
889				break parse;
890			lava = ava :: lava;
891			el = tl el;
892		}
893		return (1, ref RDName(lava));
894	}
895	if(X509_DEBUG)
896		log("parse_rdname: syntax error");
897	return (0, nil);
898}
899
900# [private]
901
902pack_rdname(r: ref RDName): ref Elem
903{
904	el: list of ref Elem;
905	lava := r.avas;
906	while(lava != nil) {
907		ava := pack_ava(hd lava);
908		if(ava == nil)
909			return nil;
910		el = ava :: el;
911		lava = tl lava;
912	}
913	return ref Elem(Tag(Universal, ASN1->SET, 1), ref Value.Set(el));
914}
915
916# [private]
917
918parse_ava(e: ref Elem): (int, ref AVA)
919{
920parse:
921	for(;;) {
922		(ok, el) := e.is_seq();
923		if(!ok || len el != 2)
924			break parse;
925		a := ref AVA;
926		(ok, a.oid) = (hd el).is_oid();
927		if(!ok)
928			break parse;
929		el = tl el;
930		(ok, a.value) = (hd el).is_string();
931		if(!ok)
932			break parse;
933		return (1, a);
934	}
935	if(X509_DEBUG)
936		log("parse_ava: syntax error");
937	return (0, nil);
938}
939
940# [private]
941
942pack_ava(a: ref AVA): ref Elem
943{
944	el: list of ref Elem;
945	if(a.oid == nil || a.value == "")
946		return nil;
947	# Note: order is important
948	el = ref Elem(Tag(Universal, ASN1->GeneralString, 0), ref Value.String(a.value)) :: el;
949	el = ref Elem(Tag(Universal, ASN1->OBJECT_ID, 0), ref Value.ObjId(a.oid)) :: el;
950	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
951}
952
953# [private]
954
955parse_validity(e: ref Elem): (int, ref Validity)
956{
957parse:
958	for(;;) {
959		(ok, el) := e.is_seq();
960		if(!ok || len el != 2)
961			break parse;
962		v := ref Validity;
963		(ok, v.not_before) = parse_time(hd el, UTCTime);
964		if(!ok)
965			break parse;
966		el = tl el;
967		(ok, v.not_after) = parse_time(hd el, UTCTime);
968		if(!ok)
969			break parse;
970		return (1, v);
971	}
972	if(X509_DEBUG)
973		log("parse_validity: syntax error");
974	return (0, nil);
975}
976
977# [private]
978# standard says only UTC Time allowed for TBS Certificate, but there is exception of
979# GeneralizedTime for CRL and Attribute Certificate. Parsing is based on format of
980# UTCTime, GeneralizedTime or undetermined (any int not UTCTime or GeneralizedTime).
981
982parse_time(e: ref Elem, format: int): (int, int)
983{
984parse:
985	for(;;) {
986		(ok, date) := e.is_time();
987		if(!ok)
988			break parse;
989		if(e.tag.num != UTCTime && e.tag.num != GeneralizedTime)
990			break parse;
991		if(format == UTCTime && e.tag.num != UTCTime)
992			break parse;
993		if(format == GeneralizedTime && e.tag.num != GeneralizedTime)
994			break parse;
995		t := decode_time(date, e.tag.num);
996		if(t < 0)
997			break parse;
998		return (1, t);
999	}
1000	if(X509_DEBUG)
1001		log("parse_time: syntax error");
1002	return (0, -1);
1003}
1004
1005# [private]
1006# decode a BER encoded UTC or Generalized time into epoch (seconds since 1/1/1970 GMT)
1007# UTC time format: YYMMDDhhmm[ss](Z|(+|-)hhmm)
1008# Generalized time format: YYYYMMDDhhmm[ss.s(...)](Z|(+|-)hhmm[ss.s(...))
1009
1010decode_time(date: string, format: int): int
1011{
1012	time := ref Daytime->Tm;
1013parse:
1014	for(;;) {
1015    		i := 0;
1016		if(format == UTCTime) {
1017			if(len date < 11)
1018				break parse;
1019			time.year = get2(date, i);
1020	   		if(time.year < 0)
1021        			break parse;
1022			if(time.year < 70)
1023        			time.year += 100;
1024			i += 2;
1025		}
1026		else {
1027			if(len date < 13)
1028				break parse;
1029			time.year = get2(date, i);
1030			if(time.year-19 < 0)
1031				break parse;
1032			time.year = (time.year - 19)*100;
1033			i += 2;
1034			time.year += get2(date, i);
1035			i += 2;
1036		}
1037		time.mon = get2(date, i) - 1;
1038		if(time.mon < 0 || time.mon > 11)
1039			break parse;
1040		i += 2;
1041		time.mday = get2(date, i);
1042		if(time.mday < 1 || time.mday > 31)
1043			break parse;
1044		i += 2;
1045		time.hour = get2(date, i);
1046		if(time.hour < 0 || time.hour > 23)
1047			break parse;
1048		i += 2;
1049		time.min = get2(date, i);
1050		if(time.min < 0 || time.min > 59)
1051			break parse;
1052		i += 2;
1053		if(int date[i] >= '0' && int date[i] <= '9') {
1054			if(len date < i+3)
1055            			break parse;
1056			time.sec = get2(date, i);
1057			if(time.sec < 0 || time.sec > 59)
1058				break parse;
1059			i += 2;
1060			if(format == GeneralizedTime) {
1061				if((len date < i+3) || int date[i++] != '.')
1062					break parse;
1063				# ignore rest
1064				ig := int date[i];
1065				while(ig >= '0' && ig <= '9' && i++ < len date) {
1066					ig = int date[i];
1067				}
1068			}
1069		}
1070		else {
1071			time.sec = 0;
1072		}
1073		zf := int date[i];
1074		if(zf != 'Z' && zf != '+' && zf != '-')
1075			break parse;
1076		if(zf == 'Z') {
1077			if(len date != i+1)
1078				break parse;
1079			time.tzoff = 0;
1080		}
1081		else {
1082			if(len date < i + 3)
1083				break parse;
1084			time.tzoff = get2(date, i+1);
1085			if(time.tzoff < 0 || time.tzoff > 23)
1086				break parse;
1087			i += 2;
1088			min := get2(date, i);
1089			if(min < 0 || min > 59)
1090				break parse;
1091			i += 2;
1092			sec := 0;
1093			if(i != len date) {
1094				if(format == UTCTime || len date < i+4)
1095					break parse;
1096				sec = get2(date, i);
1097				i += 2;
1098				# ignore the rest
1099			}
1100			time.tzoff = (time.tzoff*60 + min)*60 + sec;
1101			if(zf == '-')
1102				time.tzoff = -time.tzoff;
1103		}
1104		return daytime->tm2epoch(time);
1105	}
1106	if(X509_DEBUG)
1107		log("decode_time: syntax error: " +
1108		sys->sprint("year=%d mon=%d mday=%d hour=%d min=%d, sec=%d",
1109		time.year, time.mon, time.mday, time.hour, time.min, time.sec));
1110	return -1;
1111}
1112
1113# [private]
1114# pack as UTC time
1115
1116pack_validity(v: ref Validity): ref Elem
1117{
1118	el: list of ref Elem;
1119	el = ref Elem(
1120			Tag(Universal, UTCTime, 0),
1121			ref Value.String(pack_time(v.not_before, UTCTime))
1122		) :: nil;
1123	el = ref Elem(
1124			Tag(Universal, UTCTime, 0),
1125			ref Value.String(pack_time(v.not_after, UTCTime))
1126		) :: el;
1127	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
1128}
1129
1130# [private]
1131# Format must be either UTCTime or GeneralizedTime
1132# TODO: convert to coordinate time
1133
1134pack_time(t: int, format: int): string
1135{
1136	date := array [32] of byte;
1137	tm := daytime->gmt(t);
1138
1139	i := 0;
1140	if(format == UTCTime) {
1141		i = put2(date, tm.year, i);
1142	}
1143	else { # GeneralizedTime
1144		i = put2(date, 19 + tm.year/100, i);
1145		i = put2(date, tm.year%100, i);
1146	}
1147	i = put2(date, tm.mon, i);
1148	i = put2(date, tm.mday, i);
1149	i = put2(date, tm.hour, i);
1150	i = put2(date, tm.min, i);
1151	if(tm.sec != 0) {
1152		if(format == UTCTime)
1153			i = put2(date, tm.sec, i);
1154		else {
1155			i = put2(date, tm.sec, i);
1156			date[i++] = byte '.';
1157			date[i++] = byte 0;
1158		}
1159	}
1160	if(tm.tzoff == 0) {
1161		date[i++] = byte 'Z';
1162	}
1163	else {
1164		off := tm.tzoff;
1165		if(tm.tzoff < 0) {
1166			off = -off;
1167			date[i++] = byte '-';
1168		}
1169		else {
1170			date[i++] = byte '+';
1171		}
1172		hoff := int (off/3600);
1173		moff := int ((off%3600)/60);
1174		soff := int ((off%3600)%60);
1175		i = put2(date, hoff, i);
1176		i = put2(date, moff, i);
1177		if(soff) {
1178			if(format == UTCTime)
1179				i = put2(date, soff, i);
1180			else {
1181				i = put2(date, soff, i);
1182				date[i++] = byte '.';
1183				date[i++] = byte 0;
1184			}
1185		}
1186	}
1187	return string date[0:i];
1188}
1189
1190# [private]
1191
1192parse_pkinfo(e: ref Elem): (int, ref SubjectPKInfo)
1193{
1194parse:
1195	for(;;) {
1196		p := ref SubjectPKInfo;
1197		(ok, el) := e.is_seq();
1198		if(!ok || len el != 2)
1199			break parse;
1200		(ok, p.alg_id) = parse_alg(hd el);
1201		if(!ok)
1202			break parse;
1203		unused: int;
1204		(ok, unused, p.subject_pk) = (hd tl el).is_bitstring();
1205		if(!ok || unused != 0)
1206			break parse;
1207		return (1, p);
1208	}
1209	if(X509_DEBUG)
1210		log("parse_pkinfo: syntax error");
1211	return (0, nil);
1212}
1213
1214# [private]
1215
1216pack_pkinfo(p: ref SubjectPKInfo): ref Elem
1217{
1218	el: list of ref Elem;
1219	# SEQUENCE order is important
1220	el = ref Elem(
1221			Tag(Universal, BIT_STRING, 0),
1222			ref Value.BitString(0, p.subject_pk) # 0 bits unused ?
1223		) :: nil;
1224	el = pack_alg(p.alg_id) :: el;
1225	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
1226}
1227
1228# [private]
1229
1230parse_uid(e: ref Elem, num: int): (int, array of byte)
1231{
1232	ok, unused : int;
1233	uid : array of byte;
1234	e2 : ref Elem;
1235parse:
1236	for(;;) {
1237		(ok, e2) = is_context(e, num);
1238		if (!ok)
1239			break parse;
1240		e = e2;
1241
1242		(ok, unused, uid) = e.is_bitstring();
1243#		if(!ok || unused != 0)
1244		if(!ok)
1245			break parse;
1246		return (1, uid);
1247	}
1248	if(X509_DEBUG)
1249		log("parse_uid: syntax error");
1250	return (0, nil);
1251}
1252
1253# [private]
1254
1255pack_uid(u: array of byte): ref Elem
1256{
1257	return ref Elem(Tag(Universal, ASN1->BIT_STRING, 0), ref Value.BitString(0,u));
1258}
1259
1260# [private]
1261
1262parse_extlist(e: ref Elem): (int, list of ref Extension)
1263{
1264parse:
1265	# dummy loop for breaking out of
1266	for(;;) {
1267		l: list of ref Extension;
1268		(ok, el) := e.is_seq();
1269		if(!ok)
1270			break parse;
1271		while(el != nil) {
1272			ext := ref Extension;
1273			(ok, ext) = parse_extension(hd el);
1274			if(!ok)
1275				break parse;
1276			l = ext :: l;
1277			el = tl el;
1278		}
1279		# sort to order
1280		nl: list of ref Extension;
1281		while(l != nil) {
1282			nl = (hd l) :: nl;
1283			l = tl l;
1284		}
1285		return (1, nl);
1286	}
1287	if(X509_DEBUG)
1288		log("parse_extlist: syntax error");
1289	return (0, nil);
1290}
1291
1292# [private]
1293
1294pack_extlist(e: list of ref Extension): ref Elem
1295{
1296	el: list of ref Elem;
1297	exts := e;
1298	while(exts != nil) {
1299		ext := pack_extension(hd exts);
1300		if(ext == nil)
1301			return nil;
1302		el = ext :: el;
1303		exts = tl exts;
1304	}
1305	# reverse order
1306	l: list of ref Elem;
1307	while(el != nil) {
1308		l = (hd el) :: l;
1309		el = tl el;
1310	}
1311	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(l));
1312}
1313
1314# [private]
1315# Require further parse to check oid if critical is set to TRUE (see parse_exts)
1316
1317parse_extension(e: ref Elem): (int, ref Extension)
1318{
1319parse:
1320	for(;;) {
1321		ext := ref Extension;
1322		(ok, el) := e.is_seq();
1323		if(!ok)
1324			break parse;
1325		oid: ref Oid;
1326		(ok, oid) = (hd el).is_oid();
1327		if(!ok)
1328			break parse;
1329		ext.oid = oid;
1330		el = tl el;
1331		# BOOLEAN DEFAULT FALSE
1332		(ok, ext.critical) = (hd el).is_int();
1333		if(ok)
1334			el = tl el;
1335		else
1336			ext.critical = 0;
1337		if (len el != 1) {
1338			break parse;
1339		}
1340		(ok, ext.value) = (hd el).is_octetstring();
1341		if(!ok)
1342			break parse;
1343		return (1, ext);
1344	}
1345	if(X509_DEBUG)
1346		log("parse_extension: syntax error");
1347	return (0, nil);
1348}
1349
1350# [private]
1351
1352pack_extension(e: ref Extension): ref Elem
1353{
1354	el: list of ref Elem;
1355
1356	if(e.oid == nil || (e.critical !=0 && e.critical != 1) || e.value == nil)
1357		return nil;
1358	# SEQUENCE order
1359	el = ref Elem(Tag(Universal, OCTET_STRING, 0), ref Value.Octets(e.value)) :: el;
1360	el = ref Elem(Tag(Universal, BOOLEAN, 0), ref Value.Bool(e.critical)) :: el;
1361	el = ref Elem(Tag(Universal, OBJECT_ID, 0), ref Value.ObjId(e.oid)) :: el;
1362	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
1363}
1364
1365# [public]
1366
1367AlgIdentifier.tostring(a: self ref AlgIdentifier): string
1368{
1369	return "\n\t\toid: " + a.oid.tostring() + "\n\t\twith parameter: "+ bastr(a.parameter);
1370}
1371
1372# [public]
1373
1374Name.equal(a: self ref Name, b: ref Name): int
1375{
1376	rda := a.rd_names;
1377	rdb := b.rd_names;
1378	if(len rda != len rdb)
1379		return 0;
1380	while(rda != nil && rdb != nil) {
1381		ok := (hd rda).equal(hd rdb);
1382		if(!ok)
1383			return 0;
1384		rda = tl rda;
1385		rdb = tl rdb;
1386	}
1387
1388	return 1;
1389}
1390
1391# [public]
1392# The sequence of RelativeDistinguishedName's gives a sort of pathname, from most general to
1393# most specific.  Each element of the path can be one or more (but usually just one)
1394# attribute-value pair, such as countryName="US". We'll just form a "postal-style" address
1395# string by concatenating the elements from most specific to least specific, separated by commas.
1396
1397Name.tostring(a: self ref Name): string
1398{
1399	path: string;
1400	rdn := a.rd_names;
1401	while(rdn != nil) {
1402		path += (hd rdn).tostring();
1403		rdn = tl rdn;
1404		if(rdn != nil)
1405			path += ",";
1406	}
1407	return path;
1408}
1409
1410# [public]
1411# The allocation of distinguished names is the responsibility of the Naming Authorities.
1412# Each user shall therefore trust the Naming Authorities not to issue duplicate distinguished
1413# names. The comparison shall be unique one to one match but may not in the same order.
1414
1415RDName.equal(a: self ref RDName, b: ref RDName): int
1416{
1417	if(len a.avas != len b.avas)
1418		return 0;
1419	aa := a.avas;
1420	ba := b.avas;
1421	while(aa != nil) {
1422		found:= 0;
1423		rest: list of ref AVA;
1424		while(ba != nil) {
1425			ok := (hd ba).equal(hd ba);
1426			if(!ok)
1427				rest = (hd aa) :: rest;
1428			else {
1429				if(found)
1430					return 0;
1431				found = 1;
1432			}
1433			ba = tl ba;
1434		}
1435		if(found == 0)
1436			return 0;
1437		ba = rest;
1438		aa = tl aa;
1439	}
1440	return 1;
1441}
1442
1443# [public]
1444
1445RDName.tostring(a: self ref RDName): string
1446{
1447	s: string;
1448	avas := a.avas;
1449	while(avas != nil) {
1450		s += (hd avas).tostring();
1451		avas = tl avas;
1452		if(avas != nil)
1453			s += "-";
1454	}
1455	return s;
1456}
1457
1458# [public]
1459# AVA are equal if they have the same type oid and value
1460
1461AVA.equal(a: self ref AVA, b: ref AVA): int
1462{
1463	# TODO: need to match different encoding (T61String vs. IA5String)
1464	if(a.value != b.value)
1465		return 0;
1466
1467	return oid_cmp(a.oid, b.oid);
1468}
1469
1470# [public]
1471
1472AVA.tostring(a: self ref AVA): string
1473{
1474	return a.value;
1475}
1476
1477# [public]
1478
1479Validity.tostring(v: self ref Validity, format: string): string
1480{
1481	s: string;
1482	if(format == "local") {
1483		s = "\n\t\tnot_before[local]: ";
1484	 	s += daytime->text(daytime->local(v.not_before));
1485		s += "\n\t\tnot_after[local]: ";
1486		s += daytime->text(daytime->local(v.not_after));
1487	}
1488	else if(format == "gmt") {
1489		s = "\n\t\tnot_before[gmt]: ";
1490	 	s += daytime->text(daytime->gmt(v.not_before));
1491		s += "\n\t\tnot_after[gmt]: ";
1492		s += daytime->text(daytime->gmt(v.not_after));
1493	}
1494	else
1495		s += "unknown format: " + format;
1496	return s;
1497}
1498
1499# [public]
1500
1501SubjectPKInfo.getPublicKey(pkinfo: self ref SubjectPKInfo): (string, int, ref PublicKey)
1502{
1503parse:
1504	for(;;) {
1505		pk: ref PublicKey;
1506		id := asn1->oid_lookup(pkinfo.alg_id.oid, pkcs->objIdTab);
1507		case id {
1508		PKCS->id_pkcs_rsaEncryption or
1509		PKCS->id_pkcs_md2WithRSAEncryption or
1510		PKCS->id_pkcs_md4WithRSAEncryption or
1511		PKCS->id_pkcs_md5WithRSAEncryption =>
1512			(err, k) := pkcs->decode_rsapubkey(pkinfo.subject_pk);
1513			if(err != nil)
1514				break parse;
1515			pk = ref PublicKey.RSA(k);
1516		PKCS->id_algorithm_shaWithDSS =>
1517			(err, k) :=  pkcs->decode_dsspubkey(pkinfo.subject_pk);
1518			if(err != nil)
1519				break parse;
1520			pk = ref PublicKey.DSS(k);
1521		PKCS->id_pkcs_dhKeyAgreement =>
1522			(err, k) := pkcs->decode_dhpubkey(pkinfo.subject_pk);
1523			if(err != nil)
1524				break parse;
1525			pk = ref PublicKey.DH(k);
1526		* =>
1527			break parse;
1528		}
1529		return ("", id, pk);
1530	}
1531	return ("subject public key: syntax error", -1, nil);
1532}
1533
1534# [public]
1535
1536SubjectPKInfo.tostring(pkinfo: self ref SubjectPKInfo): string
1537{
1538	s := pkinfo.alg_id.tostring();
1539	s += "\n\t\tencoded key: " + bastr(pkinfo.subject_pk);
1540	return s;
1541}
1542
1543# [public]
1544
1545Extension.tostring(e: self ref Extension): string
1546{
1547	s := "oid: " + e.oid.tostring();
1548	s += "critical: ";
1549	if(e.critical)
1550		s += "true ";
1551	else
1552		s += "false ";
1553	s += bastr(e.value);
1554	return s;
1555}
1556
1557## Certificate PATH
1558## A list of certificates needed to allow a particular user to obtain
1559## the public key of another, is known as a certificate path. A
1560## certificate path logically forms an unbroken chain of trusted
1561## points in the DIT between two users wishing to authenticate.
1562## To establish a certification path between user A and user B using
1563## the Directory without any prior information, each CA may store
1564## one certificate and one reverse certificate designated as
1565## corresponding to its superior CA.
1566
1567# The ASN.1 data byte definitions for certificates and a certificate
1568# path is
1569#
1570# Certificates	::= SEQUENCE {
1571#	userCertificate		Certificate,
1572#	certificationPath	ForwardCertificationPath OPTIONAL }
1573#
1574# ForwardCertificationPath ::= SEQUENCE OF CrossCertificates
1575# CrossCertificates ::=	SET OF Certificate
1576#
1577
1578# [public]
1579# Verify a decoded certificate chain in order of root to user. This is useful for
1580# non_ASN.1 encoding of certificates, e.g. in SSL. Return (0, error string) if
1581# verification failure or (1, "") if verification ok
1582
1583verify_certchain(cs: list of array of byte): (int, string)
1584{
1585	lsc: list of (ref Signed, ref Certificate);
1586
1587	l := cs;
1588	while(l != nil) {
1589		(err, s) := Signed.decode(hd l);
1590		if(err != "")
1591			return (0, err);
1592		c: ref Certificate;
1593		(err, c) = Certificate.decode(s.tobe_signed);
1594		if(err != "")
1595			return (0, err);
1596		lsc = (s, c) :: lsc;
1597		l = tl l;
1598	}
1599	# reverse order
1600	a: list of (ref Signed, ref Certificate);
1601	while(lsc != nil) {
1602		a = (hd lsc) :: a;
1603		lsc = tl lsc;
1604	}
1605	return verify_certpath(a);
1606}
1607
1608# [private]
1609# along certificate path; first certificate is root
1610
1611verify_certpath(sc: list of (ref Signed, ref Certificate)): (int, string)
1612{
1613	# verify self-signed root certificate
1614	(s, c) := hd sc;
1615	# TODO: check root RDName with known CAs and using
1616	# external verification of root - Directory service
1617	(err, id, pk) := c.subject_pkinfo.getPublicKey();
1618	if(err != "")
1619		return (0, err);
1620	if(!is_validtime(c.validity)
1621		|| !c.issuer.equal(c.subject)
1622		|| !s.verify(pk, 0)) # TODO: prototype verify(key, ref AlgIdentifier)?
1623		return (0, "verification failure");
1624
1625	sc = tl sc;
1626	while(sc != nil) {
1627		(ns, nc) := hd sc;
1628		# TODO: check critical flags of extension list
1629		# check alt names field
1630		(err, id, pk) = c.subject_pkinfo.getPublicKey();
1631		if(err != "")
1632			return (0, err);
1633		if(!is_validtime(nc.validity)
1634			|| !nc.issuer.equal(c.subject)
1635			|| !ns.verify(pk, 0)) # TODO: move prototype as ?
1636			return (0, "verification failure");
1637		(s, c) = (ns, nc);
1638		sc = tl sc;
1639	}
1640
1641	return (1, "");
1642}
1643
1644# [public]
1645is_validtime(validity: ref Validity): int
1646{
1647	# a little more expensive but more accurate
1648	now := daytime->now();
1649
1650	# need some conversion here
1651	if(now < validity.not_before || now > validity.not_after)
1652		return 0;
1653
1654	return 1;
1655}
1656
1657is_validpair(): int
1658{
1659	return 0;
1660}
1661
1662## Certificate Revocation List (CRL)
1663##
1664## A CRL is a time-stampted list identifying revoked certificates. It is signed by a
1665## Certificate Authority (CA) and made freely available in a public repository.
1666##
1667## Each revoked certificate is identified in a CRL by its certificate serial number.
1668## When a certificate-using system uses a certificate (e.g., for verifying a remote
1669## user's digital signature), that system not only checks the certificate signature
1670## and validity but also acquires a suitably-recent CRL and checks that the certificate
1671## serial number is not on that CRL. The meaning of "suitably-recent" may vary with
1672## local policy, but it usually means the most recently-issued CRL. A CA issues a new
1673## CRL on a regular periodic basis (e.g., hourly, daily, or weekly). Entries are added
1674## on CRLs as revocations occur, and an entry may be removed when the certificate
1675## expiration date is reached.
1676
1677# [public]
1678
1679CRL.decode(a: array of byte): (string, ref CRL)
1680{
1681parse:
1682	# break on error
1683	for(;;) {
1684		(err, all) := asn1->decode(a);
1685		if(err != "")
1686			break parse;
1687		c := ref CRL;
1688		# CRL must be a ASN1 sequence
1689		(ok, el) := all.is_seq();
1690		if(!ok || len el < 3)
1691			break parse;
1692		c.version = 1; # set to default (v2)
1693		(ok, c.version) = parse_version(hd el);
1694		if(!ok)
1695			break parse;
1696		if(c.version < 0) {
1697			el = tl el;
1698			if(len el < 4)
1699				break parse;
1700		}
1701		# signature algorithm
1702		(ok, c.sig) = parse_alg(hd el);
1703		if(!ok)
1704			break parse;
1705		el = tl el;
1706		# issuer: who issues the CRL
1707		(ok, c.issuer) = parse_name(hd el);
1708		if(!ok)
1709			break parse;
1710		el = tl el;
1711		# this update
1712		(ok, c.this_update) = parse_time(hd el, UTCTime);
1713		if(!ok)
1714			break parse;
1715		el = tl el;
1716		# OPTIONAL, must be in order
1717		# next_update
1718		if(el != nil) {
1719			(ok, c.next_update) = parse_time(hd el, UTCTime);
1720			if(!ok)
1721				break parse;
1722			el = tl el;
1723		}
1724		# revoked certificates
1725		if(el != nil) {
1726			(ok, c.revoked_certs) = parse_revoked_certs(hd el);
1727			if(!ok)
1728				break parse;
1729			el = tl el;
1730		}
1731		# extensions
1732		if(el != nil) {
1733			(ok, c.exts) = parse_extlist(hd el);
1734			if(!ok)
1735				break parse;
1736			el = tl el;
1737		}
1738		# must be no more left
1739		if(el != nil)
1740			break parse;
1741		return ("", c);
1742	}
1743	return ("CRL: syntax error", nil);
1744}
1745
1746# [public]
1747
1748CRL.encode(c: self ref CRL): (string, array of byte)
1749{
1750pack:
1751	for(;;) {
1752		el: list of ref Elem;
1753		# always has a version packed
1754		e_version := pack_version(c.version);
1755		if(e_version == nil)
1756			break pack;
1757		el = e_version :: el;
1758		# algorithm
1759		e_sig := pack_alg(c.sig);
1760		if(e_sig == nil)
1761			break pack;
1762		el = e_sig :: el;
1763		# crl issuer
1764		e_issuer := pack_name(c.issuer);
1765		if(e_issuer == nil)
1766			break pack;
1767		el = e_issuer :: el;
1768		# validity
1769		e_this_update := pack_time(c.this_update, UTCTime);
1770		if(e_this_update == nil)
1771			break pack;
1772		el = ref Elem(
1773			Tag(Universal, ASN1->UTCTime, 0),
1774			ref Value.String(e_this_update)
1775			) :: el;
1776		# next crl update
1777		if(c.next_update != 0) {
1778			e_next_update := pack_time(c.next_update, UTCTime);
1779			if(e_next_update == nil)
1780				break pack;
1781			el = ref Elem(
1782				Tag(Universal, ASN1->UTCTime, 0),
1783				ref Value.String(e_next_update)
1784				) :: el;
1785		}
1786		# revoked certificates
1787		if(c.revoked_certs != nil) {
1788			e_revoked_certs := pack_revoked_certs(c.revoked_certs);
1789			if(e_revoked_certs == nil)
1790				break pack;
1791			el = e_revoked_certs :: el;
1792		}
1793		# crl extensions
1794		if(c.exts != nil) {
1795			e_exts := pack_extlist(c.exts);
1796			if(e_exts == nil)
1797				break pack;
1798			el = e_exts :: el;
1799		}
1800		# compose all elements
1801		lseq: list of ref Elem;
1802		while(el != nil) {
1803			lseq = (hd el) :: lseq;
1804			el = tl el;
1805		}
1806		all := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(lseq));
1807		(err, ret) := asn1->encode(all);
1808		if(err != "")
1809			break;
1810		return ("", ret);
1811	}
1812	return ("incompleted CRL; unable to pack", nil);
1813}
1814
1815# [public]
1816
1817CRL.tostring(c: self ref CRL): string
1818{
1819	s := "Certificate Revocation List (CRL)";
1820	s += "\nVersion: " + string c.version;
1821	s += "\nSignature: " + c.sig.tostring();
1822	s += "\nIssuer: " + c.issuer.tostring();
1823	s += "\nThis Update: " + daytime->text(daytime->local(c.this_update));
1824	s += "\nNext Update: " + daytime->text(daytime->local(c.next_update));
1825	s += "\nRevoked Certificates: ";
1826	rcs := c.revoked_certs;
1827	while(rcs != nil) {
1828		s += "\t" + (hd rcs).tostring();
1829		rcs = tl rcs;
1830	}
1831	s += "\nExtensions: ";
1832	exts := c.exts;
1833	while(exts != nil) {
1834		s += "\t" + (hd exts).tostring();
1835		exts = tl exts;
1836	}
1837	return s;
1838}
1839
1840# [public]
1841
1842CRL.is_revoked(c: self ref CRL, sn: ref IPint): int
1843{
1844	es := c.revoked_certs;
1845	while(es != nil) {
1846		if(sn.eq((hd es).user_cert))
1847			return 1;
1848		es = tl es;
1849	}
1850	return 0;
1851}
1852
1853# [public]
1854
1855RevokedCert.tostring(rc: self ref RevokedCert): string
1856{
1857	s := "Revoked Certificate";
1858	if(rc.user_cert == nil)
1859		return s + " [Bad Format]\n";
1860	s += "\nSerial Number: " + rc.user_cert.iptostr(10);
1861	if(rc.revoc_date != 0)
1862		s += "\nRevocation Date: " + daytime->text(daytime->local(rc.revoc_date));
1863	if(rc.exts != nil) {
1864		exts := rc.exts;
1865		while(exts != nil) {
1866			s += "\t" + (hd exts).tostring();
1867			exts = tl exts;
1868		}
1869	}
1870	return s;
1871}
1872
1873
1874# [private]
1875
1876parse_revoked_certs(e: ref Elem): (int, list of ref RevokedCert)
1877{
1878	lc: list of ref RevokedCert;
1879parse:
1880	for(;;) {
1881		(ok, el) := e.is_seq();
1882		if(!ok)
1883			break parse;
1884		while(el != nil) {
1885			c: ref RevokedCert;
1886			(ok, c) = parse_revoked(hd el);
1887			if(!ok)
1888				break parse;
1889			lc = c :: lc;
1890			el = tl el;
1891		}
1892
1893		return (1, lc);
1894	}
1895
1896	return (0, nil);
1897}
1898
1899# [private]
1900
1901pack_revoked_certs(r: list of ref RevokedCert): ref Elem
1902{
1903	el: list of ref Elem;
1904
1905	rs := r;
1906	while(rs != nil) {
1907		rc := pack_revoked(hd rs);
1908		if(rc == nil)
1909			return nil;
1910		el = rc :: el;
1911		rs = tl rs;
1912	}
1913	# reverse order
1914	l: list of ref Elem;
1915	while(el != nil) {
1916		l = (hd el) :: l;
1917		el = tl el;
1918	}
1919	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(l));
1920
1921}
1922
1923# [private]
1924
1925parse_revoked(e: ref Elem): (int, ref RevokedCert)
1926{
1927parse:
1928	for(;;) {
1929		c: ref RevokedCert;
1930		(ok, el) := e.is_seq();
1931		if(!ok || len el < 2)
1932			break parse;
1933		uc: array of byte;
1934		(ok, uc) = (hd el).is_bigint();
1935		if(!ok)
1936			break parse;
1937		c.user_cert = IPint.bebytestoip(uc);
1938		el = tl el;
1939		(ok, c.revoc_date) = parse_time(hd el, UTCTime);
1940		if(!ok)
1941			break parse;
1942		el = tl el;
1943		if(el != nil) {
1944			(ok, c.exts) = parse_extlist(hd el);
1945			if(!ok)
1946				break parse;
1947		}
1948		return (1, c);
1949	}
1950	return (0, nil);
1951}
1952
1953# [private]
1954
1955pack_revoked(r: ref RevokedCert): ref Elem
1956{
1957	el: list of ref Elem;
1958	if(r.exts != nil) {
1959		e_exts := pack_extlist(r.exts);
1960		if(e_exts == nil)
1961			return nil;
1962		el = e_exts :: el;
1963	}
1964	if(r.revoc_date != 0) {
1965		e_date := pack_time(r.revoc_date, UTCTime);
1966		if(e_date == nil)
1967			return nil;
1968		el = ref Elem(
1969				Tag(Universal, ASN1->UTCTime, 0),
1970				ref Value.String(e_date)
1971			) :: el;
1972	}
1973	if(r.user_cert == nil)
1974		return nil;
1975	el = ref Elem(Tag(Universal, INTEGER, 0),
1976			ref Value.BigInt(r.user_cert.iptobebytes())
1977		) :: el;
1978	return ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
1979}
1980
1981## The extensions field allows addition of new fields to the structure
1982## without modification to the ASN.1 definition. An extension field
1983## consists of an extension identifier, a criticality flag, and a
1984## canonical encoding of a data value of an ASN.1 type associated with
1985## the identified extension. For those extensions where ordering of
1986## individual extensions within the SEQUENCE is significant, the
1987## specification of those individual extensions shall include the rules
1988## for the significance of the ordering. When an implementation
1989## processing a certificate does not recognize an extension, if the
1990## criticality flag is FALSE, it may ignore that extension. If the
1991## criticality flag is TRUE, unrecognized extensions shall cause the
1992## structure to be considered invalid, i.e. in a certificate, an
1993## unrecognized critical extension would cause validation of a signature
1994## using that certificate to fail.
1995
1996# [public]
1997
1998cr_exts(es: list of ref Extension): list of ref Extension
1999{
2000	cr: list of ref Extension;
2001	l := es;
2002	while(l != nil) {
2003		e := hd l;
2004		if(e.critical == 1)
2005			cr = e :: cr;
2006		l = tl l;
2007	}
2008	return cr;
2009}
2010
2011# [public]
2012
2013noncr_exts(es: list of ref Extension): list of ref Extension
2014{
2015	ncr: list of ref Extension;
2016	l := es;
2017	while(l != nil) {
2018		e := hd l;
2019		if(e.critical == 0)
2020			ncr = e :: ncr;
2021		l = tl l;
2022	}
2023	return ncr;
2024}
2025
2026# [public]
2027
2028parse_exts(exts: list of ref Extension): (string, list of ref ExtClass)
2029{
2030	ets: list of ref ExtClass;
2031	l := exts;
2032	while(l != nil) {
2033		ext := hd l;
2034		(err, et) := ExtClass.decode(ext);
2035		if(err != "")
2036			return (err, nil);
2037		ets = et :: ets;
2038		l = tl l;
2039	}
2040	lseq: list of ref ExtClass;
2041	while(ets != nil) {
2042		lseq = (hd ets) :: lseq;
2043		ets = tl ets;
2044	}
2045	return ("", lseq);
2046}
2047
2048# [public]
2049
2050ExtClass.decode(ext: ref Extension): (string, ref ExtClass)
2051{
2052	err: string;
2053	eclass: ref ExtClass;
2054
2055	oid := asn1->oid_lookup(ext.oid, objIdTab);
2056	case oid {
2057	id_ce_authorityKeyIdentifier =>
2058		(err, eclass) = decode_authorityKeyIdentifier(ext);
2059		if(err == "" && ext.critical == 1) {
2060			err = "authority key identifier: should be non-critical";
2061			break;
2062		}
2063	id_ce_subjectKeyIdentifier =>
2064		(err, eclass) = decode_subjectKeyIdentifier(ext);
2065		if(err != "" && ext.critical != 0) {
2066			err = "subject key identifier: should be non-critical";
2067			break;
2068		}
2069	id_ce_basicConstraints =>
2070		(err, eclass) = decode_basicConstraints(ext);
2071		if(err == "" && ext.critical != 1) {
2072			err = "basic constraints: should be critical";
2073			break;
2074		}
2075	id_ce_keyUsage =>
2076		(err, eclass) = decode_keyUsage(ext);
2077		if(err == "" && ext.critical != 1) {
2078			err = "key usage: should be critical";
2079			break;
2080		}
2081	id_ce_privateKeyUsage =>
2082		(err, eclass) = decode_privateKeyUsage(ext);
2083		if(err == "" && ext.critical != 0) {
2084			err = "private key usage: should be non-critical";
2085			break;
2086		}
2087	id_ce_policyMapping =>
2088		(err, eclass) = decode_policyMapping(ext);
2089		if(err == "" && ext.critical != 0) {
2090			err = "policy mapping: should be non-critical";
2091			break;
2092		}
2093	id_ce_certificatePolicies =>
2094		(err, eclass) = decode_certificatePolicies(ext);
2095		# either critical or non-critical
2096	id_ce_issuerAltName =>
2097		n: list of ref GeneralName;
2098		(err, n) = decode_alias(ext);
2099		if(err == "")
2100			eclass = ref ExtClass.IssuerAltName(n);
2101		# either critical or non-critical
2102	id_ce_subjectAltName =>
2103		n: list of ref GeneralName;
2104		(err, n) = decode_alias(ext);
2105		if(err == "")
2106			eclass = ref ExtClass.SubjectAltName(n);
2107		# either critical or non-critical
2108	id_ce_nameConstraints =>
2109		(err, eclass) = decode_nameConstraints(ext);
2110		# either critical or non-critical
2111	id_ce_policyConstraints =>
2112		(err, eclass) = decode_policyConstraints(ext);
2113		# either critical or non-critical
2114	id_ce_cRLNumber =>
2115		(err, eclass) = decode_cRLNumber(ext);
2116		if(err == "" && ext.critical != 0) {
2117			err = "crl number: should be non-critical";
2118			break;
2119		}
2120	id_ce_reasonCode =>
2121		(err, eclass) = decode_reasonCode(ext);
2122		if(err == "" && ext.critical != 0) {
2123			err = "crl reason: should be non-critical";
2124			break;
2125		}
2126	id_ce_instructionCode =>
2127		(err, eclass) = decode_instructionCode(ext);
2128		if(err == "" && ext.critical != 0) {
2129			err = "instruction code: should be non-critical";
2130			break;
2131		}
2132	id_ce_invalidityDate =>
2133		(err, eclass) = decode_invalidityDate(ext);
2134		if(err == "" && ext.critical != 0) {
2135			err = "invalidity date: should be non-critical";
2136			break;
2137		}
2138	id_ce_issuingDistributionPoint =>
2139		(err, eclass) = decode_issuingDistributionPoint(ext);
2140		if(err == "" && ext.critical != 1) {
2141			err = "issuing distribution point: should be critical";
2142			break;
2143		}
2144	id_ce_cRLDistributionPoint =>
2145		(err, eclass) = decode_cRLDistributionPoint(ext);
2146		# either critical or non-critical
2147	id_ce_certificateIssuer =>
2148		(err, eclass) = decode_certificateIssuer(ext);
2149		if(err == "" && ext.critical != 1) {
2150			err = "certificate issuer: should be critical";
2151			break;
2152		}
2153	id_ce_deltaCRLIndicator =>
2154		(err, eclass) = decode_deltaCRLIndicator(ext);
2155		if(err == "" && ext.critical != 1) {
2156			err = "delta crl indicator: should be critical";
2157			break;
2158		}
2159	id_ce_subjectDirectoryAttributes =>
2160		(err, eclass) = decode_subjectDirectoryAttributes(ext);
2161		if(ext.critical != 0) {
2162			err = "subject directory attributes should be non-critical";
2163			break;
2164		}
2165	* =>
2166		err = "unknown extension class";
2167	}
2168
2169	return (err, eclass);
2170}
2171
2172# [public]
2173
2174ExtClass.encode(ec: self ref ExtClass, critical: int): ref Extension
2175{
2176	ext: ref Extension;
2177
2178	if(critical)
2179		;	# unused
2180	pick c := ec {
2181	AuthorityKeyIdentifier =>
2182		(err, a) := encode_authorityKeyIdentifier(c);
2183		if(err == "")
2184			ext = ref Extension(ref objIdTab[id_ce_authorityKeyIdentifier], 0, a);
2185	SubjectKeyIdentifier =>
2186		(err, a) := encode_subjectKeyIdentifier(c);
2187		if(err == "")
2188			ext = ref Extension(ref objIdTab[id_ce_subjectKeyIdentifier], 0, a);
2189	BasicConstraints =>
2190		(err, a) := encode_basicConstraints(c);
2191		if(err == "")
2192			ext = ref Extension(ref objIdTab[id_ce_basicConstraints], 0, a);
2193	KeyUsage =>
2194		(err, a) := encode_keyUsage(c);
2195		if(err == "")
2196			ext = ref Extension(ref objIdTab[id_ce_keyUsage], 0, a);
2197	PrivateKeyUsage =>
2198		(err, a) := encode_privateKeyUsage(c);
2199		if(err == "")
2200			ext = ref Extension(ref objIdTab[id_ce_privateKeyUsage],	0, a);
2201	PolicyMapping =>
2202		(err, a) := encode_policyMapping(c);
2203		if(err == "")
2204			ext = ref Extension(ref objIdTab[id_ce_policyMapping], 0, a);
2205	CertificatePolicies =>
2206		(err, a) := encode_certificatePolicies(c);
2207		if(err == "")
2208			ext = ref Extension(ref objIdTab[id_ce_certificatePolicies], 0, a);
2209	IssuerAltName =>
2210		(err, a) := encode_alias(c.alias);
2211		if(err == "")
2212			ext = ref Extension(ref objIdTab[id_ce_issuerAltName], 0, a);
2213	SubjectAltName =>
2214		(err, a) := encode_alias(c.alias);
2215		if(err == "")
2216			ext = ref Extension(ref objIdTab[id_ce_subjectAltName], 0, a);
2217	NameConstraints =>
2218		(err, a) := encode_nameConstraints(c);
2219		if(err == "")
2220			ext = ref Extension(ref objIdTab[id_ce_nameConstraints],	0, a);
2221	PolicyConstraints =>
2222		(err, a) := encode_policyConstraints(c);
2223		if(err == "")
2224			ext = ref Extension(ref objIdTab[id_ce_policyConstraints], 0, a);
2225	CRLNumber =>
2226		(err, a) := encode_cRLNumber(c);
2227		if(err == "")
2228			ext = ref Extension(ref objIdTab[id_ce_cRLNumber], 0, a);
2229	ReasonCode =>
2230		(err, a) := encode_reasonCode(c);
2231		if(err == "")
2232			ext = ref Extension(ref objIdTab[id_ce_reasonCode], 0, a);
2233	InstructionCode =>
2234		(err, a) := encode_instructionCode(c);
2235		if(err == "")
2236			ext = ref Extension(ref objIdTab[id_ce_instructionCode],	0, a);
2237	InvalidityDate =>
2238		(err, a) := encode_invalidityDate(c);
2239		if(err == "")
2240			ext = ref Extension(ref objIdTab[id_ce_invalidityDate], 0, a);
2241	CRLDistributionPoint =>
2242		(err, a) := encode_cRLDistributionPoint(c);
2243		if(err == "")
2244			ext = ref Extension(ref objIdTab[id_ce_cRLDistributionPoint], 0, a);
2245	IssuingDistributionPoint =>
2246		(err, a) := encode_issuingDistributionPoint(c);
2247		if(err == "")
2248			ext = ref Extension(ref objIdTab[id_ce_issuingDistributionPoint], 0, a);
2249	CertificateIssuer =>
2250		(err, a) := encode_certificateIssuer(c);
2251		if(err == "")
2252			ext = ref Extension(ref objIdTab[id_ce_certificateIssuer], 0, a);
2253	DeltaCRLIndicator =>
2254		(err, a) := encode_deltaCRLIndicator(c);
2255		if(err == "")
2256			ext = ref Extension(ref objIdTab[id_ce_deltaCRLIndicator], 0, a);
2257	SubjectDirectoryAttributes =>
2258		(err, a) := encode_subjectDirectoryAttributes(c);
2259		if(err == "")
2260			ext = ref Extension(ref objIdTab[id_ce_subjectDirectoryAttributes], 0, a);
2261	}
2262	return ext;
2263}
2264
2265# [public]
2266
2267ExtClass.tostring(et: self ref ExtClass): string
2268{
2269	s: string;
2270
2271	pick t := et {
2272	AuthorityKeyIdentifier =>
2273		s = "Authority Key Identifier: ";
2274		s += "\n\tid = " + bastr(t.id);
2275		s += "\n\tissuer = " + t.issuer.tostring();
2276		s += "\n\tserial_number = " + bastr(t.serial_number.iptobebytes());
2277	SubjectKeyIdentifier =>
2278		s = "Subject Key Identifier ";
2279		s += "\n\tid = " + bastr(t.id);
2280	BasicConstraints =>
2281		s = "Basic Constraints: ";
2282		s += "\n\tdepth = " + string t.depth;
2283	KeyUsage =>
2284		s = "Key Usage: ";
2285		s += "\n\tusage = ";
2286	PrivateKeyUsage =>
2287		s = "Private Key Usage: ";
2288		s += "\n\tusage = ";
2289	PolicyMapping =>
2290		s = "Policy Mapping: ";
2291		pl := t.pairs;
2292		while(pl != nil) {
2293			(issuer_oid, subject_oid) := hd pl;
2294			s += "\n\t(" + issuer_oid.tostring() + ", " + subject_oid.tostring() + ")";
2295			pl = tl pl;
2296		}
2297	CertificatePolicies =>
2298		s = "Certificate Policies: ";
2299		pl := t.policies;
2300		while(pl != nil) {
2301			s += (hd pl).tostring();
2302			pl = tl pl;
2303		}
2304	IssuerAltName =>
2305		s = "Issuer Alt Name: ";
2306		al := t.alias;
2307		while(al != nil) {
2308			s += (hd al).tostring() + ",";
2309			al = tl al;
2310		}
2311	SubjectAltName =>
2312		s = "Subject Alt Name: ";
2313		al := t.alias;
2314		while(al != nil) {
2315			s += (hd al).tostring() + ",";
2316			al = tl al;
2317		}
2318	NameConstraints =>
2319		s = "Name Constraints: ";
2320		s += "\n\tpermitted = ";
2321		p := t.permitted;
2322		while(p != nil) {
2323			s += (hd p).tostring();
2324			p = tl p;
2325		}
2326		s += "\n\texcluded = ";
2327		e := t.excluded;
2328		while(e != nil) {
2329			s += (hd e).tostring();
2330			e = tl e;
2331		}
2332	PolicyConstraints =>
2333		s = "Policy Constraints: ";
2334		s += "\n\trequire = " + string t.require;
2335		s += "\n\tinhibit = " + string t.inhibit;
2336	CRLNumber =>
2337		s = "CRL Number: ";
2338		s += "\n\tcurrent crl number = " + string t.curr;
2339	ReasonCode =>
2340		s = "Reason Code: ";
2341		s += "\n\tcode = ";
2342	InstructionCode =>
2343		s = "Instruction Code: ";
2344		s += "\n\thold with oid = " + t.oid.tostring();
2345	InvalidityDate =>
2346		s = "Invalidity Date: ";
2347		s += "\n\tdate = " + daytime->text(daytime->local(t.date));
2348	CRLDistributionPoint =>
2349		s = "CRL Distribution Point: ";
2350		ps := t.ps;
2351		while(ps != nil) {
2352			s += (hd ps).tostring() + ",";
2353			ps = tl ps;
2354		}
2355	IssuingDistributionPoint =>
2356		s = "Issuing Distribution Point: ";
2357	CertificateIssuer =>
2358		s = "Certificate Issuer: ";
2359	DeltaCRLIndicator =>
2360		s = "Delta CRL Indicator: ";
2361	SubjectDirectoryAttributes =>
2362		s = "Subject Directory Attributes: ";
2363	* =>
2364		s = "Unknown Extension: ";
2365	}
2366
2367	return s;
2368}
2369
2370# [private]
2371
2372decode_authorityKeyIdentifier(ext: ref Extension): (string, ref ExtClass)
2373{
2374parse:
2375	for(;;) {
2376		(err, all) := asn1->decode(ext.value);
2377		if(err != "")
2378			break parse;
2379		(ok, el) := all.is_seq();
2380		if(!ok)
2381			break parse;
2382		ak := ref ExtClass.AuthorityKeyIdentifier;
2383		e := hd el;
2384		(ok, e) = is_context(e, 0);
2385		if(ok) {
2386			(ok, ak.id) = e.is_octetstring();
2387			if(!ok)
2388				break parse;
2389			el = tl el;
2390		}
2391		if(el != nil && len el != 2)
2392			break parse;
2393		e = hd el;
2394		(ok, e) = is_context(e, 1);
2395		if(!ok)
2396			break parse;
2397		(ok, ak.issuer) = parse_gname(e);
2398		if(!ok)
2399			break parse;
2400		e = hd tl el;
2401		(ok, e) = is_context(e, 2);
2402		if(!ok)
2403			break parse;
2404		(ok, ak.serial_number) = parse_sernum(e);
2405		if(!ok)
2406			break;
2407		return ("", ak);
2408	}
2409	return ("syntax error", nil);
2410}
2411
2412# [private]
2413
2414encode_authorityKeyIdentifier(c: ref ExtClass.AuthorityKeyIdentifier): (string, array of byte)
2415{
2416	el: list of ref Elem;
2417	if(c.serial_number != nil) {
2418		(ok, e) := pack_context(
2419				ref Elem(
2420					Tag(Universal, INTEGER, 0),
2421					ref Value.BigInt(c.serial_number.iptobebytes())
2422				),
2423				2
2424			);
2425		if(!ok)
2426			return ("syntax error", nil);
2427		el = e :: nil;
2428	}
2429	if(c.issuer != nil) {
2430		(ok, e) := pack_gname(c.issuer);
2431		if(!ok)
2432			return ("authority key identifier: encoding error", nil);
2433		(ok, e) = pack_context(e, 1);
2434		if(!ok)
2435			return ("authority key identifier: encoding error", nil);
2436		el = e :: el;
2437	}
2438	if(c.id != nil) {
2439		(ok, e) := pack_context(
2440				ref Elem(
2441					Tag(Universal, OCTET_STRING, 0),
2442					ref Value.Octets(c.id)
2443				),
2444				0
2445			);
2446		if(!ok)
2447			return ("authority key identifier: encoding error", nil);
2448		el = e :: el;
2449	}
2450	return asn1->encode(ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el)));
2451}
2452
2453# [private]
2454
2455decode_subjectKeyIdentifier(ext: ref Extension): (string, ref ExtClass)
2456{
2457parse:
2458	for(;;) {
2459		(err, all) := asn1->decode(ext.value);
2460		if(err != "")
2461			break parse;
2462		(ok, id) := all.is_octetstring();
2463		if(!ok)
2464			break parse;
2465		return ("", ref ExtClass.SubjectKeyIdentifier(id));
2466
2467	}
2468	return ("subject key identifier: syntax error", nil);
2469}
2470
2471# [private]
2472
2473encode_subjectKeyIdentifier(c: ref ExtClass.SubjectKeyIdentifier): (string, array of byte)
2474{
2475	if(c.id == nil)
2476		return ("syntax error", nil);
2477	e := ref Elem(Tag(Universal, OCTET_STRING, 0), ref Value.Octets(c.id));
2478	return asn1->encode(e);
2479}
2480
2481# [private]
2482
2483decode_basicConstraints(ext: ref Extension): (string, ref ExtClass)
2484{
2485parse:
2486	for(;;) {
2487		(err, all) := asn1->decode(ext.value);
2488		if(err != "")
2489			break parse;
2490		(ok, el) := all.is_seq();
2491		if(!ok || len el != 2)
2492			break parse;
2493		ca: int;
2494		(ok, ca) = (hd el).is_int(); # boolean
2495		if(!ok || ca != 1)
2496			break parse;
2497		path: int;
2498		(ok, path) = (hd tl el).is_int(); # integer
2499		if(!ok || path < 0)
2500			break parse;
2501		return ("", ref ExtClass.BasicConstraints(path));
2502	}
2503	return ("basic constraints: syntax error", nil);
2504}
2505
2506# [private]
2507
2508encode_basicConstraints(c: ref ExtClass.BasicConstraints): (string, array of byte)
2509{
2510	el: list of ref Elem;
2511	el = ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(c.depth)) :: nil;
2512	el = ref Elem(Tag(Universal, BOOLEAN, 0), ref Value.Bool(1)) :: el;
2513	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2514	return asn1->encode(e);
2515}
2516
2517# [private]
2518
2519decode_keyUsage(ext: ref Extension): (string, ref ExtClass)
2520{
2521parse:
2522	for(;;) {
2523		# assert bits can fit into a limbo int
2524		if(len ext.value > 4)
2525			break parse;
2526		return ("", ref ExtClass.KeyUsage(b4int(ext.value)));
2527	}
2528	return ("key usage: syntax error", nil);
2529}
2530
2531# [private]
2532
2533encode_keyUsage(c: ref ExtClass.KeyUsage): (string, array of byte)
2534{
2535	return ("", int4b(c.usage));
2536}
2537
2538# [private]
2539
2540decode_privateKeyUsage(ext: ref Extension): (string, ref ExtClass)
2541{
2542parse:
2543	for(;;) {
2544		(err, all) := asn1->decode(ext.value);
2545		if(err != "")
2546			break parse;
2547		(ok, el) := all.is_seq();
2548		if(!ok || len el < 1) # at least one exists
2549			break parse;
2550		v := ref Validity;
2551		e := hd el;
2552		(ok, e) = is_context(e, 0);
2553		if(ok) {
2554			(ok, v.not_before) = parse_time(e, GeneralizedTime);
2555			if(!ok)
2556				break parse;
2557			el = tl el;
2558		}
2559		if(el != nil) {
2560			e = hd el;
2561			(ok, e) = is_context(e, 1);
2562			if(!ok)
2563				break parse;
2564			(ok, v.not_after) = parse_time(e, GeneralizedTime);
2565			if(!ok)
2566				break parse;
2567		}
2568		return ("", ref ExtClass.PrivateKeyUsage(v));
2569	}
2570	return ("private key usage: syntax error", nil);
2571}
2572
2573# [private]
2574
2575encode_privateKeyUsage(c: ref ExtClass.PrivateKeyUsage): (string, array of byte)
2576{
2577	el: list of ref Elem;
2578	e: ref Elem;
2579	ok := 1;
2580	p := c.period;
2581	if(p == nil)
2582		return ("encode private key usage: imcomplete data", nil);
2583	if(p.not_after > 0) {
2584		t := pack_time(p.not_after, GeneralizedTime);
2585		e = ref Elem(Tag(Universal, GeneralizedTime, 0), ref Value.String(t));
2586		(ok, e) = pack_context(e, 1);
2587		if(!ok)
2588			return ("encode private key usage: illegal context", nil);
2589		el = e :: nil;
2590	}
2591	if(p.not_before > 0) {
2592		t := pack_time(p.not_before, GeneralizedTime);
2593		e = ref Elem(Tag(Universal, GeneralizedTime, 0), ref Value.String(t));
2594		(ok, e) = pack_context(e, 0);
2595		if(!ok)
2596			return ("encode private key usage: illegal context", nil);
2597		el = e :: el;
2598	}
2599	e = ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2600	return asn1->encode(e);
2601}
2602
2603# [private]
2604
2605decode_policyMapping(ext: ref Extension): (string, ref ExtClass)
2606{
2607parse:
2608	for(;;) {
2609		(err, all) := asn1->decode(ext.value);
2610		if(err != "")
2611			break parse;
2612		(ok, el) := all.is_seq();
2613		if(!ok)
2614			break parse;
2615		l_pm: list of (ref Oid, ref Oid);
2616		while(el != nil) {
2617			e_pm: list of ref Elem;
2618			(ok, e_pm) = (hd el).is_seq();
2619			if(!ok || len e_pm != 2)
2620				break parse;
2621			idp, sdp: ref Oid;
2622			(ok, idp) = (hd e_pm).is_oid();
2623			if(!ok)
2624				break parse;
2625			(ok, sdp) = (hd tl e_pm).is_oid();
2626			if(!ok)
2627				break parse;
2628			l_pm = (idp, sdp) :: l_pm;
2629		}
2630		# reverse the order
2631		l: list of (ref Oid, ref Oid);
2632		while(l_pm != nil) {
2633			l = (hd l_pm) :: l;
2634			l_pm = tl l_pm;
2635		}
2636		return ("", ref ExtClass.PolicyMapping(l));
2637	}
2638	return ("policy mapping: syntax error", nil);
2639}
2640
2641# [private]
2642
2643encode_policyMapping(c: ref ExtClass.PolicyMapping): (string, array of byte)
2644{
2645	el, pel: list of ref Elem;
2646	if(c.pairs == nil)
2647		return ("policy mapping: incomplete data", nil);
2648	pl := c.pairs;
2649	while(pl != nil) {
2650		(a, b) := hd pl;
2651		if(a == nil || b == nil)
2652			return ("policy mapping: incomplete data", nil);
2653		be := ref Elem(Tag(Universal, OBJECT_ID, 0), ref Value.ObjId(b));
2654		ae := ref Elem(Tag(Universal, OBJECT_ID, 0), ref Value.ObjId(a));
2655		pel = ref Elem(
2656			Tag(Universal, SEQUENCE, 1),
2657			ref Value.Seq(ae::be::nil)
2658		) :: pel;
2659		pl = tl pl;
2660	}
2661	while(pel != nil) {
2662		el = (hd pel) :: el;
2663		pel = tl pel;
2664	}
2665	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2666	return asn1->encode(e);
2667}
2668
2669# [private]
2670
2671decode_certificatePolicies(ext: ref Extension): (string, ref ExtClass)
2672{
2673parse:
2674	for(;;) {
2675		(err, all) := asn1->decode(ext.value);
2676		if(err != "")
2677			break parse;
2678		(ok, el) := all.is_seq();
2679		if(!ok)
2680			break parse;
2681		l_pi: list of ref PolicyInfo;
2682		while(el != nil) {
2683			e_pi: list of ref Elem;
2684			(ok, e_pi) = (hd el).is_seq();
2685			if(!ok || len e_pi > 2 || len e_pi < 1)
2686				break parse;
2687			pi: ref PolicyInfo;
2688			(ok, pi.oid) = (hd e_pi).is_oid();
2689			if(!ok)
2690				break parse;
2691			# get optional policy qualifier info
2692			e_pi = tl e_pi;
2693			if(e_pi != nil) {
2694				e_pq: list of ref Elem;
2695				(ok, e_pq) = (hd e_pi).is_seq();
2696				if(!ok || len e_pq > 2 || len e_pq < 1)
2697					break parse;
2698				l_pq: list of ref PolicyQualifier;
2699				while(e_pq != nil) {
2700					pq: ref PolicyQualifier;
2701					(ok, pq.oid) = (hd e_pq).is_oid();
2702					if(!ok || pq.oid == nil)
2703						break parse;
2704					# get optional value
2705					if(tl e_pq != nil) {
2706						(ok, pq.value) = (hd tl e_pq).is_octetstring();
2707						if(!ok)
2708							break parse;
2709					}
2710					l_pq = pq :: l_pq;
2711					e_pq = tl e_pq;
2712				}
2713				# reverse the order
2714				while(l_pq != nil) {
2715					pi.qualifiers = (hd l_pq) :: pi.qualifiers;
2716					l_pq = tl l_pq;
2717				}
2718			}
2719			l_pi = pi :: l_pi;
2720		}
2721		# reverse the order
2722		l: list of ref PolicyInfo;
2723		while(l_pi != nil) {
2724			l = (hd l_pi) :: l;
2725			l_pi = tl l_pi;
2726		}
2727		return ("", ref ExtClass.CertificatePolicies(l));
2728	}
2729	return ("certificate policies: syntax error", nil);
2730}
2731
2732# [private]
2733
2734encode_certificatePolicies(c: ref ExtClass.CertificatePolicies): (string, array of byte)
2735{
2736	el, pel: list of ref Elem;
2737	pl := c.policies;
2738	while(pl != nil) {
2739		p := hd pl;
2740		if(p.oid == nil)
2741			return ("certificate policies: incomplete data", nil);
2742		plseq: list of ref Elem;
2743		if(p.qualifiers != nil) {
2744			ql := p.qualifiers;
2745			qel, qlseq: list of ref Elem;
2746			while(ql != nil) {
2747				pq := hd ql;
2748				pqseq: list of ref Elem;
2749				if(pq.oid == nil)
2750					return ("certificate policies: incomplete data", nil);
2751				if(pq.value != nil) {
2752					pqseq = ref Elem(
2753							Tag(Universal, OCTET_STRING, 0),
2754							ref Value.Octets(pq.value)
2755					) :: nil;
2756				}
2757				pqseq = ref Elem(
2758						Tag(Universal, OBJECT_ID, 0),
2759						ref Value.ObjId(pq.oid)
2760				) :: pqseq;
2761				qlseq = ref Elem(
2762						Tag(Universal, SEQUENCE, 1),
2763						ref Value.Seq(pqseq)
2764				) :: qlseq;
2765				ql = tl ql;
2766			}
2767			while(qlseq != nil) {
2768				qel = (hd qlseq) :: qel;
2769				qlseq = tl qlseq;
2770			}
2771			plseq = ref Elem(
2772					Tag(Universal, SEQUENCE, 1),
2773					ref Value.Seq(qel)
2774			) :: nil;
2775		}
2776		plseq = ref Elem(
2777				Tag(Universal, OBJECT_ID, 0),
2778				ref Value.ObjId(p.oid)
2779		) :: plseq;
2780		pel = ref Elem(
2781				Tag(Universal, SEQUENCE, 1),
2782				ref Value.Seq(plseq)
2783		) :: pel;
2784		pl = tl pl;
2785	}
2786	while(pel != nil) {
2787		el = (hd pel) :: el;
2788		pel = tl pel;
2789	}
2790	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2791	return asn1->encode(e);
2792}
2793
2794# [private]
2795
2796decode_alias(ext: ref Extension): (string, list of ref GeneralName)
2797{
2798parse:
2799	for(;;) {
2800		(err, all) := asn1->decode(ext.value);
2801		if(err != "")
2802			break parse;
2803		(ok, el) := all.is_seq();
2804		if(!ok)
2805			break parse;
2806		l_sa: list of ref GeneralName;
2807		while(el != nil) {
2808			gn: ref GeneralName;
2809			(ok, gn) = parse_gname(hd el);
2810			if(!ok)
2811				break parse;
2812			l_sa = gn :: l_sa;
2813			el = tl el;
2814		}
2815		# reverse order
2816		sa: list of ref GeneralName;
2817		while(l_sa != nil) {
2818			sa = (hd l_sa) :: sa;
2819			l_sa = tl l_sa;
2820		}
2821		return ("", sa);
2822	}
2823	return ("alias: syntax error", nil);
2824}
2825
2826# [private]
2827
2828encode_alias(gl: list of ref GeneralName): (string, array of byte)
2829{
2830	el, gel: list of ref Elem;
2831	while(gl != nil) {
2832		g := hd gl;
2833		(ok, e) := pack_gname(g);
2834		if(!ok)
2835			return ("alias: encoding error", nil);
2836		gel = e :: gel;
2837		gl = tl gl;
2838	}
2839	while(gel != nil) {
2840		el = (hd gel) :: el;
2841		gel = tl gel;
2842	}
2843	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2844	return asn1->encode(e);
2845}
2846
2847# [private]
2848
2849decode_subjectDirectoryAttributes(ext: ref Extension): (string, ref ExtClass)
2850{
2851parse:
2852	for(;;) {
2853		(err, all) := asn1->decode(ext.value);
2854		if(err != "")
2855			break parse;
2856		(ok, el) := all.is_seq();
2857		if(!ok)
2858			break parse;
2859		l_a: list of ref Attribute;
2860		while(el != nil) {
2861			a: ref Attribute;
2862			#(ok, a) = parse_attr(hd el);
2863			#if(!ok)
2864			#	break parse;
2865			l_a = a :: l_a;
2866			el = tl el;
2867		}
2868		# reverse order
2869		as: list of ref Attribute;
2870		while(l_a != nil) {
2871			as = (hd l_a) :: as;
2872			l_a = tl l_a;
2873		}
2874		return ("", ref ExtClass.SubjectDirectoryAttributes(as));
2875	}
2876	return ("subject directory attributes: syntax error", nil);
2877}
2878
2879# [private]
2880
2881encode_subjectDirectoryAttributes(c: ref ExtClass.SubjectDirectoryAttributes)
2882	: (string, array of byte)
2883{
2884	el, ael: list of ref Elem;
2885	al := c.attrs;
2886	while(al != nil) {
2887		(ok, e) := pack_attr(hd al);
2888		if(!ok)
2889			return ("subject directory attributes: encoding error", nil);
2890		ael = e :: ael;
2891		al = tl al;
2892	}
2893	while(ael != nil) {
2894		el = (hd ael) :: el;
2895		ael = tl ael;
2896	}
2897	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2898	return asn1->encode(e);
2899}
2900
2901# [private]
2902
2903decode_nameConstraints(ext: ref Extension): (string, ref ExtClass)
2904{
2905parse:
2906	for(;;) {
2907		(err, all) := asn1->decode(ext.value);
2908		if(err != "")
2909			break parse;
2910		(ok, el) := all.is_seq();
2911		if(!ok || len el < 1 || len el > 2)
2912			break parse;
2913		nc := ref ExtClass.NameConstraints;
2914		if(el != nil) {
2915			(ok, nc.permitted) = parse_gsubtrees(hd el);
2916			if(!ok || nc.permitted == nil)
2917				break parse;
2918			el = tl el;
2919		}
2920		if(el!= nil) {
2921			(ok, nc.excluded) = parse_gsubtrees(hd el);
2922			if(!ok || nc.excluded == nil)
2923				break parse;
2924		}
2925		return ("", nc);
2926	}
2927	return ("name constraints: syntax error", nil);
2928}
2929
2930# [private]
2931
2932encode_nameConstraints(c: ref ExtClass.NameConstraints): (string, array of byte)
2933{
2934	el: list of ref Elem;
2935	if(c.permitted == nil && c.excluded == nil)
2936		return ("name constraints: incomplete data", nil);
2937	if(c.excluded != nil) {
2938		(ok, e) := pack_gsubtrees(c.excluded);
2939		if(!ok)
2940			return ("name constraints: encoding error", nil);
2941		el = e :: el;
2942	}
2943	if(c.permitted != nil) {
2944		(ok, e) := pack_gsubtrees(c.permitted);
2945		if(!ok)
2946			return ("name constraints: encoding error", nil);
2947		el = e :: el;
2948	}
2949	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2950	return asn1->encode(e);
2951}
2952
2953# [private]
2954
2955parse_gsubtrees(e: ref Elem): (int, list of ref GSubtree)
2956{
2957parse:
2958	for(;;) {
2959		(ok, el) := e.is_seq();
2960		if(!ok)
2961			break parse;
2962		l, lgs: list of ref GSubtree;
2963		while(el != nil) {
2964			gs: ref GSubtree;
2965			(ok, gs) = parse_gsubtree(hd el);
2966			if(!ok)
2967				break parse;
2968			lgs = gs :: lgs;
2969			el = tl el;
2970		}
2971		while(lgs != nil) {
2972			l = (hd lgs) :: l;
2973			lgs = tl lgs;
2974		}
2975		return (1, l);
2976	}
2977	return (0, nil);
2978}
2979
2980# [private]
2981
2982pack_gsubtrees(gs: list of ref GSubtree): (int, ref Elem)
2983{
2984	el, l: list of ref Elem;
2985	while(gs != nil) {
2986		(ok, e) := pack_gsubtree(hd gs);
2987		if(!ok)
2988			return (0, nil);
2989		l = e :: l;
2990	}
2991	while(l != nil) {
2992		el = (hd l) :: el;
2993		l = tl l;
2994	}
2995	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
2996	return (1, e);
2997}
2998
2999# [private]
3000
3001parse_gsubtree(e: ref Elem): (int, ref GSubtree)
3002{
3003parse:
3004	for(;;) {
3005		(ok, el) := e.is_seq();
3006		if(!ok || len el > 3 || len el < 2)
3007			break parse;
3008		gs := ref GSubtree;
3009		e = hd el;
3010		(ok, gs.base) = parse_gname(e);
3011		if(!ok)
3012			break parse;
3013		el = tl el;
3014		e = hd el;
3015		(ok, e) = is_context(e, 0);
3016		if(ok) {
3017			(ok, gs.min) = e.is_int();
3018			if(!ok)
3019				break parse;
3020			el = tl el;
3021		}
3022		# get optional maximum base distance
3023		if(el != nil) {
3024			e = hd el;
3025			(ok, e) = is_context(e, 1);
3026			if(!ok)
3027				break parse;
3028			(ok, gs.max) = e.is_int();
3029			if(!ok)
3030				break parse;
3031		}
3032		return (1, gs);
3033	}
3034	return (0, nil);
3035}
3036
3037# [private]
3038
3039pack_gsubtree(g: ref GSubtree): (int, ref Elem)
3040{
3041	el: list of ref Elem;
3042	ok := 1;
3043	e: ref Elem;
3044	if(g.base == nil)
3045		return (0, nil);
3046	if(g.max != 0) {
3047		e = ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(g.max));
3048		(ok, e) = pack_context(e, 1);
3049		if(!ok)
3050			return (0, nil);
3051		el = e :: nil;
3052	}
3053	if(g.min != 0) {
3054		e = ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(g.min));
3055		(ok, e) = pack_context(e, 0);
3056		if(!ok)
3057			return (0, nil);
3058		el = e :: el;
3059	}
3060	(ok, e) = pack_gname(g.base);
3061	if(!ok)
3062		return (0, nil);
3063	el = e :: el;
3064	e = ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3065	return (1, e);
3066}
3067
3068# [private]
3069
3070decode_policyConstraints(ext: ref Extension): (string, ref ExtClass)
3071{
3072parse:
3073	for(;;) {
3074		(err, all) := asn1->decode(ext.value);
3075		if(err != "")
3076			break parse;
3077		(ok, el) := all.is_seq();
3078		if(!ok || len el < 1 || len el > 2)
3079			break parse;
3080		pc := ref ExtClass.PolicyConstraints;
3081		e := hd el;
3082		(ok, e) = is_context(e, 0);
3083		if(ok) {
3084			(ok, pc.require) = e.is_int();
3085			if(!ok)
3086				break parse;
3087			el = tl el;
3088		}
3089		if(el != nil) {
3090			e = hd el;
3091			(ok, e) = is_context(e, 1);
3092			if(!ok)
3093				break parse;
3094			(ok, pc.inhibit) = e.is_int();
3095			if(!ok)
3096				break parse;
3097		}
3098		return ("", pc);
3099	}
3100	return ("policy constraints: syntax error", nil);
3101}
3102
3103# [private]
3104
3105encode_policyConstraints(c: ref ExtClass.PolicyConstraints): (string, array of byte)
3106{
3107	el: list of ref Elem;
3108	ok := 1;
3109	if(c.inhibit > 0) {
3110		e := ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(c.inhibit));
3111		(ok, e) = pack_context(e, 1);
3112		if(!ok)
3113			return ("policy constraints: encoding error", nil);
3114		el = e :: nil;
3115	}
3116	if(c.require > 0) {
3117		e := ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(c.require));
3118		(ok, e) = pack_context(e, 0);
3119		if(!ok)
3120			return ("policy constraints: encoding error", nil);
3121		el = e :: el;
3122	}
3123	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3124	return asn1->encode(e);
3125}
3126
3127# [private]
3128
3129decode_cRLNumber(ext: ref Extension): (string, ref ExtClass)
3130{
3131parse:
3132	for(;;) {
3133		(err, all) := asn1->decode(ext.value);
3134		if(err != "")
3135			break parse;
3136		(ok, n) := all.is_int(); # TODO: should be IPint
3137		if(!ok)
3138			break parse;
3139		return ("", ref ExtClass.CRLNumber(n));
3140	}
3141	return ("crl number: syntax error", nil);
3142}
3143
3144# [private]
3145
3146encode_cRLNumber(c: ref ExtClass.CRLNumber): (string, array of byte)
3147{
3148	e := ref Elem(Tag(Universal, INTEGER, 0), ref Value.Int(c.curr));
3149	return asn1->encode(e);
3150}
3151
3152# [private]
3153
3154decode_reasonCode(ext: ref Extension): (string, ref ExtClass)
3155{
3156parse:
3157	for(;;) {
3158		(err, all) := asn1->decode(ext.value);
3159		if(err != "")
3160			break parse;
3161		(ok, un_used_bits, code) := all.is_bitstring();
3162		if(!ok)
3163			break parse;
3164		# no harm to ignore unused bits
3165		if(len code > 4)
3166			break parse;
3167		return ("", ref ExtClass.ReasonCode(b4int(code)));
3168	}
3169	return ("crl reason: syntax error", nil);
3170}
3171
3172# [private]
3173
3174encode_reasonCode(c: ref ExtClass.ReasonCode): (string, array of byte)
3175{
3176	e := ref Elem(
3177			Tag(Universal, BIT_STRING, 0),
3178			ref Value.BitString(0, int4b(c.code))
3179		);
3180	return asn1->encode(e);
3181}
3182
3183# [private]
3184
3185decode_instructionCode(ext: ref Extension): (string, ref ExtClass)
3186{
3187parse:
3188	for(;;) {
3189		(err, all) := asn1->decode(ext.value);
3190		if(err != "")
3191			break parse;
3192		(ok, code) := all.is_oid();
3193		if(!ok)
3194			break parse;
3195		return ("", ref ExtClass.InstructionCode(code));
3196	}
3197	return ("instruction code: syntax error", nil);
3198}
3199
3200# [private]
3201
3202encode_instructionCode(c: ref ExtClass.InstructionCode): (string, array of byte)
3203{
3204	e := ref Elem(Tag(Universal, OBJECT_ID, 0), ref Value.ObjId(c.oid));
3205	return asn1->encode(e);
3206}
3207
3208# [private]
3209
3210decode_invalidityDate(ext: ref Extension): (string, ref ExtClass)
3211{
3212parse:
3213	for(;;) {
3214		(err, all) := asn1->decode(ext.value);
3215		if(err != "")
3216			break parse;
3217		(ok, date) := all.is_time();
3218		if(!ok)
3219			break parse;
3220		t := decode_time(date, GeneralizedTime);
3221		if(t < 0)
3222			break parse;
3223		return ("", ref ExtClass.InvalidityDate(t));
3224	}
3225	return ("", nil);
3226}
3227
3228# [private]
3229
3230encode_invalidityDate(c: ref ExtClass.InvalidityDate): (string, array of byte)
3231{
3232	e := ref Elem(
3233			Tag(Universal, GeneralizedTime, 0),
3234			ref Value.String(pack_time(c.date, GeneralizedTime))
3235		);
3236	return asn1->encode(e);
3237}
3238
3239# [private]
3240
3241decode_cRLDistributionPoint(ext: ref Extension): (string, ref ExtClass)
3242{
3243parse:
3244	for(;;) {
3245		(err, all) := asn1->decode(ext.value);
3246		if(err != "")
3247			break parse;
3248		(ok, el) := all.is_seq();
3249		if(!ok || len el < 1) # Note: at least one
3250			break parse;
3251		l, dpl: list of ref DistrPoint;
3252		while(el != nil) {
3253			dp: ref DistrPoint;
3254			(ok, dp) = parse_distrpoint(hd el);
3255			if(!ok)
3256				break parse;
3257			dpl = dp :: dpl;
3258		}
3259		# reverse order
3260		while(dpl != nil) {
3261			l = (hd dpl) :: l;
3262			dpl = tl dpl;
3263		}
3264		return ("", ref ExtClass.CRLDistributionPoint(l));
3265	}
3266	return ("crl distribution point: syntax error", nil);
3267}
3268
3269# [private]
3270
3271encode_cRLDistributionPoint(c: ref ExtClass.CRLDistributionPoint): (string, array of byte)
3272{
3273	el, l: list of ref Elem;
3274	dpl := c.ps;
3275	if(dpl == nil) # at lease one
3276		return ("crl distribution point: incomplete data error", nil);
3277	while(dpl != nil) {
3278		(ok, e) := pack_distrpoint(hd dpl);
3279		if(!ok)
3280			return ("crl distribution point: encoding error", nil);
3281		l = e :: l;
3282	}
3283	while(l != nil) {
3284		el = (hd l) :: el;
3285		l = tl l;
3286	}
3287	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3288	return asn1->encode(e);
3289}
3290
3291# [private]
3292
3293parse_distrpoint(e: ref Elem): (int, ref DistrPoint)
3294{
3295parse:
3296	for(;;) {
3297		(ok, el) := e.is_seq();
3298		if(!ok)
3299			break parse;
3300		if(!ok || len el > 3 || len el < 1)
3301			break parse;
3302		dp: ref DistrPoint;
3303		e = hd el;
3304		# get optional distribution point name
3305		(ok, e) = is_context(e, 0);
3306		if(ok) {
3307			(ok, dp.name) = parse_dpname(e);
3308			if(!ok)
3309				break parse;
3310			el = tl el;
3311		}
3312		# get optional reason flags
3313		if(el != nil) {
3314			e = hd el;
3315			(ok, e) = is_context(e, 1);
3316			if(ok) {
3317				unused_bits: int;
3318				reasons: array of byte;
3319				(ok, unused_bits, reasons) = e.is_bitstring();
3320				if(!ok)
3321					break parse;
3322				# no harm to ignore unused bits
3323				if(len reasons > 4)
3324					break parse;
3325				dp.reasons = b4int(reasons);
3326			}
3327			el = tl el;
3328		}
3329		# get optional crl issuer
3330		if(el != nil) {
3331			e = hd el;
3332			(ok, e) = is_context(e, 2);
3333			if(!ok)
3334				break parse;
3335			(ok, dp.issuer) = parse_lgname(e);
3336			if(!ok)
3337				break parse;
3338			el = tl el;
3339		}
3340		# must be no more left
3341		if(el != nil)
3342			break parse;
3343		return (1, dp);
3344	}
3345	return (0, nil);
3346}
3347
3348# [private]
3349
3350pack_distrpoint(dp: ref DistrPoint): (int, ref Elem)
3351{
3352	el: list of ref Elem;
3353	if(dp.issuer != nil) {
3354		(ok, e) := pack_lgname(dp.issuer);
3355		if(!ok)
3356			return (0, nil);
3357		(ok, e) = pack_context(e, 2);
3358		if(!ok)
3359			return (0, nil);
3360		el = e :: nil;
3361	}
3362	if(dp.reasons != 0) {
3363		e := ref Elem(
3364				Tag(Universal, BIT_STRING, 0),
3365				ref Value.BitString(0, int4b(dp.reasons))
3366			);
3367		ok := 1;
3368		(ok, e) = pack_context(e, 1);
3369		if(!ok)
3370			return (0, nil);
3371		el = e :: el;
3372	}
3373	if(dp.name != nil) {
3374		(ok, e) := pack_dpname(dp.name);
3375		if(!ok)
3376			return (0, nil);
3377		(ok, e) = pack_context(e, 0);
3378		if(!ok)
3379			return (0, nil);
3380		el = e :: el;
3381	}
3382	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3383	return (1, e);
3384}
3385
3386# [private]
3387
3388parse_dpname(e: ref Elem): (int, ref DistrPointName)
3389{
3390parse:
3391	for(;;) {
3392		# parse CHOICE
3393		ok := 0;
3394		(ok, e) = is_context(e, 0);
3395		if(ok) {
3396			lg: list of ref GeneralName;
3397			(ok, lg) = parse_lgname(e);
3398			if(!ok)
3399				break parse;
3400			return (1, ref DistrPointName(lg, nil));
3401		}
3402		(ok, e) = is_context(e, 1);
3403		if(!ok)
3404			break parse;
3405		n: ref Name;
3406		(ok, n) = parse_name(e);
3407		if(!ok)
3408			break parse;
3409		return (1, ref DistrPointName(nil, n.rd_names));
3410	}
3411	return (0, nil);
3412}
3413
3414# [private]
3415
3416pack_dpname(dpn: ref DistrPointName): (int, ref Elem)
3417{
3418	if(dpn.full_name != nil) {
3419		(ok, e) := pack_lgname(dpn.full_name);
3420		if(!ok)
3421			return (0, nil);
3422		return pack_context(e, 0);
3423	}
3424	if(dpn.rdname != nil) {
3425		rdn := dpn.rdname;
3426		el, l: list of ref Elem;
3427		while(rdn != nil) {
3428			l = pack_rdname(hd rdn) :: l;
3429			rdn = tl rdn;
3430		}
3431		while(l != nil) {
3432			el = (hd l) :: el;
3433			l = tl l;
3434		}
3435		e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3436		return pack_context(e, 1);
3437	}
3438	return (0, nil);
3439}
3440
3441# [private]
3442
3443decode_issuingDistributionPoint(ext: ref Extension): (string, ref ExtClass)
3444{
3445parse:
3446	for(;;) {
3447		(err, all) := asn1->decode(ext.value);
3448		if(err != "")
3449			break parse;
3450		(ok, el) := all.is_seq();
3451		if(!ok || len el < 3 || len el > 5)
3452			break parse;
3453		ip := ref ExtClass.IssuingDistributionPoint;
3454		ae := hd el;
3455		# get optional distribution point name
3456		(ok, ae) = is_context(ae, 0);
3457		if(ok) {
3458			#(ok, ip.name) = parse_dpname(ae);
3459			if(!ok)
3460				break parse;
3461			el = tl el;
3462		}
3463		# get only contains user certs field
3464		if(el != nil) {
3465			ae = hd el;
3466			(ok, ae) = is_context(ae, 1);
3467			if(ok) {
3468				(ok, ip.only_usercerts) = ae.is_int(); # boolean
3469				if(!ok)
3470					break parse;
3471			}
3472			el = tl el;
3473		}
3474		# get only contains ca certs field
3475		if(el != nil) {
3476			ae = hd el;
3477			(ok, ae) = is_context(ae, 2);
3478			if(ok) {
3479				(ok, ip.only_cacerts) = ae.is_int(); # boolean
3480				if(!ok)
3481					break parse;
3482			}
3483			el = tl el;
3484		}
3485		# get optioinal only some reasons
3486		if(el != nil) {
3487			ae = hd el;
3488			(ok, ae) = is_context(ae, 3);
3489			if(ok) {
3490				reasons: array of byte;
3491				unused_bits: int;
3492				(ok, unused_bits, reasons) = ae.is_bitstring();
3493				if(!ok || len reasons > 4)
3494					break parse;
3495				ip.only_reasons = b4int(reasons);
3496			}
3497			el = tl el;
3498		}
3499		# get indirect crl field
3500		if(el != nil) {
3501			ae = hd el;
3502			(ok, ae) = is_context(ae, 4);
3503			if(!ok)
3504				break parse;
3505			(ok, ip.indirect_crl) = ae.is_int(); # boolean
3506			if(!ok)
3507				break parse;
3508			el = tl el;
3509		}
3510		# must be no more left
3511		if(el != nil)
3512			break parse;
3513		return ("", ip);
3514	}
3515	return ("issuing distribution point: syntax error", nil);
3516}
3517
3518# [private]
3519
3520encode_issuingDistributionPoint(c: ref ExtClass.IssuingDistributionPoint)
3521	: (string, array of byte)
3522{
3523	el: list of ref Elem;
3524	ok := 1;
3525	if(c.indirect_crl != 0) { # no encode for DEFAULT
3526		e := ref Elem(
3527				Tag(Universal, BOOLEAN, 0),
3528				ref Value.Bool(c.indirect_crl)
3529			);
3530		(ok, e) = pack_context(e, 4);
3531		if(!ok)
3532			return ("issuing distribution point: encoding error", nil);
3533		el = e :: el;
3534	}
3535	if(c.only_reasons != 0) {
3536		e := ref Elem(
3537				Tag(Universal, BIT_STRING, 0),
3538				ref Value.BitString(0, int4b(c.only_reasons))
3539			);
3540		(ok, e) = pack_context(e, 3);
3541		if(!ok)
3542			return ("issuing distribution point: encoding error", nil);
3543		el = e :: el;
3544	}
3545	if(c.only_cacerts != 0) {
3546		e := ref Elem(
3547				Tag(Universal, BOOLEAN, 0),
3548				ref Value.Bool(c.only_cacerts)
3549			);
3550		(ok, e) = pack_context(e, 2);
3551		if(!ok)
3552			return ("issuing distribution point: encoding error", nil);
3553		el = e :: el;
3554	}
3555	if(c.only_usercerts != 0) {
3556		e := ref Elem(
3557				Tag(Universal, BOOLEAN, 0),
3558				ref Value.Bool(c.only_usercerts)
3559			);
3560		(ok, e) = pack_context(e, 1);
3561		if(!ok)
3562			return ("issuing distribution point: encoding error", nil);
3563		el = e :: el;
3564	}
3565	if(c.name != nil) {
3566		e: ref Elem;
3567		(ok, e) = pack_dpname(c.name);
3568		if(!ok)
3569			return ("issuing distribution point: encoding error", nil);
3570		(ok, e) = pack_context(e, 0);
3571		if(!ok)
3572			return ("issuing distribution point: encoding error", nil);
3573		el = e :: el;
3574	}
3575
3576	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3577	return asn1->encode(e);
3578}
3579
3580# [private]
3581
3582decode_certificateIssuer(ext: ref Extension): (string, ref ExtClass)
3583{
3584parse:
3585	for(;;) {
3586		(err, all) := asn1->decode(ext.value);
3587		if(err != "")
3588			break parse;
3589		(ok, el) := all.is_seq();
3590		if(!ok)
3591			break parse;
3592		gl, gnl: list of ref GeneralName;
3593		while(el != nil) {
3594			g: ref GeneralName;
3595			(ok, g) = parse_gname(hd el);
3596			if(!ok)
3597				break parse;
3598			gnl = g :: gnl;
3599			el = tl el;
3600		}
3601		while(gnl != nil) {
3602			gl = (hd gnl) :: gl;
3603			gnl = tl gnl;
3604		}
3605		return ("", ref ExtClass.CertificateIssuer(gl));
3606	}
3607
3608	return ("certificate issuer: syntax error", nil);
3609}
3610
3611# [private]
3612
3613encode_certificateIssuer(c: ref ExtClass.CertificateIssuer): (string, array of byte)
3614{
3615	el, nel: list of ref Elem;
3616	ns := c.names;
3617	while(ns != nil) {
3618		(ok, e) := pack_gname(hd ns);
3619		if(!ok)
3620			return ("certificate issuer: encoding error", nil);
3621		nel = e :: nel;
3622		ns = tl ns;
3623	}
3624	while(nel != nil) {
3625		el = (hd nel) :: el;
3626		nel = tl nel;
3627	}
3628	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3629	return asn1->encode(e);
3630}
3631
3632# [private]
3633
3634decode_deltaCRLIndicator(ext: ref Extension): (string, ref ExtClass)
3635{
3636parse:
3637	for(;;) {
3638		(err, all) := asn1->decode(ext.value);
3639		if(err != "")
3640			break parse;
3641		(ok, b) := all.is_bigint();
3642		if(!ok)
3643			break parse;
3644		return ("", ref ExtClass.DeltaCRLIndicator(IPint.bebytestoip(b)));
3645	}
3646	return ("delta crl number: syntax error", nil);
3647}
3648
3649# [private]
3650
3651encode_deltaCRLIndicator(c: ref ExtClass.DeltaCRLIndicator): (string, array of byte)
3652{
3653	e := ref Elem(
3654			Tag(Universal, INTEGER, 0),
3655			ref Value.BigInt(c.number.iptobebytes())
3656		);
3657	return asn1->encode(e);
3658}
3659
3660# [public]
3661
3662GeneralName.tostring(gn: self ref GeneralName): string
3663{
3664	s: string;
3665
3666	pick g := gn {
3667	otherName =>
3668		s = "other name: " + g.str;
3669	rfc822Name =>
3670		s = "rfc822 name: " + g.str;
3671	dNSName =>
3672		s = "dns name: " + g.str;
3673	x400Address =>
3674		s = "x400 address: " + g.str;
3675	uniformResourceIdentifier =>
3676		s = "url: " + g.str;
3677	iPAddress =>
3678		s = "ip address: " + bastr(g.ip);
3679	registeredID =>
3680		s = "oid: " + g.oid.tostring();
3681	ediPartyName =>
3682		s = "edi party name: ";
3683		s += "\n\tname assigner is " + g.nameAssigner.tostring();
3684		s += "\n\tparty name is " + g.partyName.tostring();
3685	directoryName =>
3686		s = "directory name: " + g.dir.tostring();
3687	}
3688	return s;
3689}
3690
3691# [public]
3692
3693PolicyInfo.tostring(pi: self ref PolicyInfo): string
3694{
3695	s := "oid: " + pi.oid.tostring();
3696	s += "qualifiers: ";
3697	ql := pi.qualifiers;
3698	while(ql != nil) {
3699		s += (hd ql).tostring();
3700		ql = tl ql;
3701	}
3702	return s;
3703}
3704
3705# [public]
3706
3707PolicyQualifier.tostring(pq: self ref PolicyQualifier): string
3708{
3709	s := "oid: " + pq.oid.tostring();
3710	s += "value: " + bastr(pq.value);
3711	return s;
3712}
3713
3714# [public]
3715
3716GSubtree.tostring(gs: self ref GSubtree): string
3717{
3718	s := "base: " + gs.base.tostring();
3719	s += "range: " + string gs.min + "-" + string gs.max;
3720	return s;
3721}
3722
3723# [public]
3724
3725DistrPoint.tostring(dp: self ref DistrPoint): string
3726{
3727	s := "Distribution Point: ";
3728	s += "\n\tname = ";
3729	d := dp.name;
3730	if(d.full_name != nil) {
3731		f := d.full_name;
3732		while(f != nil) {
3733			s += (hd f).tostring() + ",";
3734			f = tl f;
3735		}
3736	}
3737	else {
3738		r := d.rdname;
3739		while(r != nil) {
3740			s += (hd r).tostring() + ",";
3741			r = tl r;
3742		}
3743	}
3744	s += "\n\treasons = " + string dp.reasons;
3745	s += "\n\tissuer = ";
3746	gl := dp.issuer;
3747	while(gl != nil) {
3748		s += (hd gl).tostring() + ",";
3749		gl = tl gl;
3750	}
3751	return s;
3752}
3753
3754# [private]
3755
3756is_context(e: ref Elem, num: int): (int, ref Elem)
3757{
3758	if(e.tag.class == ASN1->Context && e.tag.num == num) {
3759		pick v := e.val {
3760		Octets =>
3761			(err, all) := asn1->decode(v.bytes);
3762			if(err == "")
3763				return (1, all);
3764		}
3765	}
3766	return (0, nil);
3767}
3768
3769# [private]
3770
3771pack_context(e: ref Elem, num: int): (int, ref Elem)
3772{
3773	(err, b) := asn1->encode(e);
3774	if(err == "")
3775		return (1, ref Elem(Tag(Context, num, 0), ref Value.Octets(b)));
3776	return (0, nil);
3777}
3778
3779# [private]
3780
3781parse_lgname(e: ref Elem): (int, list of ref GeneralName)
3782{
3783parse:
3784	for(;;) {
3785		(ok, el) := e.is_seq();
3786		if(!ok)
3787			break parse;
3788		l, lg: list of ref GeneralName;
3789		while(el != nil) {
3790			g: ref GeneralName;
3791			(ok, g) = parse_gname(hd el);
3792			if(!ok)
3793				break parse;
3794			lg = g :: lg;
3795			el = tl el;
3796		}
3797		while(lg != nil) {
3798			l = (hd lg) :: l;
3799			lg = tl lg;
3800		}
3801		return (1, l);
3802	}
3803	return (0, nil);
3804}
3805
3806# [private]
3807
3808pack_lgname(lg: list of ref GeneralName): (int, ref Elem)
3809{
3810	el, gel: list of ref Elem;
3811	while(lg != nil) {
3812		(ok, e) := pack_gname(hd lg);
3813		if(!ok)
3814			return (0, nil);
3815		gel = e :: gel;
3816		lg = tl lg;
3817	}
3818	while(gel != nil) {
3819		el = (hd gel) :: el;
3820		gel = tl gel;
3821	}
3822	e := ref Elem(Tag(Universal, SEQUENCE, 1), ref Value.Seq(el));
3823	return (1, e);
3824}
3825
3826# [private]
3827
3828parse_gname(e: ref Elem): (int, ref GeneralName)
3829{
3830parse:
3831	for(;;) {
3832		g: ref GeneralName;
3833		ok := 1;
3834		case e.tag.num {
3835		0 =>
3836			(ok, e) = is_context(e, 0);
3837			if(!ok)
3838				break parse;
3839			str: string;
3840			(ok, str) = e.is_string();
3841			if(!ok)
3842				break parse;
3843			g = ref GeneralName.otherName(str);
3844		1 =>
3845			(ok, e) = is_context(e, 1);
3846			if(!ok)
3847				break parse;
3848			str: string;
3849			(ok, str) = e.is_string();
3850			if(!ok)
3851				break parse;
3852			g = ref GeneralName.rfc822Name(str);
3853		2 =>
3854			(ok, e) = is_context(e, 2);
3855			if(!ok)
3856				break parse;
3857			str: string;
3858			(ok, str) = e.is_string();
3859			if(!ok)
3860				break parse;
3861			g = ref GeneralName.dNSName(str);
3862		3 =>
3863			(ok, e) = is_context(e, 3);
3864			if(!ok)
3865				break parse;
3866			str: string;
3867			(ok, str) = e.is_string();
3868			if(!ok)
3869				break parse;
3870			g = ref GeneralName.x400Address(str);
3871		4 =>
3872			(ok, e) = is_context(e, 4);
3873			if(!ok)
3874				break parse;
3875			dir: ref Name;
3876			(ok, dir) = parse_name(e);
3877			if(!ok)
3878				break parse;
3879			g = ref GeneralName.directoryName(dir);
3880		5 =>
3881			(ok, e) = is_context(e, 5);
3882			if(!ok)
3883				break parse;
3884			el: list of ref Elem;
3885			(ok, el) = e.is_seq();
3886			if(!ok || len el < 1 || len el > 3)
3887				break parse;
3888			na, pn: ref Name;
3889			(ok, e) = is_context(hd el, 0);
3890			if(ok) {
3891				(ok, na) = parse_name(e);
3892				if(!ok)
3893					break parse;
3894				el = tl el;
3895			}
3896			if(el != nil) {
3897				(ok, e) = is_context(hd el, 1);
3898				if(!ok)
3899					break parse;
3900				(ok, pn) = parse_name(e);
3901				if(!ok)
3902					break parse;
3903			}
3904			g = ref GeneralName.ediPartyName(na, pn);
3905		6 =>
3906			(ok, e) = is_context(e, 6);
3907			if(!ok)
3908				break parse;
3909			str: string;
3910			(ok, str) = e.is_string();
3911			if(!ok)
3912				break parse;
3913			g = ref GeneralName.uniformResourceIdentifier(str);
3914		7 =>
3915			(ok, e) = is_context(e, 7);
3916			if(!ok)
3917				break parse;
3918			ip: array of byte;
3919			(ok, ip) = e.is_octetstring();
3920			if(!ok)
3921				break parse;
3922			g = ref GeneralName.iPAddress(ip);
3923		8 =>
3924			(ok, e) = is_context(e, 8);
3925			if(!ok)
3926				break parse;
3927			oid: ref Oid;
3928			(ok, oid) = e.is_oid();
3929			if(!ok)
3930				break parse;
3931			g = ref GeneralName.registeredID(oid);
3932		* =>
3933			break parse;
3934		}
3935		return (1, g);
3936	}
3937	return (0, nil);
3938}
3939
3940# [private]
3941
3942pack_gname(gn: ref GeneralName): (int, ref Elem)
3943{
3944	e: ref Elem;
3945	ok := 1;
3946
3947	pick g := gn {
3948	otherName =>
3949			e = ref Elem(
3950					Tag(Universal, GeneralString, 0),
3951					ref Value.String(g.str)
3952				);
3953			(ok, e) = pack_context(e, 0);
3954			if(!ok)
3955				return (0, nil);
3956	rfc822Name =>
3957			e = ref Elem(
3958					Tag(Universal, IA5String, 0),
3959					ref Value.String(g.str)
3960				);
3961			(ok, e) = pack_context(e, 1);
3962			if(!ok)
3963				return (0, nil);
3964	dNSName =>
3965			e = ref Elem(
3966					Tag(Universal, IA5String, 0),
3967					ref Value.String(g.str)
3968				);
3969			(ok, e) = pack_context(e, 2);
3970			if(!ok)
3971				return (0, nil);
3972	x400Address =>
3973			e = ref Elem(
3974					Tag(Universal, GeneralString, 0),
3975					ref Value.String(g.str)
3976				);
3977			(ok, e) = pack_context(e, 3);
3978			if(!ok)
3979				return (0, nil);
3980	uniformResourceIdentifier =>
3981			e = ref Elem(
3982					Tag(Universal, GeneralString, 0),
3983					ref Value.String(g.str)
3984				);
3985			(ok, e) = pack_context(e, 6);
3986			if(!ok)
3987				return (0, nil);
3988	iPAddress =>
3989			e = ref Elem(
3990					Tag(Universal, OCTET_STRING, 0),
3991					ref Value.Octets(g.ip)
3992				);
3993			(ok, e) = pack_context(e, 7);
3994			if(!ok)
3995				return (0, nil);
3996
3997	registeredID =>
3998			e = ref Elem(
3999					Tag(Universal, OBJECT_ID, 0),
4000					ref Value.ObjId(g.oid)
4001				);
4002			(ok, e) = pack_context(e, 8);
4003			if(!ok)
4004				return (0, nil);
4005
4006	ediPartyName =>
4007			el: list of ref Elem;
4008			if(g.partyName != nil) {
4009				e = pack_name(g.partyName);
4010				(ok, e) = pack_context(e, 1);
4011				if(!ok)
4012					return (0, nil);
4013				el = e :: nil;
4014			}
4015			if(g.nameAssigner != nil) {
4016				e = pack_name(g.nameAssigner);
4017				(ok, e) = pack_context(e, 0);
4018				if(!ok)
4019					return (0, nil);
4020				el = e :: el;
4021			}
4022			e = ref Elem(
4023					Tag(Universal, SEQUENCE, 1),
4024					ref Value.Seq(el)
4025				);
4026			(ok, e) = pack_context(e, 5);
4027			if(!ok)
4028				return (0, nil);
4029	directoryName =>
4030			e = pack_name(g.dir);
4031			(ok, e) = pack_context(e, 4);
4032			if(!ok)
4033				return (0, nil);
4034	}
4035	return (1, e);
4036}
4037
4038# [private]
4039# convert at most 4 bytes to int, len buf must be less than 4
4040
4041b4int(buf: array of byte): int
4042{
4043	val := 0;
4044	for(i := 0; i < len buf; i++)
4045		val = (val << 8) | (int buf[i]);
4046	return val;
4047}
4048
4049# [private]
4050
4051int4b(value: int): array of byte
4052{
4053	n := 4;
4054	buf := array [n] of byte;
4055	while(n--)	{
4056		buf[n] = byte value;
4057		value >>= 8;
4058	}
4059	return buf;
4060}
4061
4062# [private]
4063
4064oid_cmp(a, b: ref Oid): int
4065{
4066	na := len a.nums;
4067	nb := len b.nums;
4068	if(na != nb)
4069		return 0;
4070	for(i := 0; i < na; i++) {
4071		if(a.nums[i] != b.nums[i])
4072			return 0;
4073	}
4074	return 1;
4075}
4076
4077# [private]
4078# decode two bytes into an integer [0-99]
4079# return -1 for an invalid encoding
4080
4081get2(a: string, i: int): int
4082{
4083	a0 := int a[i];
4084	a1 := int a[i+1];
4085	if(a0 < '0' || a0 > '9' || a1 < '0' || a1 > '9')
4086        	return -1;
4087	return (a0 - '0')*10 + a1 - '0';
4088}
4089
4090# [private]
4091# encode an integer [0-99] into two bytes
4092
4093put2(a: array of byte, n, i: int): int
4094{
4095	a[i] = byte (n/10 + '0');
4096	a[i+1] = byte (n%10 + '0');
4097	return i+2;
4098}
4099
4100# [private]
4101
4102bastr(a: array of byte) : string
4103{
4104	ans := "";
4105	for(i := 0; i < len a; i++) {
4106		if(i < len a - 1 && i%10 == 0)
4107			ans += "\n\t\t";
4108		ans += sys->sprint("%2x ", int a[i]);
4109	}
4110	return ans;
4111}
4112
4113# [private]
4114
4115parse_attr(nil: ref Elem): (int, ref Attribute)
4116{
4117	return (0, nil);
4118}
4119
4120# [private]
4121
4122pack_attr(nil: ref Attribute): (int, ref Elem)
4123{
4124	return (0, nil);
4125}
4126