xref: /plan9/sys/src/ape/lib/sec/port/x509-ape.c (revision f591d9710fae2220cec09da2812fd6db952f1a27)
146d884bbSDavid du Colombier #include <u.h>
246d884bbSDavid du Colombier #include <libc.h>
346d884bbSDavid du Colombier #include <mp.h>
446d884bbSDavid du Colombier #include <libsec.h>
546d884bbSDavid du Colombier 
646d884bbSDavid du Colombier typedef DigestState*(*DigestFun)(uchar*,ulong,uchar*,DigestState*);
746d884bbSDavid du Colombier 
846d884bbSDavid du Colombier /* ANSI offsetof, backwards. */
946d884bbSDavid du Colombier #define	OFFSETOF(a, b)	offsetof(b, a)
1046d884bbSDavid du Colombier 
1146d884bbSDavid du Colombier /*=============================================================*/
1246d884bbSDavid du Colombier /*  general ASN1 declarations and parsing
1346d884bbSDavid du Colombier  *
1446d884bbSDavid du Colombier  *  For now, this is used only for extracting the key from an
1546d884bbSDavid du Colombier  *  X509 certificate, so the entire collection is hidden.  But
1646d884bbSDavid du Colombier  *  someday we should probably make the functions visible and
1746d884bbSDavid du Colombier  *  give them their own man page.
1846d884bbSDavid du Colombier  */
1946d884bbSDavid du Colombier typedef struct Elem Elem;
2046d884bbSDavid du Colombier typedef struct Tag Tag;
2146d884bbSDavid du Colombier typedef struct Value Value;
2246d884bbSDavid du Colombier typedef struct Bytes Bytes;
2346d884bbSDavid du Colombier typedef struct Ints Ints;
2446d884bbSDavid du Colombier typedef struct Bits Bits;
2546d884bbSDavid du Colombier typedef struct Elist Elist;
2646d884bbSDavid du Colombier 
2746d884bbSDavid du Colombier /* tag classes */
2846d884bbSDavid du Colombier #define Universal 0
2946d884bbSDavid du Colombier #define Context 0x80
3046d884bbSDavid du Colombier 
3146d884bbSDavid du Colombier /* universal tags */
3246d884bbSDavid du Colombier #define BOOLEAN 1
3346d884bbSDavid du Colombier #define INTEGER 2
3446d884bbSDavid du Colombier #define BIT_STRING 3
3546d884bbSDavid du Colombier #define OCTET_STRING 4
3646d884bbSDavid du Colombier #define NULLTAG 5
3746d884bbSDavid du Colombier #define OBJECT_ID 6
3846d884bbSDavid du Colombier #define ObjectDescriptor 7
3946d884bbSDavid du Colombier #define EXTERNAL 8
4046d884bbSDavid du Colombier #define REAL 9
4146d884bbSDavid du Colombier #define ENUMERATED 10
4246d884bbSDavid du Colombier #define EMBEDDED_PDV 11
4346d884bbSDavid du Colombier #define UTF8String 12
4446d884bbSDavid du Colombier #define SEQUENCE 16		/* also SEQUENCE OF */
4546d884bbSDavid du Colombier #define SETOF 17				/* also SETOF OF */
4646d884bbSDavid du Colombier #define NumericString 18
4746d884bbSDavid du Colombier #define PrintableString 19
4846d884bbSDavid du Colombier #define TeletexString 20
4946d884bbSDavid du Colombier #define VideotexString 21
5046d884bbSDavid du Colombier #define IA5String 22
5146d884bbSDavid du Colombier #define UTCTime 23
5246d884bbSDavid du Colombier #define GeneralizedTime 24
5346d884bbSDavid du Colombier #define GraphicString 25
5446d884bbSDavid du Colombier #define VisibleString 26
5546d884bbSDavid du Colombier #define GeneralString 27
5646d884bbSDavid du Colombier #define UniversalString 28
5746d884bbSDavid du Colombier #define BMPString 30
5846d884bbSDavid du Colombier 
5946d884bbSDavid du Colombier struct Bytes {
6046d884bbSDavid du Colombier 	int	len;
6146d884bbSDavid du Colombier 	uchar	data[1];
6246d884bbSDavid du Colombier };
6346d884bbSDavid du Colombier 
6446d884bbSDavid du Colombier struct Ints {
6546d884bbSDavid du Colombier 	int	len;
6646d884bbSDavid du Colombier 	int	data[1];
6746d884bbSDavid du Colombier };
6846d884bbSDavid du Colombier 
6946d884bbSDavid du Colombier struct Bits {
7046d884bbSDavid du Colombier 	int	len;		/* number of bytes */
7146d884bbSDavid du Colombier 	int	unusedbits;	/* unused bits in last byte */
7246d884bbSDavid du Colombier 	uchar	data[1];	/* most-significant bit first */
7346d884bbSDavid du Colombier };
7446d884bbSDavid du Colombier 
7546d884bbSDavid du Colombier struct Tag {
7646d884bbSDavid du Colombier 	int	class;
7746d884bbSDavid du Colombier 	int	num;
7846d884bbSDavid du Colombier };
7946d884bbSDavid du Colombier 
8046d884bbSDavid du Colombier enum { VBool, VInt, VOctets, VBigInt, VReal, VOther,
8146d884bbSDavid du Colombier 	VBitString, VNull, VEOC, VObjId, VString, VSeq, VSet };
8246d884bbSDavid du Colombier struct Value {
8346d884bbSDavid du Colombier 	int	tag;		/* VBool, etc. */
8446d884bbSDavid du Colombier 	union {
8546d884bbSDavid du Colombier 		int	boolval;
8646d884bbSDavid du Colombier 		int	intval;
8746d884bbSDavid du Colombier 		Bytes*	octetsval;
8846d884bbSDavid du Colombier 		Bytes*	bigintval;
8946d884bbSDavid du Colombier 		Bytes*	realval;	/* undecoded; hardly ever used */
9046d884bbSDavid du Colombier 		Bytes*	otherval;
9146d884bbSDavid du Colombier 		Bits*	bitstringval;
9246d884bbSDavid du Colombier 		Ints*	objidval;
9346d884bbSDavid du Colombier 		char*	stringval;
9446d884bbSDavid du Colombier 		Elist*	seqval;
9546d884bbSDavid du Colombier 		Elist*	setval;
9646d884bbSDavid du Colombier 	} u;  /* (Don't use anonymous unions, for ease of porting) */
9746d884bbSDavid du Colombier };
9846d884bbSDavid du Colombier 
9946d884bbSDavid du Colombier struct Elem {
10046d884bbSDavid du Colombier 	Tag	tag;
10146d884bbSDavid du Colombier 	Value	val;
10246d884bbSDavid du Colombier };
10346d884bbSDavid du Colombier 
10446d884bbSDavid du Colombier struct Elist {
10546d884bbSDavid du Colombier 	Elist*	tl;
10646d884bbSDavid du Colombier 	Elem	hd;
10746d884bbSDavid du Colombier };
10846d884bbSDavid du Colombier 
10946d884bbSDavid du Colombier /* decoding errors */
11046d884bbSDavid du Colombier enum { ASN_OK, ASN_ESHORT, ASN_ETOOBIG, ASN_EVALLEN,
11146d884bbSDavid du Colombier 		ASN_ECONSTR, ASN_EPRIM, ASN_EINVAL, ASN_EUNIMPL };
11246d884bbSDavid du Colombier 
11346d884bbSDavid du Colombier 
11446d884bbSDavid du Colombier /* here are the functions to consider making extern someday */
11546d884bbSDavid du Colombier static Bytes*	newbytes(int len);
11646d884bbSDavid du Colombier static Bytes*	makebytes(uchar* buf, int len);
11746d884bbSDavid du Colombier static void	freebytes(Bytes* b);
11846d884bbSDavid du Colombier static Bytes*	catbytes(Bytes* b1, Bytes* b2);
11946d884bbSDavid du Colombier static Ints*	newints(int len);
12046d884bbSDavid du Colombier static Ints*	makeints(int* buf, int len);
12146d884bbSDavid du Colombier static void	freeints(Ints* b);
12246d884bbSDavid du Colombier static Bits*	newbits(int len);
12346d884bbSDavid du Colombier static Bits*	makebits(uchar* buf, int len, int unusedbits);
12446d884bbSDavid du Colombier static void	freebits(Bits* b);
12546d884bbSDavid du Colombier static Elist*	mkel(Elem e, Elist* tail);
12646d884bbSDavid du Colombier static void	freeelist(Elist* el);
12746d884bbSDavid du Colombier static int	elistlen(Elist* el);
12846d884bbSDavid du Colombier static int	is_seq(Elem* pe, Elist** pseq);
12946d884bbSDavid du Colombier static int	is_set(Elem* pe, Elist** pset);
13046d884bbSDavid du Colombier static int	is_int(Elem* pe, int* pint);
13146d884bbSDavid du Colombier static int	is_bigint(Elem* pe, Bytes** pbigint);
13246d884bbSDavid du Colombier static int	is_bitstring(Elem* pe, Bits** pbits);
13346d884bbSDavid du Colombier static int	is_octetstring(Elem* pe, Bytes** poctets);
13446d884bbSDavid du Colombier static int	is_oid(Elem* pe, Ints** poid);
13546d884bbSDavid du Colombier static int	is_string(Elem* pe, char** pstring);
13646d884bbSDavid du Colombier static int	is_time(Elem* pe, char** ptime);
13746d884bbSDavid du Colombier static int	decode(uchar* a, int alen, Elem* pelem);
13846d884bbSDavid du Colombier static int	decode_seq(uchar* a, int alen, Elist** pelist);
13946d884bbSDavid du Colombier static int	decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval);
14046d884bbSDavid du Colombier static int	encode(Elem e, Bytes** pbytes);
14146d884bbSDavid du Colombier static int	oid_lookup(Ints* o, Ints** tab);
14246d884bbSDavid du Colombier static void	freevalfields(Value* v);
14346d884bbSDavid du Colombier static mpint	*asn1mpint(Elem *e);
14446d884bbSDavid du Colombier 
14546d884bbSDavid du Colombier 
14646d884bbSDavid du Colombier 
14746d884bbSDavid du Colombier #define TAG_MASK 0x1F
14846d884bbSDavid du Colombier #define CONSTR_MASK 0x20
14946d884bbSDavid du Colombier #define CLASS_MASK 0xC0
15046d884bbSDavid du Colombier #define MAXOBJIDLEN 20
15146d884bbSDavid du Colombier 
15246d884bbSDavid du Colombier static int ber_decode(uchar** pp, uchar* pend, Elem* pelem);
15346d884bbSDavid du Colombier static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr);
15446d884bbSDavid du Colombier static int length_decode(uchar** pp, uchar* pend, int* plength);
15546d884bbSDavid du Colombier static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval);
15646d884bbSDavid du Colombier static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint);
15746d884bbSDavid du Colombier static int uint7_decode(uchar** pp, uchar* pend, int* pint);
15846d884bbSDavid du Colombier static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes);
15946d884bbSDavid du Colombier static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist);
16046d884bbSDavid du Colombier static int enc(uchar** pp, Elem e, int lenonly);
16146d884bbSDavid du Colombier static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly);
16246d884bbSDavid du Colombier static void uint7_enc(uchar** pp, int num, int lenonly);
16346d884bbSDavid du Colombier static void int_enc(uchar** pp, int num, int unsgned, int lenonly);
16446d884bbSDavid du Colombier 
16546d884bbSDavid du Colombier static void *
emalloc(int n)16646d884bbSDavid du Colombier emalloc(int n)
16746d884bbSDavid du Colombier {
16846d884bbSDavid du Colombier 	void *p;
16946d884bbSDavid du Colombier 	if(n==0)
17046d884bbSDavid du Colombier 		n=1;
17146d884bbSDavid du Colombier 	p = malloc(n);
17246d884bbSDavid du Colombier 	if(p == nil){
17346d884bbSDavid du Colombier 		exits("out of memory");
17446d884bbSDavid du Colombier 	}
17546d884bbSDavid du Colombier 	memset(p, 0, n);
17646d884bbSDavid du Colombier 	setmalloctag(p, getcallerpc(&n));
17746d884bbSDavid du Colombier 	return p;
17846d884bbSDavid du Colombier }
17946d884bbSDavid du Colombier 
18046d884bbSDavid du Colombier static char*
estrdup(char * s)18146d884bbSDavid du Colombier estrdup(char *s)
18246d884bbSDavid du Colombier {
18346d884bbSDavid du Colombier 	char *d, *d0;
18446d884bbSDavid du Colombier 
18546d884bbSDavid du Colombier 	if(!s)
18646d884bbSDavid du Colombier 		return 0;
18746d884bbSDavid du Colombier 	d = d0 = emalloc(strlen(s)+1);
18846d884bbSDavid du Colombier 	while(*d++ = *s++)
18946d884bbSDavid du Colombier 		;
19046d884bbSDavid du Colombier 	return d0;
19146d884bbSDavid du Colombier }
19246d884bbSDavid du Colombier 
19346d884bbSDavid du Colombier 
19446d884bbSDavid du Colombier /*
19546d884bbSDavid du Colombier  * Decode a[0..len] as a BER encoding of an ASN1 type.
19646d884bbSDavid du Colombier  * The return value is one of ASN_OK, etc.
19746d884bbSDavid du Colombier  * Depending on the error, the returned elem may or may not
19846d884bbSDavid du Colombier  * be nil.
19946d884bbSDavid du Colombier  */
20046d884bbSDavid du Colombier static int
decode(uchar * a,int alen,Elem * pelem)20146d884bbSDavid du Colombier decode(uchar* a, int alen, Elem* pelem)
20246d884bbSDavid du Colombier {
20346d884bbSDavid du Colombier 	uchar* p = a;
20446d884bbSDavid du Colombier 
20546d884bbSDavid du Colombier 	return  ber_decode(&p, &a[alen], pelem);
20646d884bbSDavid du Colombier }
20746d884bbSDavid du Colombier 
20846d884bbSDavid du Colombier /*
20946d884bbSDavid du Colombier  * Like decode, but continue decoding after first element
21046d884bbSDavid du Colombier  * of array ends.
21146d884bbSDavid du Colombier  */
21246d884bbSDavid du Colombier static int
decode_seq(uchar * a,int alen,Elist ** pelist)21346d884bbSDavid du Colombier decode_seq(uchar* a, int alen, Elist** pelist)
21446d884bbSDavid du Colombier {
21546d884bbSDavid du Colombier 	uchar* p = a;
21646d884bbSDavid du Colombier 
21746d884bbSDavid du Colombier 	return seq_decode(&p, &a[alen], -1, 1, pelist);
21846d884bbSDavid du Colombier }
21946d884bbSDavid du Colombier 
22046d884bbSDavid du Colombier /*
22146d884bbSDavid du Colombier  * Decode the whole array as a BER encoding of an ASN1 value,
22246d884bbSDavid du Colombier  * (i.e., the part after the tag and length).
22346d884bbSDavid du Colombier  * Assume the value is encoded as universal tag "kind".
22446d884bbSDavid du Colombier  * The constr arg is 1 if the value is constructed, 0 if primitive.
22546d884bbSDavid du Colombier  * If there's an error, the return string will contain the error.
22646d884bbSDavid du Colombier  * Depending on the error, the returned value may or may not
22746d884bbSDavid du Colombier  * be nil.
22846d884bbSDavid du Colombier  */
22946d884bbSDavid du Colombier static int
decode_value(uchar * a,int alen,int kind,int isconstr,Value * pval)23046d884bbSDavid du Colombier decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval)
23146d884bbSDavid du Colombier {
23246d884bbSDavid du Colombier 	uchar* p = a;
23346d884bbSDavid du Colombier 
23446d884bbSDavid du Colombier 	return value_decode(&p, &a[alen], alen, kind, isconstr, pval);
23546d884bbSDavid du Colombier }
23646d884bbSDavid du Colombier 
23746d884bbSDavid du Colombier /*
23846d884bbSDavid du Colombier  * All of the following decoding routines take arguments:
23946d884bbSDavid du Colombier  *	uchar **pp;
24046d884bbSDavid du Colombier  *	uchar *pend;
24146d884bbSDavid du Colombier  * Where parsing is supposed to start at **pp, and when parsing
24246d884bbSDavid du Colombier  * is done, *pp is updated to point at next char to be parsed.
24346d884bbSDavid du Colombier  * The pend pointer is just past end of string; an error should
24446d884bbSDavid du Colombier  * be returned parsing hasn't finished by then.
24546d884bbSDavid du Colombier  *
24646d884bbSDavid du Colombier  * The returned int is ASN_OK if all went fine, else ASN_ESHORT, etc.
24746d884bbSDavid du Colombier  * The remaining argument(s) are pointers to where parsed entity goes.
24846d884bbSDavid du Colombier  */
24946d884bbSDavid du Colombier 
25046d884bbSDavid du Colombier /* Decode an ASN1 'Elem' (tag, length, value) */
25146d884bbSDavid du Colombier static int
ber_decode(uchar ** pp,uchar * pend,Elem * pelem)25246d884bbSDavid du Colombier ber_decode(uchar** pp, uchar* pend, Elem* pelem)
25346d884bbSDavid du Colombier {
25446d884bbSDavid du Colombier 	int err;
25546d884bbSDavid du Colombier 	int isconstr;
25646d884bbSDavid du Colombier 	int length;
25746d884bbSDavid du Colombier 	Tag tag;
25846d884bbSDavid du Colombier 	Value val;
25946d884bbSDavid du Colombier 
26046d884bbSDavid du Colombier 	err = tag_decode(pp, pend, &tag, &isconstr);
26146d884bbSDavid du Colombier 	if(err == ASN_OK) {
26246d884bbSDavid du Colombier 		err = length_decode(pp, pend, &length);
26346d884bbSDavid du Colombier 		if(err == ASN_OK) {
26446d884bbSDavid du Colombier 			if(tag.class == Universal) {
26546d884bbSDavid du Colombier 				err = value_decode(pp, pend, length, tag.num, isconstr, &val);
26646d884bbSDavid du Colombier 				if(val.tag == VSeq || val.tag == VSet)
26746d884bbSDavid du Colombier 					setmalloctag(val.u.seqval, getcallerpc(&pp));
26846d884bbSDavid du Colombier 			}else
26946d884bbSDavid du Colombier 				err = value_decode(pp, pend, length, OCTET_STRING, 0, &val);
27046d884bbSDavid du Colombier 			if(err == ASN_OK) {
27146d884bbSDavid du Colombier 				pelem->tag = tag;
27246d884bbSDavid du Colombier 				pelem->val = val;
27346d884bbSDavid du Colombier 			}
27446d884bbSDavid du Colombier 		}
27546d884bbSDavid du Colombier 	}
27646d884bbSDavid du Colombier 	return err;
27746d884bbSDavid du Colombier }
27846d884bbSDavid du Colombier 
27946d884bbSDavid du Colombier /* Decode a tag field */
28046d884bbSDavid du Colombier static int
tag_decode(uchar ** pp,uchar * pend,Tag * ptag,int * pisconstr)28146d884bbSDavid du Colombier tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr)
28246d884bbSDavid du Colombier {
28346d884bbSDavid du Colombier 	int err;
28446d884bbSDavid du Colombier 	int v;
28546d884bbSDavid du Colombier 	uchar* p;
28646d884bbSDavid du Colombier 
28746d884bbSDavid du Colombier 	err = ASN_OK;
28846d884bbSDavid du Colombier 	p = *pp;
28946d884bbSDavid du Colombier 	if(pend-p >= 2) {
29046d884bbSDavid du Colombier 		v = *p++;
29146d884bbSDavid du Colombier 		ptag->class = v&CLASS_MASK;
29246d884bbSDavid du Colombier 		if(v&CONSTR_MASK)
29346d884bbSDavid du Colombier 			*pisconstr = 1;
29446d884bbSDavid du Colombier 		else
29546d884bbSDavid du Colombier 			*pisconstr = 0;
29646d884bbSDavid du Colombier 		v &= TAG_MASK;
29746d884bbSDavid du Colombier 		if(v == TAG_MASK)
29846d884bbSDavid du Colombier 			err = uint7_decode(&p, pend, &v);
29946d884bbSDavid du Colombier 		ptag->num = v;
30046d884bbSDavid du Colombier 	}
30146d884bbSDavid du Colombier 	else
30246d884bbSDavid du Colombier 		err = ASN_ESHORT;
30346d884bbSDavid du Colombier 	*pp = p;
30446d884bbSDavid du Colombier 	return err;
30546d884bbSDavid du Colombier }
30646d884bbSDavid du Colombier 
30746d884bbSDavid du Colombier /* Decode a length field */
30846d884bbSDavid du Colombier static int
length_decode(uchar ** pp,uchar * pend,int * plength)30946d884bbSDavid du Colombier length_decode(uchar** pp, uchar* pend, int* plength)
31046d884bbSDavid du Colombier {
31146d884bbSDavid du Colombier 	int err;
31246d884bbSDavid du Colombier 	int num;
31346d884bbSDavid du Colombier 	int v;
31446d884bbSDavid du Colombier 	uchar* p;
31546d884bbSDavid du Colombier 
31646d884bbSDavid du Colombier 	err = ASN_OK;
31746d884bbSDavid du Colombier 	num = 0;
31846d884bbSDavid du Colombier 	p = *pp;
31946d884bbSDavid du Colombier 	if(p < pend) {
32046d884bbSDavid du Colombier 		v = *p++;
32146d884bbSDavid du Colombier 		if(v&0x80)
32246d884bbSDavid du Colombier 			err = int_decode(&p, pend, v&0x7F, 1, &num);
32346d884bbSDavid du Colombier 		else
32446d884bbSDavid du Colombier 			num = v;
32546d884bbSDavid du Colombier 	}
32646d884bbSDavid du Colombier 	else
32746d884bbSDavid du Colombier 		err = ASN_ESHORT;
32846d884bbSDavid du Colombier 	*pp = p;
32946d884bbSDavid du Colombier 	*plength = num;
33046d884bbSDavid du Colombier 	return err;
33146d884bbSDavid du Colombier }
33246d884bbSDavid du Colombier 
33346d884bbSDavid du Colombier /* Decode a value field  */
33446d884bbSDavid du Colombier static int
value_decode(uchar ** pp,uchar * pend,int length,int kind,int isconstr,Value * pval)33546d884bbSDavid du Colombier value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval)
33646d884bbSDavid du Colombier {
33746d884bbSDavid du Colombier 	int err;
33846d884bbSDavid du Colombier 	Bytes* va;
33946d884bbSDavid du Colombier 	int num;
34046d884bbSDavid du Colombier 	int bitsunused;
34146d884bbSDavid du Colombier 	int subids[MAXOBJIDLEN];
34246d884bbSDavid du Colombier 	int isubid;
34346d884bbSDavid du Colombier 	Elist*	vl;
34446d884bbSDavid du Colombier 	uchar* p;
34546d884bbSDavid du Colombier 	uchar* pe;
34646d884bbSDavid du Colombier 
34746d884bbSDavid du Colombier 	err = ASN_OK;
34846d884bbSDavid du Colombier 	p = *pp;
34946d884bbSDavid du Colombier 	if(length == -1) {	/* "indefinite" length spec */
35046d884bbSDavid du Colombier 		if(!isconstr)
35146d884bbSDavid du Colombier 			err = ASN_EINVAL;
35246d884bbSDavid du Colombier 	}
35346d884bbSDavid du Colombier 	else if(p + length > pend)
35446d884bbSDavid du Colombier 		err = ASN_EVALLEN;
35546d884bbSDavid du Colombier 	if(err != ASN_OK)
35646d884bbSDavid du Colombier 		return err;
35746d884bbSDavid du Colombier 
35846d884bbSDavid du Colombier 	switch(kind) {
35946d884bbSDavid du Colombier 	case 0:
36046d884bbSDavid du Colombier 		/* marker for end of indefinite constructions */
36146d884bbSDavid du Colombier 		if(length == 0)
36246d884bbSDavid du Colombier 			pval->tag = VNull;
36346d884bbSDavid du Colombier 		else
36446d884bbSDavid du Colombier 			err = ASN_EINVAL;
36546d884bbSDavid du Colombier 		break;
36646d884bbSDavid du Colombier 
36746d884bbSDavid du Colombier 	case BOOLEAN:
36846d884bbSDavid du Colombier 		if(isconstr)
36946d884bbSDavid du Colombier 			err = ASN_ECONSTR;
37046d884bbSDavid du Colombier 		else if(length != 1)
37146d884bbSDavid du Colombier 			err = ASN_EVALLEN;
37246d884bbSDavid du Colombier 		else {
37346d884bbSDavid du Colombier 			pval->tag = VBool;
37446d884bbSDavid du Colombier 			pval->u.boolval = (*p++ != 0);
37546d884bbSDavid du Colombier 		}
37646d884bbSDavid du Colombier 		break;
37746d884bbSDavid du Colombier 
37846d884bbSDavid du Colombier 	case INTEGER:
37946d884bbSDavid du Colombier 	case ENUMERATED:
38046d884bbSDavid du Colombier 		if(isconstr)
38146d884bbSDavid du Colombier 			err = ASN_ECONSTR;
38246d884bbSDavid du Colombier 		else if(length <= 4) {
38346d884bbSDavid du Colombier 			err = int_decode(&p, pend, length, 0, &num);
38446d884bbSDavid du Colombier 			if(err == ASN_OK) {
38546d884bbSDavid du Colombier 				pval->tag = VInt;
38646d884bbSDavid du Colombier 				pval->u.intval = num;
38746d884bbSDavid du Colombier 			}
38846d884bbSDavid du Colombier 		}
38946d884bbSDavid du Colombier 		else {
39046d884bbSDavid du Colombier 			pval->tag = VBigInt;
39146d884bbSDavid du Colombier 			pval->u.bigintval = makebytes(p, length);
39246d884bbSDavid du Colombier 			p += length;
39346d884bbSDavid du Colombier 		}
39446d884bbSDavid du Colombier 		break;
39546d884bbSDavid du Colombier 
39646d884bbSDavid du Colombier 	case BIT_STRING:
39746d884bbSDavid du Colombier 		pval->tag = VBitString;
39846d884bbSDavid du Colombier 		if(isconstr) {
39946d884bbSDavid du Colombier 			if(length == -1 && p + 2 <= pend && *p == 0 && *(p+1) ==0) {
40046d884bbSDavid du Colombier 				pval->u.bitstringval = makebits(0, 0, 0);
40146d884bbSDavid du Colombier 				p += 2;
40246d884bbSDavid du Colombier 			}
40346d884bbSDavid du Colombier 			else
40446d884bbSDavid du Colombier 				/* TODO: recurse and concat results */
40546d884bbSDavid du Colombier 				err = ASN_EUNIMPL;
40646d884bbSDavid du Colombier 		}
40746d884bbSDavid du Colombier 		else {
40846d884bbSDavid du Colombier 			if(length < 2) {
40946d884bbSDavid du Colombier 				if(length == 1 && *p == 0) {
41046d884bbSDavid du Colombier 					pval->u.bitstringval = makebits(0, 0, 0);
41146d884bbSDavid du Colombier 					p++;
41246d884bbSDavid du Colombier 				}
41346d884bbSDavid du Colombier 				else
41446d884bbSDavid du Colombier 					err = ASN_EINVAL;
41546d884bbSDavid du Colombier 			}
41646d884bbSDavid du Colombier 			else {
41746d884bbSDavid du Colombier 				bitsunused = *p;
41846d884bbSDavid du Colombier 				if(bitsunused > 7)
41946d884bbSDavid du Colombier 					err = ASN_EINVAL;
42046d884bbSDavid du Colombier 				else if(length > 0x0FFFFFFF)
42146d884bbSDavid du Colombier 					err = ASN_ETOOBIG;
42246d884bbSDavid du Colombier 				else {
42346d884bbSDavid du Colombier 					pval->u.bitstringval = makebits(p+1, length-1, bitsunused);
42446d884bbSDavid du Colombier 					p += length;
42546d884bbSDavid du Colombier 				}
42646d884bbSDavid du Colombier 			}
42746d884bbSDavid du Colombier 		}
42846d884bbSDavid du Colombier 		break;
42946d884bbSDavid du Colombier 
43046d884bbSDavid du Colombier 	case OCTET_STRING:
43146d884bbSDavid du Colombier 	case ObjectDescriptor:
43246d884bbSDavid du Colombier 		err = octet_decode(&p, pend, length, isconstr, &va);
43346d884bbSDavid du Colombier 		if(err == ASN_OK) {
43446d884bbSDavid du Colombier 			pval->tag = VOctets;
43546d884bbSDavid du Colombier 			pval->u.octetsval = va;
43646d884bbSDavid du Colombier 		}
43746d884bbSDavid du Colombier 		break;
43846d884bbSDavid du Colombier 
43946d884bbSDavid du Colombier 	case NULLTAG:
44046d884bbSDavid du Colombier 		if(isconstr)
44146d884bbSDavid du Colombier 			err = ASN_ECONSTR;
44246d884bbSDavid du Colombier 		else if(length != 0)
44346d884bbSDavid du Colombier 			err = ASN_EVALLEN;
44446d884bbSDavid du Colombier 		else
44546d884bbSDavid du Colombier 			pval->tag = VNull;
44646d884bbSDavid du Colombier 		break;
44746d884bbSDavid du Colombier 
44846d884bbSDavid du Colombier 	case OBJECT_ID:
44946d884bbSDavid du Colombier 		if(isconstr)
45046d884bbSDavid du Colombier 			err = ASN_ECONSTR;
45146d884bbSDavid du Colombier 		else if(length == 0)
45246d884bbSDavid du Colombier 			err = ASN_EVALLEN;
45346d884bbSDavid du Colombier 		else {
45446d884bbSDavid du Colombier 			isubid = 0;
45546d884bbSDavid du Colombier 			pe = p+length;
45646d884bbSDavid du Colombier 			while(p < pe && isubid < MAXOBJIDLEN) {
45746d884bbSDavid du Colombier 				err = uint7_decode(&p, pend, &num);
45846d884bbSDavid du Colombier 				if(err != ASN_OK)
45946d884bbSDavid du Colombier 					break;
46046d884bbSDavid du Colombier 				if(isubid == 0) {
46146d884bbSDavid du Colombier 					subids[isubid++] = num / 40;
46246d884bbSDavid du Colombier 					subids[isubid++] = num % 40;
46346d884bbSDavid du Colombier 				}
46446d884bbSDavid du Colombier 				else
46546d884bbSDavid du Colombier 					subids[isubid++] = num;
46646d884bbSDavid du Colombier 			}
46746d884bbSDavid du Colombier 			if(err == ASN_OK) {
46846d884bbSDavid du Colombier 				if(p != pe)
46946d884bbSDavid du Colombier 					err = ASN_EVALLEN;
47046d884bbSDavid du Colombier 				else {
47146d884bbSDavid du Colombier 					pval->tag = VObjId;
47246d884bbSDavid du Colombier 					pval->u.objidval = makeints(subids, isubid);
47346d884bbSDavid du Colombier 				}
47446d884bbSDavid du Colombier 			}
47546d884bbSDavid du Colombier 		}
47646d884bbSDavid du Colombier 		break;
47746d884bbSDavid du Colombier 
47846d884bbSDavid du Colombier 	case EXTERNAL:
47946d884bbSDavid du Colombier 	case EMBEDDED_PDV:
48046d884bbSDavid du Colombier 		/* TODO: parse this internally */
48146d884bbSDavid du Colombier 		if(p+length > pend)
48246d884bbSDavid du Colombier 			err = ASN_EVALLEN;
48346d884bbSDavid du Colombier 		else {
48446d884bbSDavid du Colombier 			pval->tag = VOther;
48546d884bbSDavid du Colombier 			pval->u.otherval = makebytes(p, length);
48646d884bbSDavid du Colombier 			p += length;
48746d884bbSDavid du Colombier 		}
48846d884bbSDavid du Colombier 		break;
48946d884bbSDavid du Colombier 
49046d884bbSDavid du Colombier 	case REAL:
49146d884bbSDavid du Colombier 		/* Let the application decode */
49246d884bbSDavid du Colombier 		if(isconstr)
49346d884bbSDavid du Colombier 			err = ASN_ECONSTR;
49446d884bbSDavid du Colombier 		else if(p+length > pend)
49546d884bbSDavid du Colombier 			err = ASN_EVALLEN;
49646d884bbSDavid du Colombier 		else {
49746d884bbSDavid du Colombier 			pval->tag = VReal;
49846d884bbSDavid du Colombier 			pval->u.realval = makebytes(p, length);
49946d884bbSDavid du Colombier 			p += length;
50046d884bbSDavid du Colombier 		}
50146d884bbSDavid du Colombier 		break;
50246d884bbSDavid du Colombier 
50346d884bbSDavid du Colombier 	case SEQUENCE:
50446d884bbSDavid du Colombier 		err = seq_decode(&p, pend, length, isconstr, &vl);
50546d884bbSDavid du Colombier 		setmalloctag(vl, getcallerpc(&pp));
50646d884bbSDavid du Colombier 		if(err == ASN_OK) {
50746d884bbSDavid du Colombier 			pval->tag = VSeq ;
50846d884bbSDavid du Colombier 			pval->u.seqval = vl;
50946d884bbSDavid du Colombier 		}
51046d884bbSDavid du Colombier 		break;
51146d884bbSDavid du Colombier 
51246d884bbSDavid du Colombier 	case SETOF:
51346d884bbSDavid du Colombier 		err = seq_decode(&p, pend, length, isconstr, &vl);
51446d884bbSDavid du Colombier 		setmalloctag(vl, getcallerpc(&pp));
51546d884bbSDavid du Colombier 		if(err == ASN_OK) {
51646d884bbSDavid du Colombier 			pval->tag = VSet;
51746d884bbSDavid du Colombier 			pval->u.setval = vl;
51846d884bbSDavid du Colombier 		}
51946d884bbSDavid du Colombier 		break;
52046d884bbSDavid du Colombier 	case UTF8String:
52146d884bbSDavid du Colombier 	case NumericString:
52246d884bbSDavid du Colombier 	case PrintableString:
52346d884bbSDavid du Colombier 	case TeletexString:
52446d884bbSDavid du Colombier 	case VideotexString:
52546d884bbSDavid du Colombier 	case IA5String:
52646d884bbSDavid du Colombier 	case UTCTime:
52746d884bbSDavid du Colombier 	case GeneralizedTime:
52846d884bbSDavid du Colombier 	case GraphicString:
52946d884bbSDavid du Colombier 	case VisibleString:
53046d884bbSDavid du Colombier 	case GeneralString:
53146d884bbSDavid du Colombier 	case UniversalString:
53246d884bbSDavid du Colombier 	case BMPString:
53346d884bbSDavid du Colombier 		/* TODO: figure out when character set conversion is necessary */
53446d884bbSDavid du Colombier 		err = octet_decode(&p, pend, length, isconstr, &va);
53546d884bbSDavid du Colombier 		if(err == ASN_OK) {
53646d884bbSDavid du Colombier 			pval->tag = VString;
53746d884bbSDavid du Colombier 			pval->u.stringval = (char*)emalloc(va->len+1);
53846d884bbSDavid du Colombier 			memmove(pval->u.stringval, va->data, va->len);
53946d884bbSDavid du Colombier 			pval->u.stringval[va->len] = 0;
54046d884bbSDavid du Colombier 			free(va);
54146d884bbSDavid du Colombier 		}
54246d884bbSDavid du Colombier 		break;
54346d884bbSDavid du Colombier 
54446d884bbSDavid du Colombier 	default:
54546d884bbSDavid du Colombier 		if(p+length > pend)
54646d884bbSDavid du Colombier 			err = ASN_EVALLEN;
54746d884bbSDavid du Colombier 		else {
54846d884bbSDavid du Colombier 			pval->tag = VOther;
54946d884bbSDavid du Colombier 			pval->u.otherval = makebytes(p, length);
55046d884bbSDavid du Colombier 			p += length;
55146d884bbSDavid du Colombier 		}
55246d884bbSDavid du Colombier 		break;
55346d884bbSDavid du Colombier 	}
55446d884bbSDavid du Colombier 	*pp = p;
55546d884bbSDavid du Colombier 	return err;
55646d884bbSDavid du Colombier }
55746d884bbSDavid du Colombier 
55846d884bbSDavid du Colombier /*
55946d884bbSDavid du Colombier  * Decode an int in format where count bytes are
56046d884bbSDavid du Colombier  * concatenated to form value.
56146d884bbSDavid du Colombier  * Although ASN1 allows any size integer, we return
56246d884bbSDavid du Colombier  * an error if the result doesn't fit in a 32-bit int.
56346d884bbSDavid du Colombier  * If unsgned is not set, make sure to propagate sign bit.
56446d884bbSDavid du Colombier  */
56546d884bbSDavid du Colombier static int
int_decode(uchar ** pp,uchar * pend,int count,int unsgned,int * pint)56646d884bbSDavid du Colombier int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint)
56746d884bbSDavid du Colombier {
56846d884bbSDavid du Colombier 	int err;
56946d884bbSDavid du Colombier 	int num;
57046d884bbSDavid du Colombier 	uchar* p;
57146d884bbSDavid du Colombier 
57246d884bbSDavid du Colombier 	p = *pp;
57346d884bbSDavid du Colombier 	err = ASN_OK;
57446d884bbSDavid du Colombier 	num = 0;
57546d884bbSDavid du Colombier 	if(p+count <= pend) {
57646d884bbSDavid du Colombier 		if((count > 4) || (unsgned && count == 4 && (*p&0x80)))
57746d884bbSDavid du Colombier 			err = ASN_ETOOBIG;
57846d884bbSDavid du Colombier 		else {
57946d884bbSDavid du Colombier 			if(!unsgned && count > 0 && count < 4 && (*p&0x80))
58046d884bbSDavid du Colombier 				num = -1;	/* set all bits, initially */
58146d884bbSDavid du Colombier 			while(count--)
58246d884bbSDavid du Colombier 				num = (num << 8)|(*p++);
58346d884bbSDavid du Colombier 		}
58446d884bbSDavid du Colombier 	}
58546d884bbSDavid du Colombier 	else
58646d884bbSDavid du Colombier 		err = ASN_ESHORT;
58746d884bbSDavid du Colombier 	*pint = num;
58846d884bbSDavid du Colombier 	*pp = p;
58946d884bbSDavid du Colombier 	return err;
59046d884bbSDavid du Colombier }
59146d884bbSDavid du Colombier 
59246d884bbSDavid du Colombier /*
59346d884bbSDavid du Colombier  * Decode an unsigned int in format where each
59446d884bbSDavid du Colombier  * byte except last has high bit set, and remaining
59546d884bbSDavid du Colombier  * seven bits of each byte are concatenated to form value.
59646d884bbSDavid du Colombier  * Although ASN1 allows any size integer, we return
59746d884bbSDavid du Colombier  * an error if the result doesn't fit in a 32 bit int.
59846d884bbSDavid du Colombier  */
59946d884bbSDavid du Colombier static int
uint7_decode(uchar ** pp,uchar * pend,int * pint)60046d884bbSDavid du Colombier uint7_decode(uchar** pp, uchar* pend, int* pint)
60146d884bbSDavid du Colombier {
60246d884bbSDavid du Colombier 	int err;
60346d884bbSDavid du Colombier 	int num;
60446d884bbSDavid du Colombier 	int more;
60546d884bbSDavid du Colombier 	int v;
60646d884bbSDavid du Colombier 	uchar* p;
60746d884bbSDavid du Colombier 
60846d884bbSDavid du Colombier 	p = *pp;
60946d884bbSDavid du Colombier 	err = ASN_OK;
61046d884bbSDavid du Colombier 	num = 0;
61146d884bbSDavid du Colombier 	more = 1;
61246d884bbSDavid du Colombier 	while(more && p < pend) {
61346d884bbSDavid du Colombier 		v = *p++;
61446d884bbSDavid du Colombier 		if(num&0x7F000000) {
61546d884bbSDavid du Colombier 			err = ASN_ETOOBIG;
61646d884bbSDavid du Colombier 			break;
61746d884bbSDavid du Colombier 		}
61846d884bbSDavid du Colombier 		num <<= 7;
61946d884bbSDavid du Colombier 		more = v&0x80;
62046d884bbSDavid du Colombier 		num |= (v&0x7F);
62146d884bbSDavid du Colombier 	}
62246d884bbSDavid du Colombier 	if(p == pend)
62346d884bbSDavid du Colombier 		err = ASN_ESHORT;
62446d884bbSDavid du Colombier 	*pint = num;
62546d884bbSDavid du Colombier 	*pp = p;
62646d884bbSDavid du Colombier 	return err;
62746d884bbSDavid du Colombier }
62846d884bbSDavid du Colombier 
62946d884bbSDavid du Colombier /*
63046d884bbSDavid du Colombier  * Decode an octet string, recursively if isconstr.
63146d884bbSDavid du Colombier  * We've already checked that length==-1 implies isconstr==1,
63246d884bbSDavid du Colombier  * and otherwise that specified length fits within (*pp..pend)
63346d884bbSDavid du Colombier  */
63446d884bbSDavid du Colombier static int
octet_decode(uchar ** pp,uchar * pend,int length,int isconstr,Bytes ** pbytes)63546d884bbSDavid du Colombier octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes)
63646d884bbSDavid du Colombier {
63746d884bbSDavid du Colombier 	int err;
63846d884bbSDavid du Colombier 	uchar* p;
63946d884bbSDavid du Colombier 	Bytes* ans;
64046d884bbSDavid du Colombier 	Bytes* newans;
64146d884bbSDavid du Colombier 	uchar* pstart;
64246d884bbSDavid du Colombier 	uchar* pold;
64346d884bbSDavid du Colombier 	Elem	elem;
64446d884bbSDavid du Colombier 
64546d884bbSDavid du Colombier 	err = ASN_OK;
64646d884bbSDavid du Colombier 	p = *pp;
64746d884bbSDavid du Colombier 	ans = nil;
64846d884bbSDavid du Colombier 	if(length >= 0 && !isconstr) {
64946d884bbSDavid du Colombier 		ans = makebytes(p, length);
65046d884bbSDavid du Colombier 		p += length;
65146d884bbSDavid du Colombier 	}
65246d884bbSDavid du Colombier 	else {
65346d884bbSDavid du Colombier 		/* constructed, either definite or indefinite length */
65446d884bbSDavid du Colombier 		pstart = p;
65546d884bbSDavid du Colombier 		for(;;) {
65646d884bbSDavid du Colombier 			if(length >= 0 && p >= pstart + length) {
65746d884bbSDavid du Colombier 				if(p != pstart + length)
65846d884bbSDavid du Colombier 					err = ASN_EVALLEN;
65946d884bbSDavid du Colombier 				break;
66046d884bbSDavid du Colombier 			}
66146d884bbSDavid du Colombier 			pold = p;
66246d884bbSDavid du Colombier 			err = ber_decode(&p, pend, &elem);
66346d884bbSDavid du Colombier 			if(err != ASN_OK)
66446d884bbSDavid du Colombier 				break;
66546d884bbSDavid du Colombier 			switch(elem.val.tag) {
66646d884bbSDavid du Colombier 			case VOctets:
66746d884bbSDavid du Colombier 				newans = catbytes(ans, elem.val.u.octetsval);
66846d884bbSDavid du Colombier 				freebytes(ans);
66946d884bbSDavid du Colombier 				ans = newans;
67046d884bbSDavid du Colombier 				break;
67146d884bbSDavid du Colombier 
67246d884bbSDavid du Colombier 			case VEOC:
67346d884bbSDavid du Colombier 				if(length != -1) {
67446d884bbSDavid du Colombier 					p = pold;
67546d884bbSDavid du Colombier 					err = ASN_EINVAL;
67646d884bbSDavid du Colombier 				}
67746d884bbSDavid du Colombier 				goto cloop_done;
67846d884bbSDavid du Colombier 
67946d884bbSDavid du Colombier 			default:
68046d884bbSDavid du Colombier 				p = pold;
68146d884bbSDavid du Colombier 				err = ASN_EINVAL;
68246d884bbSDavid du Colombier 				goto cloop_done;
68346d884bbSDavid du Colombier 			}
68446d884bbSDavid du Colombier 		}
68546d884bbSDavid du Colombier cloop_done:
68646d884bbSDavid du Colombier 		;
68746d884bbSDavid du Colombier 	}
68846d884bbSDavid du Colombier 	*pp = p;
68946d884bbSDavid du Colombier 	*pbytes = ans;
69046d884bbSDavid du Colombier 	return err;
69146d884bbSDavid du Colombier }
69246d884bbSDavid du Colombier 
69346d884bbSDavid du Colombier /*
69446d884bbSDavid du Colombier  * Decode a sequence or set.
69546d884bbSDavid du Colombier  * We've already checked that length==-1 implies isconstr==1,
69646d884bbSDavid du Colombier  * and otherwise that specified length fits within (*p..pend)
69746d884bbSDavid du Colombier  */
69846d884bbSDavid du Colombier static int
seq_decode(uchar ** pp,uchar * pend,int length,int isconstr,Elist ** pelist)69946d884bbSDavid du Colombier seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist)
70046d884bbSDavid du Colombier {
70146d884bbSDavid du Colombier 	int err;
70246d884bbSDavid du Colombier 	uchar* p;
70346d884bbSDavid du Colombier 	uchar* pstart;
70446d884bbSDavid du Colombier 	uchar* pold;
70546d884bbSDavid du Colombier 	Elist* ans;
70646d884bbSDavid du Colombier 	Elem elem;
70746d884bbSDavid du Colombier 	Elist* lve;
70846d884bbSDavid du Colombier 	Elist* lveold;
70946d884bbSDavid du Colombier 
71046d884bbSDavid du Colombier 	err = ASN_OK;
71146d884bbSDavid du Colombier 	ans = nil;
71246d884bbSDavid du Colombier 	p = *pp;
71346d884bbSDavid du Colombier 	if(!isconstr)
71446d884bbSDavid du Colombier 		err = ASN_EPRIM;
71546d884bbSDavid du Colombier 	else {
71646d884bbSDavid du Colombier 		/* constructed, either definite or indefinite length */
71746d884bbSDavid du Colombier 		lve = nil;
71846d884bbSDavid du Colombier 		pstart = p;
71946d884bbSDavid du Colombier 		for(;;) {
72046d884bbSDavid du Colombier 			if(length >= 0 && p >= pstart + length) {
72146d884bbSDavid du Colombier 				if(p != pstart + length)
72246d884bbSDavid du Colombier 					err = ASN_EVALLEN;
72346d884bbSDavid du Colombier 				break;
72446d884bbSDavid du Colombier 			}
72546d884bbSDavid du Colombier 			pold = p;
72646d884bbSDavid du Colombier 			err = ber_decode(&p, pend, &elem);
72746d884bbSDavid du Colombier 			if(err != ASN_OK)
72846d884bbSDavid du Colombier 				break;
72946d884bbSDavid du Colombier 			if(elem.val.tag == VEOC) {
73046d884bbSDavid du Colombier 				if(length != -1) {
73146d884bbSDavid du Colombier 					p = pold;
73246d884bbSDavid du Colombier 					err = ASN_EINVAL;
73346d884bbSDavid du Colombier 				}
73446d884bbSDavid du Colombier 				break;
73546d884bbSDavid du Colombier 			}
73646d884bbSDavid du Colombier 			else
73746d884bbSDavid du Colombier 				lve = mkel(elem, lve);
73846d884bbSDavid du Colombier 		}
73946d884bbSDavid du Colombier 		if(err == ASN_OK) {
74046d884bbSDavid du Colombier 			/* reverse back to original order */
74146d884bbSDavid du Colombier 			while(lve != nil) {
74246d884bbSDavid du Colombier 				lveold = lve;
74346d884bbSDavid du Colombier 				lve = lve->tl;
74446d884bbSDavid du Colombier 				lveold->tl = ans;
74546d884bbSDavid du Colombier 				ans = lveold;
74646d884bbSDavid du Colombier 			}
74746d884bbSDavid du Colombier 		}
74846d884bbSDavid du Colombier 	}
74946d884bbSDavid du Colombier 	*pp = p;
75046d884bbSDavid du Colombier 	*pelist = ans;
75146d884bbSDavid du Colombier 	setmalloctag(ans, getcallerpc(&pp));
75246d884bbSDavid du Colombier 	return err;
75346d884bbSDavid du Colombier }
75446d884bbSDavid du Colombier 
75546d884bbSDavid du Colombier /*
75646d884bbSDavid du Colombier  * Encode e by BER rules, putting answer in *pbytes.
75746d884bbSDavid du Colombier  * This is done by first calling enc with lenonly==1
75846d884bbSDavid du Colombier  * to get the length of the needed buffer,
75946d884bbSDavid du Colombier  * then allocating the buffer and using enc again to fill it up.
76046d884bbSDavid du Colombier  */
76146d884bbSDavid du Colombier static int
encode(Elem e,Bytes ** pbytes)76246d884bbSDavid du Colombier encode(Elem e, Bytes** pbytes)
76346d884bbSDavid du Colombier {
76446d884bbSDavid du Colombier 	uchar* p;
76546d884bbSDavid du Colombier 	Bytes* ans;
76646d884bbSDavid du Colombier 	int err;
76746d884bbSDavid du Colombier 	uchar uc;
76846d884bbSDavid du Colombier 
76946d884bbSDavid du Colombier 	p = &uc;
77046d884bbSDavid du Colombier 	err = enc(&p, e, 1);
77146d884bbSDavid du Colombier 	if(err == ASN_OK) {
77246d884bbSDavid du Colombier 		ans = newbytes(p-&uc);
77346d884bbSDavid du Colombier 		p = ans->data;
77446d884bbSDavid du Colombier 		err = enc(&p, e, 0);
77546d884bbSDavid du Colombier 		*pbytes = ans;
77646d884bbSDavid du Colombier 	}
77746d884bbSDavid du Colombier 	return err;
77846d884bbSDavid du Colombier }
77946d884bbSDavid du Colombier 
78046d884bbSDavid du Colombier /*
78146d884bbSDavid du Colombier  * The various enc functions take a pointer to a pointer
78246d884bbSDavid du Colombier  * into a buffer, and encode their entity starting there,
78346d884bbSDavid du Colombier  * updating the pointer afterwards.
78446d884bbSDavid du Colombier  * If lenonly is 1, only the pointer update is done,
78546d884bbSDavid du Colombier  * allowing enc to be called first to calculate the needed
78646d884bbSDavid du Colombier  * buffer length.
78746d884bbSDavid du Colombier  * If lenonly is 0, it is assumed that the answer will fit.
78846d884bbSDavid du Colombier  */
78946d884bbSDavid du Colombier 
79046d884bbSDavid du Colombier static int
enc(uchar ** pp,Elem e,int lenonly)79146d884bbSDavid du Colombier enc(uchar** pp, Elem e, int lenonly)
79246d884bbSDavid du Colombier {
79346d884bbSDavid du Colombier 	int err;
79446d884bbSDavid du Colombier 	int vlen;
79546d884bbSDavid du Colombier 	int constr;
79646d884bbSDavid du Colombier 	Tag tag;
79746d884bbSDavid du Colombier 	int v;
79846d884bbSDavid du Colombier 	int ilen;
79946d884bbSDavid du Colombier 	uchar* p;
80046d884bbSDavid du Colombier 	uchar* psave;
80146d884bbSDavid du Colombier 
80246d884bbSDavid du Colombier 	p = *pp;
80346d884bbSDavid du Colombier 	err = val_enc(&p, e, &constr, 1);
80446d884bbSDavid du Colombier 	if(err != ASN_OK)
80546d884bbSDavid du Colombier 		return err;
80646d884bbSDavid du Colombier 	vlen = p - *pp;
80746d884bbSDavid du Colombier 	p = *pp;
80846d884bbSDavid du Colombier 	tag = e.tag;
80946d884bbSDavid du Colombier 	v = tag.class|constr;
81046d884bbSDavid du Colombier 	if(tag.num < 31) {
81146d884bbSDavid du Colombier 		if(!lenonly)
81246d884bbSDavid du Colombier 			*p = (v|tag.num);
81346d884bbSDavid du Colombier 		p++;
81446d884bbSDavid du Colombier 	}
81546d884bbSDavid du Colombier 	else {
81646d884bbSDavid du Colombier 		if(!lenonly)
81746d884bbSDavid du Colombier 			*p = (v|31);
81846d884bbSDavid du Colombier 		p++;
81946d884bbSDavid du Colombier 		if(tag.num < 0)
82046d884bbSDavid du Colombier 			return ASN_EINVAL;
82146d884bbSDavid du Colombier 		uint7_enc(&p, tag.num, lenonly);
82246d884bbSDavid du Colombier 	}
82346d884bbSDavid du Colombier 	if(vlen < 0x80) {
82446d884bbSDavid du Colombier 		if(!lenonly)
82546d884bbSDavid du Colombier 			*p = vlen;
82646d884bbSDavid du Colombier 		p++;
82746d884bbSDavid du Colombier 	}
82846d884bbSDavid du Colombier 	else {
82946d884bbSDavid du Colombier 		psave = p;
83046d884bbSDavid du Colombier 		int_enc(&p, vlen, 1, 1);
83146d884bbSDavid du Colombier 		ilen = p-psave;
83246d884bbSDavid du Colombier 		p = psave;
83346d884bbSDavid du Colombier 		if(!lenonly) {
83446d884bbSDavid du Colombier 			*p++ = (0x80 | ilen);
83546d884bbSDavid du Colombier 			int_enc(&p, vlen, 1, 0);
83646d884bbSDavid du Colombier 		}
83746d884bbSDavid du Colombier 		else
83846d884bbSDavid du Colombier 			p += 1 + ilen;
83946d884bbSDavid du Colombier 	}
84046d884bbSDavid du Colombier 	if(!lenonly)
84146d884bbSDavid du Colombier 		val_enc(&p, e, &constr, 0);
84246d884bbSDavid du Colombier 	else
84346d884bbSDavid du Colombier 		p += vlen;
84446d884bbSDavid du Colombier 	*pp = p;
84546d884bbSDavid du Colombier 	return err;
84646d884bbSDavid du Colombier }
84746d884bbSDavid du Colombier 
84846d884bbSDavid du Colombier static int
val_enc(uchar ** pp,Elem e,int * pconstr,int lenonly)84946d884bbSDavid du Colombier val_enc(uchar** pp, Elem e, int *pconstr, int lenonly)
85046d884bbSDavid du Colombier {
85146d884bbSDavid du Colombier 	int err;
85246d884bbSDavid du Colombier 	uchar* p;
85346d884bbSDavid du Colombier 	int kind;
85446d884bbSDavid du Colombier 	int cl;
85546d884bbSDavid du Colombier 	int v;
85646d884bbSDavid du Colombier 	Bytes* bb = nil;
85746d884bbSDavid du Colombier 	Bits* bits;
85846d884bbSDavid du Colombier 	Ints* oid;
85946d884bbSDavid du Colombier 	int k;
86046d884bbSDavid du Colombier 	Elist* el;
86146d884bbSDavid du Colombier 	char* s;
86246d884bbSDavid du Colombier 
86346d884bbSDavid du Colombier 	p = *pp;
86446d884bbSDavid du Colombier 	err = ASN_OK;
86546d884bbSDavid du Colombier 	kind = e.tag.num;
86646d884bbSDavid du Colombier 	cl = e.tag.class;
86746d884bbSDavid du Colombier 	*pconstr = 0;
86846d884bbSDavid du Colombier 	if(cl != Universal) {
86946d884bbSDavid du Colombier 		switch(e.val.tag) {
87046d884bbSDavid du Colombier 		case VBool:
87146d884bbSDavid du Colombier 			kind = BOOLEAN;
87246d884bbSDavid du Colombier 			break;
87346d884bbSDavid du Colombier 		case VInt:
87446d884bbSDavid du Colombier 			kind = INTEGER;
87546d884bbSDavid du Colombier 			break;
87646d884bbSDavid du Colombier 		case VBigInt:
87746d884bbSDavid du Colombier 			kind = INTEGER;
87846d884bbSDavid du Colombier 			break;
87946d884bbSDavid du Colombier 		case VOctets:
88046d884bbSDavid du Colombier 			kind = OCTET_STRING;
88146d884bbSDavid du Colombier 			break;
88246d884bbSDavid du Colombier 		case VReal:
88346d884bbSDavid du Colombier 			kind = REAL;
88446d884bbSDavid du Colombier 			break;
88546d884bbSDavid du Colombier 		case VOther:
88646d884bbSDavid du Colombier 			kind = OCTET_STRING;
88746d884bbSDavid du Colombier 			break;
88846d884bbSDavid du Colombier 		case VBitString:
88946d884bbSDavid du Colombier 			kind = BIT_STRING;
89046d884bbSDavid du Colombier 			break;
89146d884bbSDavid du Colombier 		case VNull:
89246d884bbSDavid du Colombier 			kind = NULLTAG;
89346d884bbSDavid du Colombier 			break;
89446d884bbSDavid du Colombier 		case VObjId:
89546d884bbSDavid du Colombier 			kind = OBJECT_ID;
89646d884bbSDavid du Colombier 			break;
89746d884bbSDavid du Colombier 		case VString:
89846d884bbSDavid du Colombier 			kind = UniversalString;
89946d884bbSDavid du Colombier 			break;
90046d884bbSDavid du Colombier 		case VSeq:
90146d884bbSDavid du Colombier 			kind = SEQUENCE;
90246d884bbSDavid du Colombier 			break;
90346d884bbSDavid du Colombier 		case VSet:
90446d884bbSDavid du Colombier 			kind = SETOF;
90546d884bbSDavid du Colombier 			break;
90646d884bbSDavid du Colombier 		}
90746d884bbSDavid du Colombier 	}
90846d884bbSDavid du Colombier 	switch(kind) {
90946d884bbSDavid du Colombier 	case BOOLEAN:
91046d884bbSDavid du Colombier 		if(is_int(&e, &v)) {
91146d884bbSDavid du Colombier 			if(v != 0)
91246d884bbSDavid du Colombier 				v = 255;
91346d884bbSDavid du Colombier 			 int_enc(&p, v, 1, lenonly);
91446d884bbSDavid du Colombier 		}
91546d884bbSDavid du Colombier 		else
91646d884bbSDavid du Colombier 			err = ASN_EINVAL;
91746d884bbSDavid du Colombier 		break;
91846d884bbSDavid du Colombier 
91946d884bbSDavid du Colombier 	case INTEGER:
92046d884bbSDavid du Colombier 	case ENUMERATED:
92146d884bbSDavid du Colombier 		if(is_int(&e, &v))
92246d884bbSDavid du Colombier 			int_enc(&p, v, 0, lenonly);
92346d884bbSDavid du Colombier 		else {
92446d884bbSDavid du Colombier 			if(is_bigint(&e, &bb)) {
92546d884bbSDavid du Colombier 				if(!lenonly)
92646d884bbSDavid du Colombier 					memmove(p, bb->data, bb->len);
92746d884bbSDavid du Colombier 				p += bb->len;
92846d884bbSDavid du Colombier 			}
92946d884bbSDavid du Colombier 			else
93046d884bbSDavid du Colombier 				err = ASN_EINVAL;
93146d884bbSDavid du Colombier 		}
93246d884bbSDavid du Colombier 		break;
93346d884bbSDavid du Colombier 
93446d884bbSDavid du Colombier 	case BIT_STRING:
93546d884bbSDavid du Colombier 		if(is_bitstring(&e, &bits)) {
93646d884bbSDavid du Colombier 			if(bits->len == 0) {
93746d884bbSDavid du Colombier 				if(!lenonly)
93846d884bbSDavid du Colombier 					*p = 0;
93946d884bbSDavid du Colombier 				p++;
94046d884bbSDavid du Colombier 			}
94146d884bbSDavid du Colombier 			else {
94246d884bbSDavid du Colombier 				v = bits->unusedbits;
94346d884bbSDavid du Colombier 				if(v < 0 || v > 7)
94446d884bbSDavid du Colombier 					err = ASN_EINVAL;
94546d884bbSDavid du Colombier 				else {
94646d884bbSDavid du Colombier 					if(!lenonly) {
94746d884bbSDavid du Colombier 						*p = v;
94846d884bbSDavid du Colombier 						memmove(p+1, bits->data, bits->len);
94946d884bbSDavid du Colombier 					}
95046d884bbSDavid du Colombier 					p += 1 + bits->len;
95146d884bbSDavid du Colombier 				}
95246d884bbSDavid du Colombier 			}
95346d884bbSDavid du Colombier 		}
95446d884bbSDavid du Colombier 		else
95546d884bbSDavid du Colombier 			err = ASN_EINVAL;
95646d884bbSDavid du Colombier 		break;
95746d884bbSDavid du Colombier 
95846d884bbSDavid du Colombier 	case OCTET_STRING:
95946d884bbSDavid du Colombier 	case ObjectDescriptor:
96046d884bbSDavid du Colombier 	case EXTERNAL:
96146d884bbSDavid du Colombier 	case REAL:
96246d884bbSDavid du Colombier 	case EMBEDDED_PDV:
96346d884bbSDavid du Colombier 		bb = nil;
96446d884bbSDavid du Colombier 		switch(e.val.tag) {
96546d884bbSDavid du Colombier 		case VOctets:
96646d884bbSDavid du Colombier 			bb = e.val.u.octetsval;
96746d884bbSDavid du Colombier 			break;
96846d884bbSDavid du Colombier 		case VReal:
96946d884bbSDavid du Colombier 			bb = e.val.u.realval;
97046d884bbSDavid du Colombier 			break;
97146d884bbSDavid du Colombier 		case VOther:
97246d884bbSDavid du Colombier 			bb = e.val.u.otherval;
97346d884bbSDavid du Colombier 			break;
97446d884bbSDavid du Colombier 		}
97546d884bbSDavid du Colombier 		if(bb != nil) {
97646d884bbSDavid du Colombier 			if(!lenonly)
97746d884bbSDavid du Colombier 				memmove(p, bb->data, bb->len);
97846d884bbSDavid du Colombier 			p += bb->len;
97946d884bbSDavid du Colombier 		}
98046d884bbSDavid du Colombier 			else
98146d884bbSDavid du Colombier 				err = ASN_EINVAL;
98246d884bbSDavid du Colombier 		break;
98346d884bbSDavid du Colombier 
98446d884bbSDavid du Colombier 	case NULLTAG:
98546d884bbSDavid du Colombier 		break;
98646d884bbSDavid du Colombier 
98746d884bbSDavid du Colombier 	case OBJECT_ID:
98846d884bbSDavid du Colombier 		if(is_oid(&e, &oid)) {
98946d884bbSDavid du Colombier 			for(k = 0; k < oid->len; k++) {
99046d884bbSDavid du Colombier 				v = oid->data[k];
99146d884bbSDavid du Colombier 				if(k == 0) {
99246d884bbSDavid du Colombier 					v *= 40;
99346d884bbSDavid du Colombier 					if(oid->len > 1)
99446d884bbSDavid du Colombier 						v += oid->data[++k];
99546d884bbSDavid du Colombier 				}
99646d884bbSDavid du Colombier 				uint7_enc(&p, v, lenonly);
99746d884bbSDavid du Colombier 			}
99846d884bbSDavid du Colombier 		}
99946d884bbSDavid du Colombier 		else
100046d884bbSDavid du Colombier 			err = ASN_EINVAL;
100146d884bbSDavid du Colombier 		break;
100246d884bbSDavid du Colombier 
100346d884bbSDavid du Colombier 	case SEQUENCE:
100446d884bbSDavid du Colombier 	case SETOF:
100546d884bbSDavid du Colombier 		el = nil;
100646d884bbSDavid du Colombier 		if(e.val.tag == VSeq)
100746d884bbSDavid du Colombier 			el = e.val.u.seqval;
100846d884bbSDavid du Colombier 		else if(e.val.tag == VSet)
100946d884bbSDavid du Colombier 			el = e.val.u.setval;
101046d884bbSDavid du Colombier 		else
101146d884bbSDavid du Colombier 			err = ASN_EINVAL;
101246d884bbSDavid du Colombier 		if(el != nil) {
101346d884bbSDavid du Colombier 			*pconstr = CONSTR_MASK;
101446d884bbSDavid du Colombier 			for(; el != nil; el = el->tl) {
101546d884bbSDavid du Colombier 				err = enc(&p, el->hd, lenonly);
101646d884bbSDavid du Colombier 				if(err != ASN_OK)
101746d884bbSDavid du Colombier 					break;
101846d884bbSDavid du Colombier 			}
101946d884bbSDavid du Colombier 		}
102046d884bbSDavid du Colombier 		break;
102146d884bbSDavid du Colombier 
102246d884bbSDavid du Colombier 	case UTF8String:
102346d884bbSDavid du Colombier 	case NumericString:
102446d884bbSDavid du Colombier 	case PrintableString:
102546d884bbSDavid du Colombier 	case TeletexString:
102646d884bbSDavid du Colombier 	case VideotexString:
102746d884bbSDavid du Colombier 	case IA5String:
102846d884bbSDavid du Colombier 	case UTCTime:
102946d884bbSDavid du Colombier 	case GeneralizedTime:
103046d884bbSDavid du Colombier 	case GraphicString:
103146d884bbSDavid du Colombier 	case VisibleString:
103246d884bbSDavid du Colombier 	case GeneralString:
103346d884bbSDavid du Colombier 	case UniversalString:
103446d884bbSDavid du Colombier 	case BMPString:
103546d884bbSDavid du Colombier 		if(e.val.tag == VString) {
103646d884bbSDavid du Colombier 			s = e.val.u.stringval;
103746d884bbSDavid du Colombier 			if(s != nil) {
103846d884bbSDavid du Colombier 				v = strlen(s);
103946d884bbSDavid du Colombier 				if(!lenonly)
104046d884bbSDavid du Colombier 					memmove(p, s, v);
104146d884bbSDavid du Colombier 				p += v;
104246d884bbSDavid du Colombier 			}
104346d884bbSDavid du Colombier 		}
104446d884bbSDavid du Colombier 		else
104546d884bbSDavid du Colombier 			err = ASN_EINVAL;
104646d884bbSDavid du Colombier 		break;
104746d884bbSDavid du Colombier 
104846d884bbSDavid du Colombier 	default:
104946d884bbSDavid du Colombier 		err = ASN_EINVAL;
105046d884bbSDavid du Colombier 	}
105146d884bbSDavid du Colombier 	*pp = p;
105246d884bbSDavid du Colombier 	return err;
105346d884bbSDavid du Colombier }
105446d884bbSDavid du Colombier 
105546d884bbSDavid du Colombier /*
105646d884bbSDavid du Colombier  * Encode num as unsigned 7 bit values with top bit 1 on all bytes
105746d884bbSDavid du Colombier  * except last, only putting in bytes if !lenonly.
105846d884bbSDavid du Colombier  */
105946d884bbSDavid du Colombier static void
uint7_enc(uchar ** pp,int num,int lenonly)106046d884bbSDavid du Colombier uint7_enc(uchar** pp, int num, int lenonly)
106146d884bbSDavid du Colombier {
106246d884bbSDavid du Colombier 	int n;
106346d884bbSDavid du Colombier 	int v;
106446d884bbSDavid du Colombier 	int k;
106546d884bbSDavid du Colombier 	uchar* p;
106646d884bbSDavid du Colombier 
106746d884bbSDavid du Colombier 	p = *pp;
106846d884bbSDavid du Colombier 	n = 1;
106946d884bbSDavid du Colombier 	v = num >> 7;
107046d884bbSDavid du Colombier 	while(v > 0) {
107146d884bbSDavid du Colombier 		v >>= 7;
107246d884bbSDavid du Colombier 		n++;
107346d884bbSDavid du Colombier 	}
107446d884bbSDavid du Colombier 	if(lenonly)
107546d884bbSDavid du Colombier 		p += n;
107646d884bbSDavid du Colombier 	else {
107746d884bbSDavid du Colombier 		for(k = (n - 1)*7; k > 0; k -= 7)
107846d884bbSDavid du Colombier 			*p++= ((num >> k)|0x80);
107946d884bbSDavid du Colombier 		*p++ = (num&0x7F);
108046d884bbSDavid du Colombier 	}
108146d884bbSDavid du Colombier 	*pp = p;
108246d884bbSDavid du Colombier }
108346d884bbSDavid du Colombier 
108446d884bbSDavid du Colombier /*
108546d884bbSDavid du Colombier  * Encode num as unsigned or signed integer,
108646d884bbSDavid du Colombier  * only putting in bytes if !lenonly.
108746d884bbSDavid du Colombier  * Encoding is length followed by bytes to concatenate.
108846d884bbSDavid du Colombier  */
108946d884bbSDavid du Colombier static void
int_enc(uchar ** pp,int num,int unsgned,int lenonly)109046d884bbSDavid du Colombier int_enc(uchar** pp, int num, int unsgned, int lenonly)
109146d884bbSDavid du Colombier {
109246d884bbSDavid du Colombier 	int v;
109346d884bbSDavid du Colombier 	int n;
109446d884bbSDavid du Colombier 	int prevv;
109546d884bbSDavid du Colombier 	int k;
109646d884bbSDavid du Colombier 	uchar* p;
109746d884bbSDavid du Colombier 
109846d884bbSDavid du Colombier 	p = *pp;
109946d884bbSDavid du Colombier 	v = num;
110046d884bbSDavid du Colombier 	if(v < 0)
110146d884bbSDavid du Colombier 		v = -(v + 1);
110246d884bbSDavid du Colombier 	n = 1;
110346d884bbSDavid du Colombier 	prevv = v;
110446d884bbSDavid du Colombier 	v >>= 8;
110546d884bbSDavid du Colombier 	while(v > 0) {
110646d884bbSDavid du Colombier 		prevv = v;
110746d884bbSDavid du Colombier 		v >>= 8;
110846d884bbSDavid du Colombier 		n++;
110946d884bbSDavid du Colombier 	}
111046d884bbSDavid du Colombier 	if(!unsgned && (prevv&0x80))
111146d884bbSDavid du Colombier 		n++;
111246d884bbSDavid du Colombier 	if(lenonly)
111346d884bbSDavid du Colombier 		p += n;
111446d884bbSDavid du Colombier 	else {
111546d884bbSDavid du Colombier 		for(k = (n - 1)*8; k >= 0; k -= 8)
111646d884bbSDavid du Colombier 			*p++ = (num >> k);
111746d884bbSDavid du Colombier 	}
111846d884bbSDavid du Colombier 	*pp = p;
111946d884bbSDavid du Colombier }
112046d884bbSDavid du Colombier 
112146d884bbSDavid du Colombier static int
ints_eq(Ints * a,Ints * b)112246d884bbSDavid du Colombier ints_eq(Ints* a, Ints* b)
112346d884bbSDavid du Colombier {
112446d884bbSDavid du Colombier 	int	alen;
112546d884bbSDavid du Colombier 	int	i;
112646d884bbSDavid du Colombier 
112746d884bbSDavid du Colombier 	alen = a->len;
112846d884bbSDavid du Colombier 	if(alen != b->len)
112946d884bbSDavid du Colombier 		return 0;
113046d884bbSDavid du Colombier 	for(i = 0; i < alen; i++)
113146d884bbSDavid du Colombier 		if(a->data[i] != b->data[i])
113246d884bbSDavid du Colombier 			return 0;
113346d884bbSDavid du Colombier 	return 1;
113446d884bbSDavid du Colombier }
113546d884bbSDavid du Colombier 
113646d884bbSDavid du Colombier /*
113746d884bbSDavid du Colombier  * Look up o in tab (which must have nil entry to terminate).
113846d884bbSDavid du Colombier  * Return index of matching entry, or -1 if none.
113946d884bbSDavid du Colombier  */
114046d884bbSDavid du Colombier static int
oid_lookup(Ints * o,Ints ** tab)114146d884bbSDavid du Colombier oid_lookup(Ints* o, Ints** tab)
114246d884bbSDavid du Colombier {
114346d884bbSDavid du Colombier 	int i;
114446d884bbSDavid du Colombier 
114546d884bbSDavid du Colombier 	for(i = 0; tab[i] != nil; i++)
114646d884bbSDavid du Colombier 		if(ints_eq(o, tab[i]))
114746d884bbSDavid du Colombier 			return  i;
114846d884bbSDavid du Colombier 	return -1;
114946d884bbSDavid du Colombier }
115046d884bbSDavid du Colombier 
115146d884bbSDavid du Colombier /*
115246d884bbSDavid du Colombier  * Return true if *pe is a SEQUENCE, and set *pseq to
115346d884bbSDavid du Colombier  * the value of the sequence if so.
115446d884bbSDavid du Colombier  */
115546d884bbSDavid du Colombier static int
is_seq(Elem * pe,Elist ** pseq)115646d884bbSDavid du Colombier is_seq(Elem* pe, Elist** pseq)
115746d884bbSDavid du Colombier {
115846d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == SEQUENCE && pe->val.tag == VSeq) {
115946d884bbSDavid du Colombier 		*pseq = pe->val.u.seqval;
116046d884bbSDavid du Colombier 		return 1;
116146d884bbSDavid du Colombier 	}
116246d884bbSDavid du Colombier 	return 0;
116346d884bbSDavid du Colombier }
116446d884bbSDavid du Colombier 
116546d884bbSDavid du Colombier static int
is_set(Elem * pe,Elist ** pset)116646d884bbSDavid du Colombier is_set(Elem* pe, Elist** pset)
116746d884bbSDavid du Colombier {
116846d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == SETOF && pe->val.tag == VSet) {
116946d884bbSDavid du Colombier 		*pset = pe->val.u.setval;
117046d884bbSDavid du Colombier 		return 1;
117146d884bbSDavid du Colombier 	}
117246d884bbSDavid du Colombier 	return 0;
117346d884bbSDavid du Colombier }
117446d884bbSDavid du Colombier 
117546d884bbSDavid du Colombier static int
is_int(Elem * pe,int * pint)117646d884bbSDavid du Colombier is_int(Elem* pe, int* pint)
117746d884bbSDavid du Colombier {
117846d884bbSDavid du Colombier 	if(pe->tag.class == Universal) {
117946d884bbSDavid du Colombier 		if(pe->tag.num == INTEGER && pe->val.tag == VInt) {
118046d884bbSDavid du Colombier 			*pint = pe->val.u.intval;
118146d884bbSDavid du Colombier 			return 1;
118246d884bbSDavid du Colombier 		}
118346d884bbSDavid du Colombier 		else if(pe->tag.num == BOOLEAN && pe->val.tag == VBool) {
118446d884bbSDavid du Colombier 			*pint = pe->val.u.boolval;
118546d884bbSDavid du Colombier 			return 1;
118646d884bbSDavid du Colombier 		}
118746d884bbSDavid du Colombier 	}
118846d884bbSDavid du Colombier 	return 0;
118946d884bbSDavid du Colombier }
119046d884bbSDavid du Colombier 
119146d884bbSDavid du Colombier /*
119246d884bbSDavid du Colombier  * for convience, all VInt's are readable via this routine,
119346d884bbSDavid du Colombier  * as well as all VBigInt's
119446d884bbSDavid du Colombier  */
119546d884bbSDavid du Colombier static int
is_bigint(Elem * pe,Bytes ** pbigint)119646d884bbSDavid du Colombier is_bigint(Elem* pe, Bytes** pbigint)
119746d884bbSDavid du Colombier {
119846d884bbSDavid du Colombier 	int v, n, i;
119946d884bbSDavid du Colombier 
120046d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == INTEGER) {
120146d884bbSDavid du Colombier 		if(pe->val.tag == VBigInt)
120246d884bbSDavid du Colombier 			*pbigint = pe->val.u.bigintval;
120346d884bbSDavid du Colombier 		else if(pe->val.tag == VInt){
120446d884bbSDavid du Colombier 			v = pe->val.u.intval;
120546d884bbSDavid du Colombier 			for(n = 1; n < 4; n++)
120646d884bbSDavid du Colombier 				if((1 << (8 * n)) > v)
120746d884bbSDavid du Colombier 					break;
120846d884bbSDavid du Colombier 			*pbigint = newbytes(n);
120946d884bbSDavid du Colombier 			for(i = 0; i < n; i++)
121046d884bbSDavid du Colombier 				(*pbigint)->data[i] = (v >> ((n - 1 - i) * 8));
121146d884bbSDavid du Colombier 		}else
121246d884bbSDavid du Colombier 			return 0;
121346d884bbSDavid du Colombier 		return 1;
121446d884bbSDavid du Colombier 	}
121546d884bbSDavid du Colombier 	return 0;
121646d884bbSDavid du Colombier }
121746d884bbSDavid du Colombier 
121846d884bbSDavid du Colombier static int
is_bitstring(Elem * pe,Bits ** pbits)121946d884bbSDavid du Colombier is_bitstring(Elem* pe, Bits** pbits)
122046d884bbSDavid du Colombier {
122146d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == BIT_STRING && pe->val.tag == VBitString) {
122246d884bbSDavid du Colombier 		*pbits = pe->val.u.bitstringval;
122346d884bbSDavid du Colombier 		return 1;
122446d884bbSDavid du Colombier 	}
122546d884bbSDavid du Colombier 	return 0;
122646d884bbSDavid du Colombier }
122746d884bbSDavid du Colombier 
122846d884bbSDavid du Colombier static int
is_octetstring(Elem * pe,Bytes ** poctets)122946d884bbSDavid du Colombier is_octetstring(Elem* pe, Bytes** poctets)
123046d884bbSDavid du Colombier {
123146d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == OCTET_STRING && pe->val.tag == VOctets) {
123246d884bbSDavid du Colombier 		*poctets = pe->val.u.octetsval;
123346d884bbSDavid du Colombier 		return 1;
123446d884bbSDavid du Colombier 	}
123546d884bbSDavid du Colombier 	return 0;
123646d884bbSDavid du Colombier }
123746d884bbSDavid du Colombier 
123846d884bbSDavid du Colombier static int
is_oid(Elem * pe,Ints ** poid)123946d884bbSDavid du Colombier is_oid(Elem* pe, Ints** poid)
124046d884bbSDavid du Colombier {
124146d884bbSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == OBJECT_ID && pe->val.tag == VObjId) {
124246d884bbSDavid du Colombier 		*poid = pe->val.u.objidval;
124346d884bbSDavid du Colombier 		return 1;
124446d884bbSDavid du Colombier 	}
124546d884bbSDavid du Colombier 	return 0;
124646d884bbSDavid du Colombier }
124746d884bbSDavid du Colombier 
124846d884bbSDavid du Colombier static int
is_string(Elem * pe,char ** pstring)124946d884bbSDavid du Colombier is_string(Elem* pe, char** pstring)
125046d884bbSDavid du Colombier {
125146d884bbSDavid du Colombier 	if(pe->tag.class == Universal) {
125246d884bbSDavid du Colombier 		switch(pe->tag.num) {
125346d884bbSDavid du Colombier 		case UTF8String:
125446d884bbSDavid du Colombier 		case NumericString:
125546d884bbSDavid du Colombier 		case PrintableString:
125646d884bbSDavid du Colombier 		case TeletexString:
125746d884bbSDavid du Colombier 		case VideotexString:
125846d884bbSDavid du Colombier 		case IA5String:
125946d884bbSDavid du Colombier 		case GraphicString:
126046d884bbSDavid du Colombier 		case VisibleString:
126146d884bbSDavid du Colombier 		case GeneralString:
126246d884bbSDavid du Colombier 		case UniversalString:
126346d884bbSDavid du Colombier 		case BMPString:
126446d884bbSDavid du Colombier 			if(pe->val.tag == VString) {
126546d884bbSDavid du Colombier 				*pstring = pe->val.u.stringval;
126646d884bbSDavid du Colombier 				return 1;
126746d884bbSDavid du Colombier 			}
126846d884bbSDavid du Colombier 		}
126946d884bbSDavid du Colombier 	}
127046d884bbSDavid du Colombier 	return 0;
127146d884bbSDavid du Colombier }
127246d884bbSDavid du Colombier 
127346d884bbSDavid du Colombier static int
is_time(Elem * pe,char ** ptime)127446d884bbSDavid du Colombier is_time(Elem* pe, char** ptime)
127546d884bbSDavid du Colombier {
127646d884bbSDavid du Colombier 	if(pe->tag.class == Universal
127746d884bbSDavid du Colombier 	   && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
127846d884bbSDavid du Colombier 	   && pe->val.tag == VString) {
127946d884bbSDavid du Colombier 		*ptime = pe->val.u.stringval;
128046d884bbSDavid du Colombier 		return 1;
128146d884bbSDavid du Colombier 	}
128246d884bbSDavid du Colombier 	return 0;
128346d884bbSDavid du Colombier }
128446d884bbSDavid du Colombier 
128546d884bbSDavid du Colombier 
128646d884bbSDavid du Colombier /*
128746d884bbSDavid du Colombier  * malloc and return a new Bytes structure capable of
128846d884bbSDavid du Colombier  * holding len bytes. (len >= 0)
128946d884bbSDavid du Colombier  */
129046d884bbSDavid du Colombier static Bytes*
newbytes(int len)129146d884bbSDavid du Colombier newbytes(int len)
129246d884bbSDavid du Colombier {
129346d884bbSDavid du Colombier 	Bytes* ans;
129446d884bbSDavid du Colombier 
129546d884bbSDavid du Colombier 	ans = (Bytes*)emalloc(OFFSETOF(data[0], Bytes) + len);
129646d884bbSDavid du Colombier 	ans->len = len;
129746d884bbSDavid du Colombier 	return ans;
129846d884bbSDavid du Colombier }
129946d884bbSDavid du Colombier 
130046d884bbSDavid du Colombier /*
130146d884bbSDavid du Colombier  * newbytes(len), with data initialized from buf
130246d884bbSDavid du Colombier  */
130346d884bbSDavid du Colombier static Bytes*
makebytes(uchar * buf,int len)130446d884bbSDavid du Colombier makebytes(uchar* buf, int len)
130546d884bbSDavid du Colombier {
130646d884bbSDavid du Colombier 	Bytes* ans;
130746d884bbSDavid du Colombier 
130846d884bbSDavid du Colombier 	ans = newbytes(len);
130946d884bbSDavid du Colombier 	memmove(ans->data, buf, len);
131046d884bbSDavid du Colombier 	return ans;
131146d884bbSDavid du Colombier }
131246d884bbSDavid du Colombier 
131346d884bbSDavid du Colombier static void
freebytes(Bytes * b)131446d884bbSDavid du Colombier freebytes(Bytes* b)
131546d884bbSDavid du Colombier {
131646d884bbSDavid du Colombier 	if(b != nil)
131746d884bbSDavid du Colombier 		free(b);
131846d884bbSDavid du Colombier }
131946d884bbSDavid du Colombier 
132046d884bbSDavid du Colombier /*
132146d884bbSDavid du Colombier  * Make a new Bytes, containing bytes of b1 followed by those of b2.
132246d884bbSDavid du Colombier  * Either b1 or b2 or both can be nil.
132346d884bbSDavid du Colombier  */
132446d884bbSDavid du Colombier static Bytes*
catbytes(Bytes * b1,Bytes * b2)132546d884bbSDavid du Colombier catbytes(Bytes* b1, Bytes* b2)
132646d884bbSDavid du Colombier {
132746d884bbSDavid du Colombier 	Bytes* ans;
132846d884bbSDavid du Colombier 	int n;
132946d884bbSDavid du Colombier 
133046d884bbSDavid du Colombier 	if(b1 == nil) {
133146d884bbSDavid du Colombier 		if(b2 == nil)
133246d884bbSDavid du Colombier 			ans = newbytes(0);
133346d884bbSDavid du Colombier 		else
133446d884bbSDavid du Colombier 			ans = makebytes(b2->data, b2->len);
133546d884bbSDavid du Colombier 	}
133646d884bbSDavid du Colombier 	else if(b2 == nil) {
133746d884bbSDavid du Colombier 		ans = makebytes(b1->data, b1->len);
133846d884bbSDavid du Colombier 	}
133946d884bbSDavid du Colombier 	else {
134046d884bbSDavid du Colombier 		n = b1->len + b2->len;
134146d884bbSDavid du Colombier 		ans = newbytes(n);
134246d884bbSDavid du Colombier 		ans->len = n;
134346d884bbSDavid du Colombier 		memmove(ans->data, b1->data, b1->len);
134446d884bbSDavid du Colombier 		memmove(ans->data+b1->len, b2->data, b2->len);
134546d884bbSDavid du Colombier 	}
134646d884bbSDavid du Colombier 	return ans;
134746d884bbSDavid du Colombier }
134846d884bbSDavid du Colombier 
134946d884bbSDavid du Colombier /* len is number of ints */
135046d884bbSDavid du Colombier static Ints*
newints(int len)135146d884bbSDavid du Colombier newints(int len)
135246d884bbSDavid du Colombier {
135346d884bbSDavid du Colombier 	Ints* ans;
135446d884bbSDavid du Colombier 
135546d884bbSDavid du Colombier 	ans = (Ints*)emalloc(OFFSETOF(data[0], Ints) + len*sizeof(int));
135646d884bbSDavid du Colombier 	ans->len = len;
135746d884bbSDavid du Colombier 	return ans;
135846d884bbSDavid du Colombier }
135946d884bbSDavid du Colombier 
136046d884bbSDavid du Colombier static Ints*
makeints(int * buf,int len)136146d884bbSDavid du Colombier makeints(int* buf, int len)
136246d884bbSDavid du Colombier {
136346d884bbSDavid du Colombier 	Ints* ans;
136446d884bbSDavid du Colombier 
136546d884bbSDavid du Colombier 	ans = newints(len);
136646d884bbSDavid du Colombier 	if(len > 0)
136746d884bbSDavid du Colombier 		memmove(ans->data, buf, len*sizeof(int));
136846d884bbSDavid du Colombier 	return ans;
136946d884bbSDavid du Colombier }
137046d884bbSDavid du Colombier 
137146d884bbSDavid du Colombier static void
freeints(Ints * b)137246d884bbSDavid du Colombier freeints(Ints* b)
137346d884bbSDavid du Colombier {
137446d884bbSDavid du Colombier 	if(b != nil)
137546d884bbSDavid du Colombier 		free(b);
137646d884bbSDavid du Colombier }
137746d884bbSDavid du Colombier 
137846d884bbSDavid du Colombier /* len is number of bytes */
137946d884bbSDavid du Colombier static Bits*
newbits(int len)138046d884bbSDavid du Colombier newbits(int len)
138146d884bbSDavid du Colombier {
138246d884bbSDavid du Colombier 	Bits* ans;
138346d884bbSDavid du Colombier 
138446d884bbSDavid du Colombier 	ans = (Bits*)emalloc(OFFSETOF(data[0], Bits) + len);
138546d884bbSDavid du Colombier 	ans->len = len;
138646d884bbSDavid du Colombier 	ans->unusedbits = 0;
138746d884bbSDavid du Colombier 	return ans;
138846d884bbSDavid du Colombier }
138946d884bbSDavid du Colombier 
139046d884bbSDavid du Colombier static Bits*
makebits(uchar * buf,int len,int unusedbits)139146d884bbSDavid du Colombier makebits(uchar* buf, int len, int unusedbits)
139246d884bbSDavid du Colombier {
139346d884bbSDavid du Colombier 	Bits* ans;
139446d884bbSDavid du Colombier 
139546d884bbSDavid du Colombier 	ans = newbits(len);
139646d884bbSDavid du Colombier 	memmove(ans->data, buf, len);
139746d884bbSDavid du Colombier 	ans->unusedbits = unusedbits;
139846d884bbSDavid du Colombier 	return ans;
139946d884bbSDavid du Colombier }
140046d884bbSDavid du Colombier 
140146d884bbSDavid du Colombier static void
freebits(Bits * b)140246d884bbSDavid du Colombier freebits(Bits* b)
140346d884bbSDavid du Colombier {
140446d884bbSDavid du Colombier 	if(b != nil)
140546d884bbSDavid du Colombier 		free(b);
140646d884bbSDavid du Colombier }
140746d884bbSDavid du Colombier 
140846d884bbSDavid du Colombier static Elist*
mkel(Elem e,Elist * tail)140946d884bbSDavid du Colombier mkel(Elem e, Elist* tail)
141046d884bbSDavid du Colombier {
141146d884bbSDavid du Colombier 	Elist* el;
141246d884bbSDavid du Colombier 
141346d884bbSDavid du Colombier 	el = (Elist*)emalloc(sizeof(Elist));
141446d884bbSDavid du Colombier 	setmalloctag(el, getcallerpc(&e));
141546d884bbSDavid du Colombier 	el->hd = e;
141646d884bbSDavid du Colombier 	el->tl = tail;
141746d884bbSDavid du Colombier 	return el;
141846d884bbSDavid du Colombier }
141946d884bbSDavid du Colombier 
142046d884bbSDavid du Colombier static int
elistlen(Elist * el)142146d884bbSDavid du Colombier elistlen(Elist* el)
142246d884bbSDavid du Colombier {
142346d884bbSDavid du Colombier 	int ans = 0;
142446d884bbSDavid du Colombier 	while(el != nil) {
142546d884bbSDavid du Colombier 		ans++;
142646d884bbSDavid du Colombier 		el = el->tl;
142746d884bbSDavid du Colombier 	}
142846d884bbSDavid du Colombier 	return ans;
142946d884bbSDavid du Colombier }
143046d884bbSDavid du Colombier 
143146d884bbSDavid du Colombier /* Frees elist, but not fields inside values of constituent elems */
143246d884bbSDavid du Colombier static void
freeelist(Elist * el)143346d884bbSDavid du Colombier freeelist(Elist* el)
143446d884bbSDavid du Colombier {
143546d884bbSDavid du Colombier 	Elist* next;
143646d884bbSDavid du Colombier 
143746d884bbSDavid du Colombier 	while(el != nil) {
143846d884bbSDavid du Colombier 		next = el->tl;
143946d884bbSDavid du Colombier 		free(el);
144046d884bbSDavid du Colombier 		el = next;
144146d884bbSDavid du Colombier 	}
144246d884bbSDavid du Colombier }
144346d884bbSDavid du Colombier 
144446d884bbSDavid du Colombier /* free any allocated structures inside v (recursively freeing Elists) */
144546d884bbSDavid du Colombier static void
freevalfields(Value * v)144646d884bbSDavid du Colombier freevalfields(Value* v)
144746d884bbSDavid du Colombier {
144846d884bbSDavid du Colombier 	Elist* el;
144946d884bbSDavid du Colombier 	Elist* l;
145046d884bbSDavid du Colombier 	if(v == nil)
145146d884bbSDavid du Colombier 		return;
145246d884bbSDavid du Colombier 	switch(v->tag) {
145346d884bbSDavid du Colombier  	case VOctets:
145446d884bbSDavid du Colombier 		freebytes(v->u.octetsval);
145546d884bbSDavid du Colombier 		break;
145646d884bbSDavid du Colombier 	case VBigInt:
145746d884bbSDavid du Colombier 		freebytes(v->u.bigintval);
145846d884bbSDavid du Colombier 		break;
145946d884bbSDavid du Colombier 	case VReal:
146046d884bbSDavid du Colombier 		freebytes(v->u.realval);
146146d884bbSDavid du Colombier 		break;
146246d884bbSDavid du Colombier 	case VOther:
146346d884bbSDavid du Colombier 		freebytes(v->u.otherval);
146446d884bbSDavid du Colombier 		break;
146546d884bbSDavid du Colombier 	case VBitString:
146646d884bbSDavid du Colombier 		freebits(v->u.bitstringval);
146746d884bbSDavid du Colombier 		break;
146846d884bbSDavid du Colombier 	case VObjId:
146946d884bbSDavid du Colombier 		freeints(v->u.objidval);
147046d884bbSDavid du Colombier 		break;
147146d884bbSDavid du Colombier 	case VString:
147246d884bbSDavid du Colombier 		if(v->u.stringval)
147346d884bbSDavid du Colombier 			free(v->u.stringval);
147446d884bbSDavid du Colombier 		break;
147546d884bbSDavid du Colombier 	case VSeq:
147646d884bbSDavid du Colombier 		el = v->u.seqval;
147746d884bbSDavid du Colombier 		for(l = el; l != nil; l = l->tl)
147846d884bbSDavid du Colombier 			freevalfields(&l->hd.val);
147946d884bbSDavid du Colombier 		if(el)
148046d884bbSDavid du Colombier 			freeelist(el);
148146d884bbSDavid du Colombier 		break;
148246d884bbSDavid du Colombier 	case VSet:
148346d884bbSDavid du Colombier 		el = v->u.setval;
148446d884bbSDavid du Colombier 		for(l = el; l != nil; l = l->tl)
148546d884bbSDavid du Colombier 			freevalfields(&l->hd.val);
148646d884bbSDavid du Colombier 		if(el)
148746d884bbSDavid du Colombier 			freeelist(el);
148846d884bbSDavid du Colombier 		break;
148946d884bbSDavid du Colombier 	}
149046d884bbSDavid du Colombier }
149146d884bbSDavid du Colombier 
149246d884bbSDavid du Colombier /* end of general ASN1 functions */
149346d884bbSDavid du Colombier 
149446d884bbSDavid du Colombier 
149546d884bbSDavid du Colombier 
149646d884bbSDavid du Colombier 
149746d884bbSDavid du Colombier 
149846d884bbSDavid du Colombier /*=============================================================*/
149946d884bbSDavid du Colombier /*
150046d884bbSDavid du Colombier  * Decode and parse an X.509 Certificate, defined by this ASN1:
150146d884bbSDavid du Colombier  *	Certificate ::= SEQUENCE {
150246d884bbSDavid du Colombier  *		certificateInfo CertificateInfo,
150346d884bbSDavid du Colombier  *		signatureAlgorithm AlgorithmIdentifier,
150446d884bbSDavid du Colombier  *		signature BIT STRING }
150546d884bbSDavid du Colombier  *
150646d884bbSDavid du Colombier  *	CertificateInfo ::= SEQUENCE {
150746d884bbSDavid du Colombier  *		version [0] INTEGER DEFAULT v1 (0),
150846d884bbSDavid du Colombier  *		serialNumber INTEGER,
150946d884bbSDavid du Colombier  *		signature AlgorithmIdentifier,
151046d884bbSDavid du Colombier  *		issuer Name,
151146d884bbSDavid du Colombier  *		validity Validity,
151246d884bbSDavid du Colombier  *		subject Name,
151346d884bbSDavid du Colombier  *		subjectPublicKeyInfo SubjectPublicKeyInfo }
151446d884bbSDavid du Colombier  *	(version v2 has two more fields, optional unique identifiers for
151546d884bbSDavid du Colombier  *  issuer and subject; since we ignore these anyway, we won't parse them)
151646d884bbSDavid du Colombier  *
151746d884bbSDavid du Colombier  *	Validity ::= SEQUENCE {
151846d884bbSDavid du Colombier  *		notBefore UTCTime,
151946d884bbSDavid du Colombier  *		notAfter UTCTime }
152046d884bbSDavid du Colombier  *
152146d884bbSDavid du Colombier  *	SubjectPublicKeyInfo ::= SEQUENCE {
152246d884bbSDavid du Colombier  *		algorithm AlgorithmIdentifier,
152346d884bbSDavid du Colombier  *		subjectPublicKey BIT STRING }
152446d884bbSDavid du Colombier  *
152546d884bbSDavid du Colombier  *	AlgorithmIdentifier ::= SEQUENCE {
152646d884bbSDavid du Colombier  *		algorithm OBJECT IDENTIFER,
152746d884bbSDavid du Colombier  *		parameters ANY DEFINED BY ALGORITHM OPTIONAL }
152846d884bbSDavid du Colombier  *
152946d884bbSDavid du Colombier  *	Name ::= SEQUENCE OF RelativeDistinguishedName
153046d884bbSDavid du Colombier  *
153146d884bbSDavid du Colombier  *	RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue
153246d884bbSDavid du Colombier  *
153346d884bbSDavid du Colombier  *	AttributeTypeAndValue ::= SEQUENCE {
153446d884bbSDavid du Colombier  *		type OBJECT IDENTIFER,
153546d884bbSDavid du Colombier  *		value DirectoryString }
153646d884bbSDavid du Colombier  *	(selected attributes have these Object Ids:
153746d884bbSDavid du Colombier  *		commonName {2 5 4 3}
153846d884bbSDavid du Colombier  *		countryName {2 5 4 6}
153946d884bbSDavid du Colombier  *		localityName {2 5 4 7}
154046d884bbSDavid du Colombier  *		stateOrProvinceName {2 5 4 8}
154146d884bbSDavid du Colombier  *		organizationName {2 5 4 10}
154246d884bbSDavid du Colombier  *		organizationalUnitName {2 5 4 11}
154346d884bbSDavid du Colombier  *	)
154446d884bbSDavid du Colombier  *
154546d884bbSDavid du Colombier  *	DirectoryString ::= CHOICE {
154646d884bbSDavid du Colombier  *		teletexString TeletexString,
154746d884bbSDavid du Colombier  *		printableString PrintableString,
154846d884bbSDavid du Colombier  *		universalString UniversalString }
154946d884bbSDavid du Colombier  *
155046d884bbSDavid du Colombier  *  See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature.
155146d884bbSDavid du Colombier  *
155246d884bbSDavid du Colombier  *  Not yet implemented:
155346d884bbSDavid du Colombier  *   CertificateRevocationList ::= SIGNED SEQUENCE{
155446d884bbSDavid du Colombier  *           signature       AlgorithmIdentifier,
155546d884bbSDavid du Colombier  *           issuer          Name,
155646d884bbSDavid du Colombier  *           lastUpdate      UTCTime,
155746d884bbSDavid du Colombier  *           nextUpdate      UTCTime,
155846d884bbSDavid du Colombier  *           revokedCertificates
155946d884bbSDavid du Colombier  *                           SEQUENCE OF CRLEntry OPTIONAL}
156046d884bbSDavid du Colombier  *   CRLEntry ::= SEQUENCE{
156146d884bbSDavid du Colombier  *           userCertificate SerialNumber,
156246d884bbSDavid du Colombier  *           revocationDate UTCTime}
156346d884bbSDavid du Colombier  */
156446d884bbSDavid du Colombier 
156546d884bbSDavid du Colombier typedef struct CertX509 {
156646d884bbSDavid du Colombier 	int	serial;
156746d884bbSDavid du Colombier 	char*	issuer;
156846d884bbSDavid du Colombier 	char*	validity_start;
156946d884bbSDavid du Colombier 	char*	validity_end;
157046d884bbSDavid du Colombier 	char*	subject;
157146d884bbSDavid du Colombier 	int	publickey_alg;
157246d884bbSDavid du Colombier 	Bytes*	publickey;
157346d884bbSDavid du Colombier 	int	signature_alg;
157446d884bbSDavid du Colombier 	Bytes*	signature;
157546d884bbSDavid du Colombier } CertX509;
157646d884bbSDavid du Colombier 
157746d884bbSDavid du Colombier /* Algorithm object-ids */
157846d884bbSDavid du Colombier enum {
157946d884bbSDavid du Colombier 	ALG_rsaEncryption,
158046d884bbSDavid du Colombier 	ALG_md2WithRSAEncryption,
158146d884bbSDavid du Colombier 	ALG_md4WithRSAEncryption,
158246d884bbSDavid du Colombier 	ALG_md5WithRSAEncryption,
158346d884bbSDavid du Colombier 	ALG_sha1WithRSAEncryption,
158446d884bbSDavid du Colombier 	ALG_sha1WithRSAEncryptionOiw,
158546d884bbSDavid du Colombier 	ALG_md5,
158646d884bbSDavid du Colombier 	NUMALGS
158746d884bbSDavid du Colombier };
158846d884bbSDavid du Colombier typedef struct Ints7 {
158946d884bbSDavid du Colombier 	int		len;
159046d884bbSDavid du Colombier 	int		data[7];
159146d884bbSDavid du Colombier } Ints7;
159246d884bbSDavid du Colombier static Ints7 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 };
159346d884bbSDavid du Colombier static Ints7 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 };
159446d884bbSDavid du Colombier static Ints7 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 };
159546d884bbSDavid du Colombier static Ints7 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 };
159646d884bbSDavid du Colombier static Ints7 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 };
159746d884bbSDavid du Colombier static Ints7 oid_sha1WithRSAEncryptionOiw ={6, 1, 3, 14, 3, 2, 29 };
159846d884bbSDavid du Colombier static Ints7 oid_md5 ={6, 1, 2, 840, 113549, 2, 5, 0 };
159946d884bbSDavid du Colombier static Ints *alg_oid_tab[NUMALGS+1] = {
160046d884bbSDavid du Colombier 	(Ints*)&oid_rsaEncryption,
160146d884bbSDavid du Colombier 	(Ints*)&oid_md2WithRSAEncryption,
160246d884bbSDavid du Colombier 	(Ints*)&oid_md4WithRSAEncryption,
160346d884bbSDavid du Colombier 	(Ints*)&oid_md5WithRSAEncryption,
160446d884bbSDavid du Colombier 	(Ints*)&oid_sha1WithRSAEncryption,
160546d884bbSDavid du Colombier 	(Ints*)&oid_sha1WithRSAEncryptionOiw,
160646d884bbSDavid du Colombier 	(Ints*)&oid_md5,
160746d884bbSDavid du Colombier 	nil
160846d884bbSDavid du Colombier };
160946d884bbSDavid du Colombier static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, sha1, md5, nil };
161046d884bbSDavid du Colombier 
161146d884bbSDavid du Colombier static void
freecert(CertX509 * c)161246d884bbSDavid du Colombier freecert(CertX509* c)
161346d884bbSDavid du Colombier {
161446d884bbSDavid du Colombier 	if(!c) return;
161546d884bbSDavid du Colombier 	if(c->issuer != nil)
161646d884bbSDavid du Colombier 		free(c->issuer);
161746d884bbSDavid du Colombier 	if(c->validity_start != nil)
161846d884bbSDavid du Colombier 		free(c->validity_start);
161946d884bbSDavid du Colombier 	if(c->validity_end != nil)
162046d884bbSDavid du Colombier 		free(c->validity_end);
162146d884bbSDavid du Colombier 	if(c->subject != nil)
162246d884bbSDavid du Colombier 		free(c->subject);
162346d884bbSDavid du Colombier 	freebytes(c->publickey);
162446d884bbSDavid du Colombier 	freebytes(c->signature);
162546d884bbSDavid du Colombier 	free(c);
162646d884bbSDavid du Colombier }
162746d884bbSDavid du Colombier 
162846d884bbSDavid du Colombier /*
162946d884bbSDavid du Colombier  * Parse the Name ASN1 type.
163046d884bbSDavid du Colombier  * The sequence of RelativeDistinguishedName's gives a sort of pathname,
163146d884bbSDavid du Colombier  * from most general to most specific.  Each element of the path can be
163246d884bbSDavid du Colombier  * one or more (but usually just one) attribute-value pair, such as
163346d884bbSDavid du Colombier  * countryName="US".
163446d884bbSDavid du Colombier  * We'll just form a "postal-style" address string by concatenating the elements
163546d884bbSDavid du Colombier  * from most specific to least specific, separated by commas.
163646d884bbSDavid du Colombier  * Return name-as-string (which must be freed by caller).
163746d884bbSDavid du Colombier  */
163846d884bbSDavid du Colombier static char*
parse_name(Elem * e)163946d884bbSDavid du Colombier parse_name(Elem* e)
164046d884bbSDavid du Colombier {
164146d884bbSDavid du Colombier 	Elist* el;
164246d884bbSDavid du Colombier 	Elem* es;
164346d884bbSDavid du Colombier 	Elist* esetl;
164446d884bbSDavid du Colombier 	Elem* eat;
164546d884bbSDavid du Colombier 	Elist* eatl;
164646d884bbSDavid du Colombier 	char* s;
164746d884bbSDavid du Colombier 	enum { MAXPARTS = 100 };
164846d884bbSDavid du Colombier 	char* parts[MAXPARTS];
164946d884bbSDavid du Colombier 	int i;
165046d884bbSDavid du Colombier 	int plen;
165146d884bbSDavid du Colombier 	char* ans = nil;
165246d884bbSDavid du Colombier 
165346d884bbSDavid du Colombier 	if(!is_seq(e, &el))
165446d884bbSDavid du Colombier 		goto errret;
165546d884bbSDavid du Colombier 	i = 0;
165646d884bbSDavid du Colombier 	plen = 0;
165746d884bbSDavid du Colombier 	while(el != nil) {
165846d884bbSDavid du Colombier 		es = &el->hd;
165946d884bbSDavid du Colombier 		if(!is_set(es, &esetl))
166046d884bbSDavid du Colombier 			goto errret;
166146d884bbSDavid du Colombier 		while(esetl != nil) {
166246d884bbSDavid du Colombier 			eat = &esetl->hd;
166346d884bbSDavid du Colombier 			if(!is_seq(eat, &eatl) || elistlen(eatl) != 2)
166446d884bbSDavid du Colombier 				goto errret;
166546d884bbSDavid du Colombier 			if(!is_string(&eatl->tl->hd, &s) || i>=MAXPARTS)
166646d884bbSDavid du Colombier 				goto errret;
166746d884bbSDavid du Colombier 			parts[i++] = s;
166846d884bbSDavid du Colombier 			plen += strlen(s) + 2;		/* room for ", " after */
166946d884bbSDavid du Colombier 			esetl = esetl->tl;
167046d884bbSDavid du Colombier 		}
167146d884bbSDavid du Colombier 		el = el->tl;
167246d884bbSDavid du Colombier 	}
167346d884bbSDavid du Colombier 	if(i > 0) {
167446d884bbSDavid du Colombier 		ans = (char*)emalloc(plen);
167546d884bbSDavid du Colombier 		*ans = '\0';
167646d884bbSDavid du Colombier 		while(--i >= 0) {
167746d884bbSDavid du Colombier 			s = parts[i];
167846d884bbSDavid du Colombier 			strcat(ans, s);
167946d884bbSDavid du Colombier 			if(i > 0)
168046d884bbSDavid du Colombier 				strcat(ans, ", ");
168146d884bbSDavid du Colombier 		}
168246d884bbSDavid du Colombier 	}
168346d884bbSDavid du Colombier 
168446d884bbSDavid du Colombier errret:
168546d884bbSDavid du Colombier 	return ans;
168646d884bbSDavid du Colombier }
168746d884bbSDavid du Colombier 
168846d884bbSDavid du Colombier /*
168946d884bbSDavid du Colombier  * Parse an AlgorithmIdentifer ASN1 type.
169046d884bbSDavid du Colombier  * Look up the oid in oid_tab and return one of OID_rsaEncryption, etc..,
169146d884bbSDavid du Colombier  * or -1 if not found.
169246d884bbSDavid du Colombier  * For now, ignore parameters, since none of our algorithms need them.
169346d884bbSDavid du Colombier  */
169446d884bbSDavid du Colombier static int
parse_alg(Elem * e)169546d884bbSDavid du Colombier parse_alg(Elem* e)
169646d884bbSDavid du Colombier {
169746d884bbSDavid du Colombier 	Elist* el;
169846d884bbSDavid du Colombier 	Ints* oid;
169946d884bbSDavid du Colombier 
170046d884bbSDavid du Colombier 	if(!is_seq(e, &el) || el == nil || !is_oid(&el->hd, &oid))
170146d884bbSDavid du Colombier 		return -1;
170246d884bbSDavid du Colombier 	return oid_lookup(oid, alg_oid_tab);
170346d884bbSDavid du Colombier }
170446d884bbSDavid du Colombier 
170546d884bbSDavid du Colombier static CertX509*
decode_cert(Bytes * a)170646d884bbSDavid du Colombier decode_cert(Bytes* a)
170746d884bbSDavid du Colombier {
170846d884bbSDavid du Colombier 	int ok = 0;
170946d884bbSDavid du Colombier 	int n;
171046d884bbSDavid du Colombier 	CertX509* c = nil;
171146d884bbSDavid du Colombier 	Elem  ecert;
171246d884bbSDavid du Colombier 	Elem* ecertinfo;
171346d884bbSDavid du Colombier 	Elem* esigalg;
171446d884bbSDavid du Colombier 	Elem* esig;
171546d884bbSDavid du Colombier 	Elem* eserial;
171646d884bbSDavid du Colombier 	Elem* eissuer;
171746d884bbSDavid du Colombier 	Elem* evalidity;
171846d884bbSDavid du Colombier 	Elem* esubj;
171946d884bbSDavid du Colombier 	Elem* epubkey;
172046d884bbSDavid du Colombier 	Elist* el;
172146d884bbSDavid du Colombier 	Elist* elcert = nil;
172246d884bbSDavid du Colombier 	Elist* elcertinfo = nil;
172346d884bbSDavid du Colombier 	Elist* elvalidity = nil;
172446d884bbSDavid du Colombier 	Elist* elpubkey = nil;
172546d884bbSDavid du Colombier 	Bits* bits = nil;
172646d884bbSDavid du Colombier 	Bytes* b;
172746d884bbSDavid du Colombier 	Elem* e;
172846d884bbSDavid du Colombier 
172946d884bbSDavid du Colombier 	if(decode(a->data, a->len, &ecert) != ASN_OK)
173046d884bbSDavid du Colombier 		goto errret;
173146d884bbSDavid du Colombier 
173246d884bbSDavid du Colombier 	c = (CertX509*)emalloc(sizeof(CertX509));
173346d884bbSDavid du Colombier 	c->serial = -1;
173446d884bbSDavid du Colombier 	c->issuer = nil;
173546d884bbSDavid du Colombier 	c->validity_start = nil;
173646d884bbSDavid du Colombier 	c->validity_end = nil;
173746d884bbSDavid du Colombier 	c->subject = nil;
173846d884bbSDavid du Colombier 	c->publickey_alg = -1;
173946d884bbSDavid du Colombier 	c->publickey = nil;
174046d884bbSDavid du Colombier 	c->signature_alg = -1;
174146d884bbSDavid du Colombier 	c->signature = nil;
174246d884bbSDavid du Colombier 
174346d884bbSDavid du Colombier 	/* Certificate */
174446d884bbSDavid du Colombier  	if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
174546d884bbSDavid du Colombier 		goto errret;
174646d884bbSDavid du Colombier  	ecertinfo = &elcert->hd;
174746d884bbSDavid du Colombier  	el = elcert->tl;
174846d884bbSDavid du Colombier  	esigalg = &el->hd;
174946d884bbSDavid du Colombier 	c->signature_alg = parse_alg(esigalg);
175046d884bbSDavid du Colombier  	el = el->tl;
175146d884bbSDavid du Colombier  	esig = &el->hd;
175246d884bbSDavid du Colombier 
175346d884bbSDavid du Colombier 	/* Certificate Info */
175446d884bbSDavid du Colombier 	if(!is_seq(ecertinfo, &elcertinfo))
175546d884bbSDavid du Colombier 		goto errret;
175646d884bbSDavid du Colombier 	n = elistlen(elcertinfo);
175746d884bbSDavid du Colombier   	if(n < 6)
175846d884bbSDavid du Colombier 		goto errret;
175946d884bbSDavid du Colombier 	eserial =&elcertinfo->hd;
176046d884bbSDavid du Colombier  	el = elcertinfo->tl;
176146d884bbSDavid du Colombier  	/* check for optional version, marked by explicit context tag 0 */
176246d884bbSDavid du Colombier 	if(eserial->tag.class == Context && eserial->tag.num == 0) {
176346d884bbSDavid du Colombier  		eserial = &el->hd;
176446d884bbSDavid du Colombier  		if(n < 7)
176546d884bbSDavid du Colombier  			goto errret;
176646d884bbSDavid du Colombier  		el = el->tl;
176746d884bbSDavid du Colombier  	}
176846d884bbSDavid du Colombier 
176946d884bbSDavid du Colombier 	if(parse_alg(&el->hd) != c->signature_alg)
177046d884bbSDavid du Colombier 		goto errret;
177146d884bbSDavid du Colombier  	el = el->tl;
177246d884bbSDavid du Colombier  	eissuer = &el->hd;
177346d884bbSDavid du Colombier  	el = el->tl;
177446d884bbSDavid du Colombier  	evalidity = &el->hd;
177546d884bbSDavid du Colombier  	el = el->tl;
177646d884bbSDavid du Colombier  	esubj = &el->hd;
177746d884bbSDavid du Colombier  	el = el->tl;
177846d884bbSDavid du Colombier  	epubkey = &el->hd;
177946d884bbSDavid du Colombier  	if(!is_int(eserial, &c->serial)) {
178046d884bbSDavid du Colombier 		if(!is_bigint(eserial, &b))
178146d884bbSDavid du Colombier 			goto errret;
178246d884bbSDavid du Colombier 		c->serial = -1;	/* else we have to change cert struct */
178346d884bbSDavid du Colombier   	}
178446d884bbSDavid du Colombier 	c->issuer = parse_name(eissuer);
178546d884bbSDavid du Colombier 	if(c->issuer == nil)
178646d884bbSDavid du Colombier 		goto errret;
178746d884bbSDavid du Colombier 	/* Validity */
178846d884bbSDavid du Colombier   	if(!is_seq(evalidity, &elvalidity))
178946d884bbSDavid du Colombier 		goto errret;
179046d884bbSDavid du Colombier 	if(elistlen(elvalidity) != 2)
179146d884bbSDavid du Colombier 		goto errret;
179246d884bbSDavid du Colombier 	e = &elvalidity->hd;
179346d884bbSDavid du Colombier 	if(!is_time(e, &c->validity_start))
179446d884bbSDavid du Colombier 		goto errret;
179546d884bbSDavid du Colombier 	e->val.u.stringval = nil;	/* string ownership transfer */
179646d884bbSDavid du Colombier 	e = &elvalidity->tl->hd;
179746d884bbSDavid du Colombier  	if(!is_time(e, &c->validity_end))
179846d884bbSDavid du Colombier 		goto errret;
179946d884bbSDavid du Colombier 	e->val.u.stringval = nil;	/* string ownership transfer */
180046d884bbSDavid du Colombier 
180146d884bbSDavid du Colombier 	/* resume CertificateInfo */
180246d884bbSDavid du Colombier  	c->subject = parse_name(esubj);
180346d884bbSDavid du Colombier 	if(c->subject == nil)
180446d884bbSDavid du Colombier 		goto errret;
180546d884bbSDavid du Colombier 
180646d884bbSDavid du Colombier 	/* SubjectPublicKeyInfo */
180746d884bbSDavid du Colombier  	if(!is_seq(epubkey, &elpubkey))
180846d884bbSDavid du Colombier 		goto errret;
180946d884bbSDavid du Colombier 	if(elistlen(elpubkey) != 2)
181046d884bbSDavid du Colombier 		goto errret;
181146d884bbSDavid du Colombier 
181246d884bbSDavid du Colombier 	c->publickey_alg = parse_alg(&elpubkey->hd);
181346d884bbSDavid du Colombier 	if(c->publickey_alg < 0)
181446d884bbSDavid du Colombier 		goto errret;
181546d884bbSDavid du Colombier   	if(!is_bitstring(&elpubkey->tl->hd, &bits))
181646d884bbSDavid du Colombier 		goto errret;
181746d884bbSDavid du Colombier 	if(bits->unusedbits != 0)
181846d884bbSDavid du Colombier 		goto errret;
181946d884bbSDavid du Colombier  	c->publickey = makebytes(bits->data, bits->len);
182046d884bbSDavid du Colombier 
182146d884bbSDavid du Colombier 	/*resume Certificate */
182246d884bbSDavid du Colombier 	if(c->signature_alg < 0)
182346d884bbSDavid du Colombier 		goto errret;
182446d884bbSDavid du Colombier  	if(!is_bitstring(esig, &bits))
182546d884bbSDavid du Colombier 		goto errret;
182646d884bbSDavid du Colombier  	c->signature = makebytes(bits->data, bits->len);
182746d884bbSDavid du Colombier 	ok = 1;
182846d884bbSDavid du Colombier 
182946d884bbSDavid du Colombier errret:
183046d884bbSDavid du Colombier 	freevalfields(&ecert.val);	/* recurses through lists, too */
183146d884bbSDavid du Colombier 	if(!ok){
183246d884bbSDavid du Colombier 		freecert(c);
183346d884bbSDavid du Colombier 		c = nil;
183446d884bbSDavid du Colombier 	}
183546d884bbSDavid du Colombier 	return c;
183646d884bbSDavid du Colombier }
183746d884bbSDavid du Colombier 
183846d884bbSDavid du Colombier /*
183946d884bbSDavid du Colombier  *	RSAPublickKey :: SEQUENCE {
184046d884bbSDavid du Colombier  *		modulus INTEGER,
184146d884bbSDavid du Colombier  *		publicExponent INTEGER
184246d884bbSDavid du Colombier  *	}
184346d884bbSDavid du Colombier  */
184446d884bbSDavid du Colombier static RSApub*
decode_rsapubkey(Bytes * a)184546d884bbSDavid du Colombier decode_rsapubkey(Bytes* a)
184646d884bbSDavid du Colombier {
184746d884bbSDavid du Colombier 	Elem e;
184846d884bbSDavid du Colombier 	Elist *el, *l;
184946d884bbSDavid du Colombier 	mpint *mp;
185046d884bbSDavid du Colombier 	RSApub* key;
185146d884bbSDavid du Colombier 
185246d884bbSDavid du Colombier 	l = nil;
185346d884bbSDavid du Colombier 	key = rsapuballoc();
185446d884bbSDavid du Colombier 	if(decode(a->data, a->len, &e) != ASN_OK)
185546d884bbSDavid du Colombier 		goto errret;
185646d884bbSDavid du Colombier 	if(!is_seq(&e, &el) || elistlen(el) != 2)
185746d884bbSDavid du Colombier 		goto errret;
185846d884bbSDavid du Colombier 
185946d884bbSDavid du Colombier 	l = el;
186046d884bbSDavid du Colombier 
186146d884bbSDavid du Colombier 	key->n = mp = asn1mpint(&el->hd);
186246d884bbSDavid du Colombier 	if(mp == nil)
186346d884bbSDavid du Colombier 		goto errret;
186446d884bbSDavid du Colombier 
186546d884bbSDavid du Colombier 	el = el->tl;
186646d884bbSDavid du Colombier 	key->ek = mp = asn1mpint(&el->hd);
186746d884bbSDavid du Colombier 	if(mp == nil)
186846d884bbSDavid du Colombier 		goto errret;
186946d884bbSDavid du Colombier 
187046d884bbSDavid du Colombier 	if(l != nil)
187146d884bbSDavid du Colombier 		freeelist(l);
187246d884bbSDavid du Colombier 	return key;
187346d884bbSDavid du Colombier errret:
187446d884bbSDavid du Colombier 	if(l != nil)
187546d884bbSDavid du Colombier 		freeelist(l);
187646d884bbSDavid du Colombier 	rsapubfree(key);
187746d884bbSDavid du Colombier 	return nil;
187846d884bbSDavid du Colombier }
187946d884bbSDavid du Colombier 
188046d884bbSDavid du Colombier /*
188146d884bbSDavid du Colombier  *	RSAPrivateKey ::= SEQUENCE {
188246d884bbSDavid du Colombier  *		version Version,
188346d884bbSDavid du Colombier  *		modulus INTEGER, -- n
188446d884bbSDavid du Colombier  *		publicExponent INTEGER, -- e
188546d884bbSDavid du Colombier  *		privateExponent INTEGER, -- d
188646d884bbSDavid du Colombier  *		prime1 INTEGER, -- p
188746d884bbSDavid du Colombier  *		prime2 INTEGER, -- q
188846d884bbSDavid du Colombier  *		exponent1 INTEGER, -- d mod (p-1)
188946d884bbSDavid du Colombier  *		exponent2 INTEGER, -- d mod (q-1)
189046d884bbSDavid du Colombier  *		coefficient INTEGER -- (inverse of q) mod p }
189146d884bbSDavid du Colombier  */
189246d884bbSDavid du Colombier static RSApriv*
decode_rsaprivkey(Bytes * a)189346d884bbSDavid du Colombier decode_rsaprivkey(Bytes* a)
189446d884bbSDavid du Colombier {
189546d884bbSDavid du Colombier 	int version;
189646d884bbSDavid du Colombier 	Elem e;
189746d884bbSDavid du Colombier 	Elist *el;
189846d884bbSDavid du Colombier 	mpint *mp;
189946d884bbSDavid du Colombier 	RSApriv* key;
190046d884bbSDavid du Colombier 
190146d884bbSDavid du Colombier 	key = rsaprivalloc();
190246d884bbSDavid du Colombier 	if(decode(a->data, a->len, &e) != ASN_OK)
190346d884bbSDavid du Colombier 		goto errret;
190446d884bbSDavid du Colombier 	if(!is_seq(&e, &el) || elistlen(el) != 9)
190546d884bbSDavid du Colombier 		goto errret;
190646d884bbSDavid du Colombier 	if(!is_int(&el->hd, &version) || version != 0)
190746d884bbSDavid du Colombier 		goto errret;
190846d884bbSDavid du Colombier 
190946d884bbSDavid du Colombier 	el = el->tl;
191046d884bbSDavid du Colombier 	key->pub.n = mp = asn1mpint(&el->hd);
191146d884bbSDavid du Colombier 	if(mp == nil)
191246d884bbSDavid du Colombier 		goto errret;
191346d884bbSDavid du Colombier 
191446d884bbSDavid du Colombier 	el = el->tl;
191546d884bbSDavid du Colombier 	key->pub.ek = mp = asn1mpint(&el->hd);
191646d884bbSDavid du Colombier 	if(mp == nil)
191746d884bbSDavid du Colombier 		goto errret;
191846d884bbSDavid du Colombier 
191946d884bbSDavid du Colombier 	el = el->tl;
192046d884bbSDavid du Colombier 	key->dk = mp = asn1mpint(&el->hd);
192146d884bbSDavid du Colombier 	if(mp == nil)
192246d884bbSDavid du Colombier 		goto errret;
192346d884bbSDavid du Colombier 
192446d884bbSDavid du Colombier 	el = el->tl;
192546d884bbSDavid du Colombier 	key->q = mp = asn1mpint(&el->hd);
192646d884bbSDavid du Colombier 	if(mp == nil)
192746d884bbSDavid du Colombier 		goto errret;
192846d884bbSDavid du Colombier 
192946d884bbSDavid du Colombier 	el = el->tl;
193046d884bbSDavid du Colombier 	key->p = mp = asn1mpint(&el->hd);
193146d884bbSDavid du Colombier 	if(mp == nil)
193246d884bbSDavid du Colombier 		goto errret;
193346d884bbSDavid du Colombier 
193446d884bbSDavid du Colombier 	el = el->tl;
193546d884bbSDavid du Colombier 	key->kq = mp = asn1mpint(&el->hd);
193646d884bbSDavid du Colombier 	if(mp == nil)
193746d884bbSDavid du Colombier 		goto errret;
193846d884bbSDavid du Colombier 
193946d884bbSDavid du Colombier 	el = el->tl;
194046d884bbSDavid du Colombier 	key->kp = mp = asn1mpint(&el->hd);
194146d884bbSDavid du Colombier 	if(mp == nil)
194246d884bbSDavid du Colombier 		goto errret;
194346d884bbSDavid du Colombier 
194446d884bbSDavid du Colombier 	el = el->tl;
194546d884bbSDavid du Colombier 	key->c2 = mp = asn1mpint(&el->hd);
194646d884bbSDavid du Colombier 	if(mp == nil)
194746d884bbSDavid du Colombier 		goto errret;
194846d884bbSDavid du Colombier 
194946d884bbSDavid du Colombier 	return key;
195046d884bbSDavid du Colombier errret:
195146d884bbSDavid du Colombier 	rsaprivfree(key);
195246d884bbSDavid du Colombier 	return nil;
195346d884bbSDavid du Colombier }
195446d884bbSDavid du Colombier 
195546d884bbSDavid du Colombier /*
195646d884bbSDavid du Colombier  * 	DSAPrivateKey ::= SEQUENCE{
195746d884bbSDavid du Colombier  *		version Version,
195846d884bbSDavid du Colombier  *		p INTEGER,
195946d884bbSDavid du Colombier  *		q INTEGER,
196046d884bbSDavid du Colombier  *		g INTEGER, -- alpha
196146d884bbSDavid du Colombier  *		pub_key INTEGER, -- key
196246d884bbSDavid du Colombier  *		priv_key INTEGER, -- secret
196346d884bbSDavid du Colombier  *	}
196446d884bbSDavid du Colombier  */
196546d884bbSDavid du Colombier static DSApriv*
decode_dsaprivkey(Bytes * a)196646d884bbSDavid du Colombier decode_dsaprivkey(Bytes* a)
196746d884bbSDavid du Colombier {
196846d884bbSDavid du Colombier 	int version;
196946d884bbSDavid du Colombier 	Elem e;
197046d884bbSDavid du Colombier 	Elist *el;
197146d884bbSDavid du Colombier 	mpint *mp;
197246d884bbSDavid du Colombier 	DSApriv* key;
197346d884bbSDavid du Colombier 
197446d884bbSDavid du Colombier 	key = dsaprivalloc();
197546d884bbSDavid du Colombier 	if(decode(a->data, a->len, &e) != ASN_OK)
197646d884bbSDavid du Colombier 		goto errret;
197746d884bbSDavid du Colombier 	if(!is_seq(&e, &el) || elistlen(el) != 6)
197846d884bbSDavid du Colombier 		goto errret;
197946d884bbSDavid du Colombier version = -1;
198046d884bbSDavid du Colombier 	if(!is_int(&el->hd, &version) || version != 0)
198146d884bbSDavid du Colombier {
198246d884bbSDavid du Colombier fprint(2, "version %d\n", version);
198346d884bbSDavid du Colombier 		goto errret;
198446d884bbSDavid du Colombier }
198546d884bbSDavid du Colombier 
198646d884bbSDavid du Colombier 	el = el->tl;
198746d884bbSDavid du Colombier 	key->pub.p = mp = asn1mpint(&el->hd);
198846d884bbSDavid du Colombier 	if(mp == nil)
198946d884bbSDavid du Colombier 		goto errret;
199046d884bbSDavid du Colombier 
199146d884bbSDavid du Colombier 	el = el->tl;
199246d884bbSDavid du Colombier 	key->pub.q = mp = asn1mpint(&el->hd);
199346d884bbSDavid du Colombier 	if(mp == nil)
199446d884bbSDavid du Colombier 		goto errret;
199546d884bbSDavid du Colombier 
199646d884bbSDavid du Colombier 	el = el->tl;
199746d884bbSDavid du Colombier 	key->pub.alpha = mp = asn1mpint(&el->hd);
199846d884bbSDavid du Colombier 	if(mp == nil)
199946d884bbSDavid du Colombier 		goto errret;
200046d884bbSDavid du Colombier 
200146d884bbSDavid du Colombier 	el = el->tl;
200246d884bbSDavid du Colombier 	key->pub.key = mp = asn1mpint(&el->hd);
200346d884bbSDavid du Colombier 	if(mp == nil)
200446d884bbSDavid du Colombier 		goto errret;
200546d884bbSDavid du Colombier 
200646d884bbSDavid du Colombier 	el = el->tl;
200746d884bbSDavid du Colombier 	key->secret = mp = asn1mpint(&el->hd);
200846d884bbSDavid du Colombier 	if(mp == nil)
200946d884bbSDavid du Colombier 		goto errret;
201046d884bbSDavid du Colombier 
201146d884bbSDavid du Colombier 	return key;
201246d884bbSDavid du Colombier errret:
201346d884bbSDavid du Colombier 	dsaprivfree(key);
201446d884bbSDavid du Colombier 	return nil;
201546d884bbSDavid du Colombier }
201646d884bbSDavid du Colombier 
201746d884bbSDavid du Colombier static mpint*
asn1mpint(Elem * e)201846d884bbSDavid du Colombier asn1mpint(Elem *e)
201946d884bbSDavid du Colombier {
202046d884bbSDavid du Colombier 	Bytes *b;
202146d884bbSDavid du Colombier 	mpint *mp;
202246d884bbSDavid du Colombier 	int v;
202346d884bbSDavid du Colombier 
202446d884bbSDavid du Colombier 	if(is_int(e, &v))
202546d884bbSDavid du Colombier 		return itomp(v, nil);
202646d884bbSDavid du Colombier 	if(is_bigint(e, &b)) {
202746d884bbSDavid du Colombier 		mp = betomp(b->data, b->len, nil);
202846d884bbSDavid du Colombier 		freebytes(b);
202946d884bbSDavid du Colombier 		return mp;
203046d884bbSDavid du Colombier 	}
203146d884bbSDavid du Colombier 	return nil;
203246d884bbSDavid du Colombier }
203346d884bbSDavid du Colombier 
203446d884bbSDavid du Colombier static mpint*
pkcs1pad(Bytes * b,mpint * modulus)203546d884bbSDavid du Colombier pkcs1pad(Bytes *b, mpint *modulus)
203646d884bbSDavid du Colombier {
203746d884bbSDavid du Colombier 	int n = (mpsignif(modulus)+7)/8;
203846d884bbSDavid du Colombier 	int pm1, i;
203946d884bbSDavid du Colombier 	uchar *p;
204046d884bbSDavid du Colombier 	mpint *mp;
204146d884bbSDavid du Colombier 
204246d884bbSDavid du Colombier 	pm1 = n - 1 - b->len;
204346d884bbSDavid du Colombier 	p = (uchar*)emalloc(n);
204446d884bbSDavid du Colombier 	p[0] = 0;
204546d884bbSDavid du Colombier 	p[1] = 1;
204646d884bbSDavid du Colombier 	for(i = 2; i < pm1; i++)
204746d884bbSDavid du Colombier 		p[i] = 0xFF;
204846d884bbSDavid du Colombier 	p[pm1] = 0;
204946d884bbSDavid du Colombier 	memcpy(&p[pm1+1], b->data, b->len);
205046d884bbSDavid du Colombier 	mp = betomp(p, n, nil);
205146d884bbSDavid du Colombier 	free(p);
205246d884bbSDavid du Colombier 	return mp;
205346d884bbSDavid du Colombier }
205446d884bbSDavid du Colombier 
205546d884bbSDavid du Colombier RSApriv*
asn1toRSApriv(uchar * kd,int kn)205646d884bbSDavid du Colombier asn1toRSApriv(uchar *kd, int kn)
205746d884bbSDavid du Colombier {
205846d884bbSDavid du Colombier 	Bytes *b;
205946d884bbSDavid du Colombier 	RSApriv *key;
206046d884bbSDavid du Colombier 
206146d884bbSDavid du Colombier 	b = makebytes(kd, kn);
206246d884bbSDavid du Colombier 	key = decode_rsaprivkey(b);
206346d884bbSDavid du Colombier 	freebytes(b);
206446d884bbSDavid du Colombier 	return key;
206546d884bbSDavid du Colombier }
206646d884bbSDavid du Colombier 
206746d884bbSDavid du Colombier DSApriv*
asn1toDSApriv(uchar * kd,int kn)206846d884bbSDavid du Colombier asn1toDSApriv(uchar *kd, int kn)
206946d884bbSDavid du Colombier {
207046d884bbSDavid du Colombier 	Bytes *b;
207146d884bbSDavid du Colombier 	DSApriv *key;
207246d884bbSDavid du Colombier 
207346d884bbSDavid du Colombier 	b = makebytes(kd, kn);
207446d884bbSDavid du Colombier 	key = decode_dsaprivkey(b);
207546d884bbSDavid du Colombier 	freebytes(b);
207646d884bbSDavid du Colombier 	return key;
207746d884bbSDavid du Colombier }
207846d884bbSDavid du Colombier 
207946d884bbSDavid du Colombier /*
208046d884bbSDavid du Colombier  * digest(CertificateInfo)
208146d884bbSDavid du Colombier  * Our ASN.1 library doesn't return pointers into the original
208246d884bbSDavid du Colombier  * data array, so we need to do a little hand decoding.
208346d884bbSDavid du Colombier  */
208446d884bbSDavid du Colombier static void
digest_certinfo(Bytes * cert,DigestFun digestfun,uchar * digest)208546d884bbSDavid du Colombier digest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest)
208646d884bbSDavid du Colombier {
208746d884bbSDavid du Colombier 	uchar *info, *p, *pend;
208846d884bbSDavid du Colombier 	ulong infolen;
208946d884bbSDavid du Colombier 	int isconstr, length;
209046d884bbSDavid du Colombier 	Tag tag;
209146d884bbSDavid du Colombier 	Elem elem;
209246d884bbSDavid du Colombier 
209346d884bbSDavid du Colombier 	p = cert->data;
209446d884bbSDavid du Colombier 	pend = cert->data + cert->len;
209546d884bbSDavid du Colombier 	if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK ||
209646d884bbSDavid du Colombier 	   tag.class != Universal || tag.num != SEQUENCE ||
209746d884bbSDavid du Colombier 	   length_decode(&p, pend, &length) != ASN_OK ||
209846d884bbSDavid du Colombier 	   p+length > pend ||
209946d884bbSDavid du Colombier 	   p+length < p)
210046d884bbSDavid du Colombier 		return;
210146d884bbSDavid du Colombier 	info = p;
210246d884bbSDavid du Colombier 	if(ber_decode(&p, pend, &elem) != ASN_OK)
210346d884bbSDavid du Colombier 		return;
210446d884bbSDavid du Colombier 	freevalfields(&elem.val);
210546d884bbSDavid du Colombier 	if(elem.tag.num != SEQUENCE)
210646d884bbSDavid du Colombier 		return;
210746d884bbSDavid du Colombier 	infolen = p - info;
210846d884bbSDavid du Colombier 	(*digestfun)(info, infolen, digest, nil);
210946d884bbSDavid du Colombier }
211046d884bbSDavid du Colombier 
211146d884bbSDavid du Colombier static char*
verify_signature(Bytes * signature,RSApub * pk,uchar * edigest,Elem ** psigalg)211246d884bbSDavid du Colombier verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg)
211346d884bbSDavid du Colombier {
211446d884bbSDavid du Colombier 	Elem e;
211546d884bbSDavid du Colombier 	Elist *el;
211646d884bbSDavid du Colombier 	Bytes *digest;
211746d884bbSDavid du Colombier 	uchar *pkcs1buf, *buf;
211846d884bbSDavid du Colombier 	int buflen;
211946d884bbSDavid du Colombier 	mpint *pkcs1;
212046d884bbSDavid du Colombier 	int nlen;
212146d884bbSDavid du Colombier 	char *err;
212246d884bbSDavid du Colombier 
212346d884bbSDavid du Colombier 	err = nil;
212446d884bbSDavid du Colombier 	pkcs1buf = nil;
212546d884bbSDavid du Colombier 
212646d884bbSDavid du Colombier 	/* one less than the byte length of the modulus */
212746d884bbSDavid du Colombier 	nlen = (mpsignif(pk->n)-1)/8;
212846d884bbSDavid du Colombier 
212946d884bbSDavid du Colombier 	/* see 9.2.1 of rfc2437 */
213046d884bbSDavid du Colombier 	pkcs1 = betomp(signature->data, signature->len, nil);
213146d884bbSDavid du Colombier 	mpexp(pkcs1, pk->ek, pk->n, pkcs1);
213246d884bbSDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &pkcs1buf);
213346d884bbSDavid du Colombier 	buf = pkcs1buf;
213446d884bbSDavid du Colombier 	if(buflen != nlen || buf[0] != 1) {
213546d884bbSDavid du Colombier 		err = "expected 1";
213646d884bbSDavid du Colombier 		goto end;
213746d884bbSDavid du Colombier 	}
213846d884bbSDavid du Colombier 	buf++;
213946d884bbSDavid du Colombier 	while(buf[0] == 0xff)
214046d884bbSDavid du Colombier 		buf++;
214146d884bbSDavid du Colombier 	if(buf[0] != 0) {
214246d884bbSDavid du Colombier 		err = "expected 0";
214346d884bbSDavid du Colombier 		goto end;
214446d884bbSDavid du Colombier 	}
214546d884bbSDavid du Colombier 	buf++;
214646d884bbSDavid du Colombier 	buflen -= buf-pkcs1buf;
214746d884bbSDavid du Colombier 	if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 ||
214846d884bbSDavid du Colombier 			!is_octetstring(&el->tl->hd, &digest)) {
214946d884bbSDavid du Colombier 		err = "signature parse error";
215046d884bbSDavid du Colombier 		goto end;
215146d884bbSDavid du Colombier 	}
215246d884bbSDavid du Colombier 	*psigalg = &el->hd;
215346d884bbSDavid du Colombier 	if(memcmp(digest->data, edigest, digest->len) == 0)
215446d884bbSDavid du Colombier 		goto end;
215546d884bbSDavid du Colombier 	err = "digests did not match";
215646d884bbSDavid du Colombier 
215746d884bbSDavid du Colombier end:
215846d884bbSDavid du Colombier 	if(pkcs1 != nil)
215946d884bbSDavid du Colombier 		mpfree(pkcs1);
216046d884bbSDavid du Colombier 	if(pkcs1buf != nil)
216146d884bbSDavid du Colombier 		free(pkcs1buf);
216246d884bbSDavid du Colombier 	return err;
216346d884bbSDavid du Colombier }
216446d884bbSDavid du Colombier 
216546d884bbSDavid du Colombier RSApub*
X509toRSApub(uchar * cert,int ncert,char * name,int nname)216646d884bbSDavid du Colombier X509toRSApub(uchar *cert, int ncert, char *name, int nname)
216746d884bbSDavid du Colombier {
216846d884bbSDavid du Colombier 	char *e;
216946d884bbSDavid du Colombier 	Bytes *b;
217046d884bbSDavid du Colombier 	CertX509 *c;
217146d884bbSDavid du Colombier 	RSApub *pk;
217246d884bbSDavid du Colombier 
217346d884bbSDavid du Colombier 	b = makebytes(cert, ncert);
217446d884bbSDavid du Colombier 	c = decode_cert(b);
217546d884bbSDavid du Colombier 	freebytes(b);
217646d884bbSDavid du Colombier 	if(c == nil)
217746d884bbSDavid du Colombier 		return nil;
217846d884bbSDavid du Colombier 	if(name != nil && c->subject != nil){
217946d884bbSDavid du Colombier 		e = strchr(c->subject, ',');
218046d884bbSDavid du Colombier 		if(e != nil)
218146d884bbSDavid du Colombier 			*e = 0;	/* take just CN part of Distinguished Name */
218246d884bbSDavid du Colombier 		strncpy(name, c->subject, nname);
218346d884bbSDavid du Colombier 	}
218446d884bbSDavid du Colombier 	pk = decode_rsapubkey(c->publickey);
218546d884bbSDavid du Colombier 	freecert(c);
218646d884bbSDavid du Colombier 	return pk;
218746d884bbSDavid du Colombier }
218846d884bbSDavid du Colombier 
2189*f591d971SDavid du Colombier int
getalgo(Elem * e)2190*f591d971SDavid du Colombier getalgo(Elem *e)
2191*f591d971SDavid du Colombier {
2192*f591d971SDavid du Colombier 	Value *v;
2193*f591d971SDavid du Colombier 	Elist *el;
2194*f591d971SDavid du Colombier 	int a;
2195*f591d971SDavid du Colombier 
2196*f591d971SDavid du Colombier 	if((a = parse_alg(e)) >= 0)
2197*f591d971SDavid du Colombier 		return a;
2198*f591d971SDavid du Colombier 	v = &e->val;
2199*f591d971SDavid du Colombier 	if(v->tag == VSeq){
2200*f591d971SDavid du Colombier 		print("Seq\n");
2201*f591d971SDavid du Colombier 		for(el = v->u.seqval; el!=nil; el = el->tl){
2202*f591d971SDavid du Colombier 			if((a = getalgo(&el->hd)) >= 0)
2203*f591d971SDavid du Colombier 				return a;
2204*f591d971SDavid du Colombier 		}
2205*f591d971SDavid du Colombier 	}
2206*f591d971SDavid du Colombier 	return -1;
2207*f591d971SDavid du Colombier }
2208*f591d971SDavid du Colombier 
2209*f591d971SDavid du Colombier static void edump(Elem e);
2210*f591d971SDavid du Colombier 
2211*f591d971SDavid du Colombier RSApub*
asn1toRSApub(uchar * der,int nder)2212*f591d971SDavid du Colombier asn1toRSApub(uchar *der, int nder)
2213*f591d971SDavid du Colombier {
2214*f591d971SDavid du Colombier 	Elem e;
2215*f591d971SDavid du Colombier 	Elist *el, *l;
2216*f591d971SDavid du Colombier 	int n;
2217*f591d971SDavid du Colombier 	Bits *b;
2218*f591d971SDavid du Colombier 	RSApub *key;
2219*f591d971SDavid du Colombier 	mpint *mp;
2220*f591d971SDavid du Colombier 
2221*f591d971SDavid du Colombier 	if(decode(der, nder, &e) != ASN_OK){
2222*f591d971SDavid du Colombier 		print("didn't parse\n");
2223*f591d971SDavid du Colombier 		return nil;
2224*f591d971SDavid du Colombier 	}
2225*f591d971SDavid du Colombier 	if(!is_seq(&e, &el)){
2226*f591d971SDavid du Colombier 		print("no seq");
2227*f591d971SDavid du Colombier 		return nil;
2228*f591d971SDavid du Colombier 	}
2229*f591d971SDavid du Colombier 	if((n = elistlen(el)) != 2){
2230*f591d971SDavid du Colombier 		print("bad length %d\n", n);
2231*f591d971SDavid du Colombier 		return nil;
2232*f591d971SDavid du Colombier 	}
2233*f591d971SDavid du Colombier 	if((n = getalgo(&el->hd)) < 0){
2234*f591d971SDavid du Colombier 		print("no algo\n");
2235*f591d971SDavid du Colombier 		return nil;
2236*f591d971SDavid du Colombier 	}
2237*f591d971SDavid du Colombier 	if(n != 0){
2238*f591d971SDavid du Colombier 		print("cant do algorithm %d\n", n);
2239*f591d971SDavid du Colombier 		return nil;
2240*f591d971SDavid du Colombier 	}
2241*f591d971SDavid du Colombier 	if(!is_bitstring(&el->tl->hd, &b)){
2242*f591d971SDavid du Colombier 		print("no bits\n");
2243*f591d971SDavid du Colombier 		return nil;
2244*f591d971SDavid du Colombier 	}
2245*f591d971SDavid du Colombier 	if(decode(b->data, b->len, &e) != ASN_OK){
2246*f591d971SDavid du Colombier 		print("no second decode\n");
2247*f591d971SDavid du Colombier 		return nil;
2248*f591d971SDavid du Colombier 	}
2249*f591d971SDavid du Colombier 	if(!is_seq(&e, &el)){
2250*f591d971SDavid du Colombier 		print("no second seq\n");
2251*f591d971SDavid du Colombier 		return nil;
2252*f591d971SDavid du Colombier 	}
2253*f591d971SDavid du Colombier 	if(elistlen(el) != 2){
2254*f591d971SDavid du Colombier 		print("no second length\n");
2255*f591d971SDavid du Colombier 		return nil;
2256*f591d971SDavid du Colombier 	}
2257*f591d971SDavid du Colombier 	key = rsapuballoc();
2258*f591d971SDavid du Colombier 
2259*f591d971SDavid du Colombier 	l = el;
2260*f591d971SDavid du Colombier 
2261*f591d971SDavid du Colombier 	key->n = mp = asn1mpint(&el->hd);
2262*f591d971SDavid du Colombier 	if(mp == nil)
2263*f591d971SDavid du Colombier 		goto errret;
2264*f591d971SDavid du Colombier 
2265*f591d971SDavid du Colombier 	el = el->tl;
2266*f591d971SDavid du Colombier 	key->ek = mp = asn1mpint(&el->hd);
2267*f591d971SDavid du Colombier 	if(mp == nil)
2268*f591d971SDavid du Colombier 		goto errret;
2269*f591d971SDavid du Colombier 
2270*f591d971SDavid du Colombier 	if(l != nil)
2271*f591d971SDavid du Colombier 		freeelist(l);
2272*f591d971SDavid du Colombier 	return key;
2273*f591d971SDavid du Colombier errret:
2274*f591d971SDavid du Colombier 	if(l != nil)
2275*f591d971SDavid du Colombier 		freeelist(l);
2276*f591d971SDavid du Colombier 	rsapubfree(key);
2277*f591d971SDavid du Colombier 	return nil;
2278*f591d971SDavid du Colombier }
2279*f591d971SDavid du Colombier 
228046d884bbSDavid du Colombier char*
X509verify(uchar * cert,int ncert,RSApub * pk)228146d884bbSDavid du Colombier X509verify(uchar *cert, int ncert, RSApub *pk)
228246d884bbSDavid du Colombier {
228346d884bbSDavid du Colombier 	char *e;
228446d884bbSDavid du Colombier 	Bytes *b;
228546d884bbSDavid du Colombier 	CertX509 *c;
228646d884bbSDavid du Colombier 	uchar digest[SHA1dlen];
228746d884bbSDavid du Colombier 	Elem *sigalg;
228846d884bbSDavid du Colombier 
228946d884bbSDavid du Colombier 	b = makebytes(cert, ncert);
229046d884bbSDavid du Colombier 	c = decode_cert(b);
229146d884bbSDavid du Colombier 	if(c != nil)
229246d884bbSDavid du Colombier 		digest_certinfo(b, digestalg[c->signature_alg], digest);
229346d884bbSDavid du Colombier 	freebytes(b);
229446d884bbSDavid du Colombier 	if(c == nil)
229546d884bbSDavid du Colombier 		return "cannot decode cert";
229646d884bbSDavid du Colombier 	e = verify_signature(c->signature, pk, digest, &sigalg);
229746d884bbSDavid du Colombier 	freecert(c);
229846d884bbSDavid du Colombier 	return e;
229946d884bbSDavid du Colombier }
230046d884bbSDavid du Colombier 
230146d884bbSDavid du Colombier /* ------- Elem constructors ---------- */
230246d884bbSDavid du Colombier static Elem
Null(void)230346d884bbSDavid du Colombier Null(void)
230446d884bbSDavid du Colombier {
230546d884bbSDavid du Colombier 	Elem e;
230646d884bbSDavid du Colombier 
230746d884bbSDavid du Colombier 	e.tag.class = Universal;
230846d884bbSDavid du Colombier 	e.tag.num = NULLTAG;
230946d884bbSDavid du Colombier 	e.val.tag = VNull;
231046d884bbSDavid du Colombier 	return e;
231146d884bbSDavid du Colombier }
231246d884bbSDavid du Colombier 
231346d884bbSDavid du Colombier static Elem
mkint(int j)231446d884bbSDavid du Colombier mkint(int j)
231546d884bbSDavid du Colombier {
231646d884bbSDavid du Colombier 	Elem e;
231746d884bbSDavid du Colombier 
231846d884bbSDavid du Colombier 	e.tag.class = Universal;
231946d884bbSDavid du Colombier 	e.tag.num = INTEGER;
232046d884bbSDavid du Colombier 	e.val.tag = VInt;
232146d884bbSDavid du Colombier 	e.val.u.intval = j;
232246d884bbSDavid du Colombier 	return e;
232346d884bbSDavid du Colombier }
232446d884bbSDavid du Colombier 
232546d884bbSDavid du Colombier static Elem
mkbigint(mpint * p)232646d884bbSDavid du Colombier mkbigint(mpint *p)
232746d884bbSDavid du Colombier {
232846d884bbSDavid du Colombier 	Elem e;
232946d884bbSDavid du Colombier 	uchar *buf;
233046d884bbSDavid du Colombier 	int buflen;
233146d884bbSDavid du Colombier 
233246d884bbSDavid du Colombier 	e.tag.class = Universal;
233346d884bbSDavid du Colombier 	e.tag.num = INTEGER;
233446d884bbSDavid du Colombier 	e.val.tag = VBigInt;
233546d884bbSDavid du Colombier 	buflen = mptobe(p, nil, 0, &buf);
233646d884bbSDavid du Colombier 	e.val.u.bigintval = makebytes(buf, buflen);
233746d884bbSDavid du Colombier 	free(buf);
233846d884bbSDavid du Colombier 	return e;
233946d884bbSDavid du Colombier }
234046d884bbSDavid du Colombier 
234146d884bbSDavid du Colombier static Elem
mkstring(char * s)234246d884bbSDavid du Colombier mkstring(char *s)
234346d884bbSDavid du Colombier {
234446d884bbSDavid du Colombier 	Elem e;
234546d884bbSDavid du Colombier 
234646d884bbSDavid du Colombier 	e.tag.class = Universal;
234746d884bbSDavid du Colombier 	e.tag.num = IA5String;
234846d884bbSDavid du Colombier 	e.val.tag = VString;
234946d884bbSDavid du Colombier 	e.val.u.stringval = estrdup(s);
235046d884bbSDavid du Colombier 	return e;
235146d884bbSDavid du Colombier }
235246d884bbSDavid du Colombier 
235346d884bbSDavid du Colombier static Elem
mkoctet(uchar * buf,int buflen)235446d884bbSDavid du Colombier mkoctet(uchar *buf, int buflen)
235546d884bbSDavid du Colombier {
235646d884bbSDavid du Colombier 	Elem e;
235746d884bbSDavid du Colombier 
235846d884bbSDavid du Colombier 	e.tag.class = Universal;
235946d884bbSDavid du Colombier 	e.tag.num = OCTET_STRING;
236046d884bbSDavid du Colombier 	e.val.tag = VOctets;
236146d884bbSDavid du Colombier 	e.val.u.octetsval = makebytes(buf, buflen);
236246d884bbSDavid du Colombier 	return e;
236346d884bbSDavid du Colombier }
236446d884bbSDavid du Colombier 
236546d884bbSDavid du Colombier static Elem
mkbits(uchar * buf,int buflen)236646d884bbSDavid du Colombier mkbits(uchar *buf, int buflen)
236746d884bbSDavid du Colombier {
236846d884bbSDavid du Colombier 	Elem e;
236946d884bbSDavid du Colombier 
237046d884bbSDavid du Colombier 	e.tag.class = Universal;
237146d884bbSDavid du Colombier 	e.tag.num = BIT_STRING;
237246d884bbSDavid du Colombier 	e.val.tag = VBitString;
237346d884bbSDavid du Colombier 	e.val.u.bitstringval = makebits(buf, buflen, 0);
237446d884bbSDavid du Colombier 	return e;
237546d884bbSDavid du Colombier }
237646d884bbSDavid du Colombier 
237746d884bbSDavid du Colombier static Elem
mkutc(long t)237846d884bbSDavid du Colombier mkutc(long t)
237946d884bbSDavid du Colombier {
238046d884bbSDavid du Colombier 	Elem e;
238146d884bbSDavid du Colombier 	char utc[50];
2382*f591d971SDavid du Colombier 	Tm *tm = gmtime(t);
238346d884bbSDavid du Colombier 
238446d884bbSDavid du Colombier 	e.tag.class = Universal;
238546d884bbSDavid du Colombier 	e.tag.num = UTCTime;
238646d884bbSDavid du Colombier 	e.val.tag = VString;
238746d884bbSDavid du Colombier 	snprint(utc, 50, "%.2d%.2d%.2d%.2d%.2d%.2dZ",
2388*f591d971SDavid du Colombier 		tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec);
238946d884bbSDavid du Colombier 	e.val.u.stringval = estrdup(utc);
239046d884bbSDavid du Colombier 	return e;
239146d884bbSDavid du Colombier }
239246d884bbSDavid du Colombier 
239346d884bbSDavid du Colombier static Elem
mkoid(Ints * oid)239446d884bbSDavid du Colombier mkoid(Ints *oid)
239546d884bbSDavid du Colombier {
239646d884bbSDavid du Colombier 	Elem e;
239746d884bbSDavid du Colombier 
239846d884bbSDavid du Colombier 	e.tag.class = Universal;
239946d884bbSDavid du Colombier 	e.tag.num = OBJECT_ID;
240046d884bbSDavid du Colombier 	e.val.tag = VObjId;
240146d884bbSDavid du Colombier 	e.val.u.objidval = makeints(oid->data, oid->len);
240246d884bbSDavid du Colombier 	return e;
240346d884bbSDavid du Colombier }
240446d884bbSDavid du Colombier 
240546d884bbSDavid du Colombier static Elem
mkseq(Elist * el)240646d884bbSDavid du Colombier mkseq(Elist *el)
240746d884bbSDavid du Colombier {
240846d884bbSDavid du Colombier 	Elem e;
240946d884bbSDavid du Colombier 
241046d884bbSDavid du Colombier 	e.tag.class = Universal;
241146d884bbSDavid du Colombier 	e.tag.num = SEQUENCE;
241246d884bbSDavid du Colombier 	e.val.tag = VSeq;
241346d884bbSDavid du Colombier 	e.val.u.seqval = el;
241446d884bbSDavid du Colombier 	return e;
241546d884bbSDavid du Colombier }
241646d884bbSDavid du Colombier 
241746d884bbSDavid du Colombier static Elem
mkset(Elist * el)241846d884bbSDavid du Colombier mkset(Elist *el)
241946d884bbSDavid du Colombier {
242046d884bbSDavid du Colombier 	Elem e;
242146d884bbSDavid du Colombier 
242246d884bbSDavid du Colombier 	e.tag.class = Universal;
242346d884bbSDavid du Colombier 	e.tag.num = SETOF;
242446d884bbSDavid du Colombier 	e.val.tag = VSet;
242546d884bbSDavid du Colombier 	e.val.u.setval = el;
242646d884bbSDavid du Colombier 	return e;
242746d884bbSDavid du Colombier }
242846d884bbSDavid du Colombier 
242946d884bbSDavid du Colombier static Elem
mkalg(int alg)243046d884bbSDavid du Colombier mkalg(int alg)
243146d884bbSDavid du Colombier {
243246d884bbSDavid du Colombier 	return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil)));
243346d884bbSDavid du Colombier }
243446d884bbSDavid du Colombier 
243546d884bbSDavid du Colombier typedef struct Ints7pref {
243646d884bbSDavid du Colombier 	int		len;
243746d884bbSDavid du Colombier 	int		data[7];
243846d884bbSDavid du Colombier 	char	prefix[4];
243946d884bbSDavid du Colombier } Ints7pref;
244046d884bbSDavid du Colombier Ints7pref DN_oid[] = {
244146d884bbSDavid du Colombier 	{4, 2, 5, 4, 6, 0, 0, 0,  "C="},
244246d884bbSDavid du Colombier 	{4, 2, 5, 4, 8, 0, 0, 0,  "ST="},
244346d884bbSDavid du Colombier 	{4, 2, 5, 4, 7, 0, 0, 0,  "L="},
244446d884bbSDavid du Colombier 	{4, 2, 5, 4, 10, 0, 0, 0, "O="},
244546d884bbSDavid du Colombier 	{4, 2, 5, 4, 11, 0, 0, 0, "OU="},
244646d884bbSDavid du Colombier 	{4, 2, 5, 4, 3, 0, 0, 0,  "CN="},
244746d884bbSDavid du Colombier  	{7, 1,2,840,113549,1,9,1, "E="},
244846d884bbSDavid du Colombier };
244946d884bbSDavid du Colombier 
245046d884bbSDavid du Colombier static Elem
mkname(Ints7pref * oid,char * subj)245146d884bbSDavid du Colombier mkname(Ints7pref *oid, char *subj)
245246d884bbSDavid du Colombier {
245346d884bbSDavid du Colombier 	return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj), nil))), nil));
245446d884bbSDavid du Colombier }
245546d884bbSDavid du Colombier 
245646d884bbSDavid du Colombier static Elem
mkDN(char * dn)245746d884bbSDavid du Colombier mkDN(char *dn)
245846d884bbSDavid du Colombier {
245946d884bbSDavid du Colombier 	int i, j, nf;
246046d884bbSDavid du Colombier 	char *f[20], *prefix, *d2 = estrdup(dn);
246146d884bbSDavid du Colombier 	Elist* el = nil;
246246d884bbSDavid du Colombier 
246346d884bbSDavid du Colombier 	nf = tokenize(d2, f, nelem(f));
246446d884bbSDavid du Colombier 	for(i=nf-1; i>=0; i--){
246546d884bbSDavid du Colombier 		for(j=0; j<nelem(DN_oid); j++){
246646d884bbSDavid du Colombier 			prefix = DN_oid[j].prefix;
246746d884bbSDavid du Colombier 			if(strncmp(f[i],prefix,strlen(prefix))==0){
246846d884bbSDavid du Colombier 				el = mkel(mkname(&DN_oid[j],f[i]+strlen(prefix)), el);
246946d884bbSDavid du Colombier 				break;
247046d884bbSDavid du Colombier 			}
247146d884bbSDavid du Colombier 		}
247246d884bbSDavid du Colombier 	}
247346d884bbSDavid du Colombier 	free(d2);
247446d884bbSDavid du Colombier 	return mkseq(el);
247546d884bbSDavid du Colombier }
247646d884bbSDavid du Colombier 
2477*f591d971SDavid du Colombier uchar*
RSApubtoasn1(RSApub * pub,int * keylen)2478*f591d971SDavid du Colombier RSApubtoasn1(RSApub *pub, int *keylen)
2479*f591d971SDavid du Colombier {
2480*f591d971SDavid du Colombier 	Elem pubkey;
2481*f591d971SDavid du Colombier 	Bytes *pkbytes;
2482*f591d971SDavid du Colombier 	uchar *key;
2483*f591d971SDavid du Colombier 
2484*f591d971SDavid du Colombier 	key = nil;
2485*f591d971SDavid du Colombier 	pubkey = mkseq(mkel(mkbigint(pub->n),mkel(mkint(mptoi(pub->ek)),nil)));
2486*f591d971SDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
2487*f591d971SDavid du Colombier 		goto errret;
2488*f591d971SDavid du Colombier 	freevalfields(&pubkey.val);
2489*f591d971SDavid du Colombier 	pubkey = mkseq(
2490*f591d971SDavid du Colombier 		mkel(mkalg(ALG_rsaEncryption),
2491*f591d971SDavid du Colombier 		mkel(mkbits(pkbytes->data, pkbytes->len),
2492*f591d971SDavid du Colombier 		nil)));
2493*f591d971SDavid du Colombier 	freebytes(pkbytes);
2494*f591d971SDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
2495*f591d971SDavid du Colombier 		goto errret;
2496*f591d971SDavid du Colombier 	if(keylen)
2497*f591d971SDavid du Colombier 		*keylen = pkbytes->len;
2498*f591d971SDavid du Colombier 	key = malloc(pkbytes->len);
2499*f591d971SDavid du Colombier 	memmove(key, pkbytes->data, pkbytes->len);
2500*f591d971SDavid du Colombier 	free(pkbytes);
2501*f591d971SDavid du Colombier errret:
2502*f591d971SDavid du Colombier 	freevalfields(&pubkey.val);
2503*f591d971SDavid du Colombier 	return key;
2504*f591d971SDavid du Colombier }
250546d884bbSDavid du Colombier 
250646d884bbSDavid du Colombier uchar*
X509gen(RSApriv * priv,char * subj,ulong valid[2],int * certlen)250746d884bbSDavid du Colombier X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
250846d884bbSDavid du Colombier {
250946d884bbSDavid du Colombier 	int serial = 0;
251046d884bbSDavid du Colombier 	uchar *cert = nil;
251146d884bbSDavid du Colombier 	RSApub *pk = rsaprivtopub(priv);
251246d884bbSDavid du Colombier 	Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
251346d884bbSDavid du Colombier 	Elem e, certinfo, issuer, subject, pubkey, validity, sig;
251446d884bbSDavid du Colombier 	uchar digest[MD5dlen], *buf;
251546d884bbSDavid du Colombier 	int buflen;
251646d884bbSDavid du Colombier 	mpint *pkcs1;
251746d884bbSDavid du Colombier 
251846d884bbSDavid du Colombier 	e.val.tag = VInt;  /* so freevalfields at errret is no-op */
251946d884bbSDavid du Colombier 	issuer = mkDN(subj);
252046d884bbSDavid du Colombier 	subject = mkDN(subj);
252146d884bbSDavid du Colombier 	pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
252246d884bbSDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
252346d884bbSDavid du Colombier 		goto errret;
252446d884bbSDavid du Colombier 	freevalfields(&pubkey.val);
252546d884bbSDavid du Colombier 	pubkey = mkseq(
252646d884bbSDavid du Colombier 		mkel(mkalg(ALG_rsaEncryption),
252746d884bbSDavid du Colombier 		mkel(mkbits(pkbytes->data, pkbytes->len),
252846d884bbSDavid du Colombier 		nil)));
252946d884bbSDavid du Colombier 	freebytes(pkbytes);
253046d884bbSDavid du Colombier 	validity = mkseq(
253146d884bbSDavid du Colombier 		mkel(mkutc(valid[0]),
253246d884bbSDavid du Colombier 		mkel(mkutc(valid[1]),
253346d884bbSDavid du Colombier 		nil)));
253446d884bbSDavid du Colombier 	certinfo = mkseq(
253546d884bbSDavid du Colombier 		mkel(mkint(serial),
253646d884bbSDavid du Colombier 		mkel(mkalg(ALG_md5WithRSAEncryption),
253746d884bbSDavid du Colombier 		mkel(issuer,
253846d884bbSDavid du Colombier 		mkel(validity,
253946d884bbSDavid du Colombier 		mkel(subject,
254046d884bbSDavid du Colombier 		mkel(pubkey,
254146d884bbSDavid du Colombier 		nil)))))));
254246d884bbSDavid du Colombier 	if(encode(certinfo, &certinfobytes) != ASN_OK)
254346d884bbSDavid du Colombier 		goto errret;
254446d884bbSDavid du Colombier 	md5(certinfobytes->data, certinfobytes->len, digest, 0);
254546d884bbSDavid du Colombier 	freebytes(certinfobytes);
254646d884bbSDavid du Colombier 	sig = mkseq(
254746d884bbSDavid du Colombier 		mkel(mkalg(ALG_md5),
254846d884bbSDavid du Colombier 		mkel(mkoctet(digest, MD5dlen),
254946d884bbSDavid du Colombier 		nil)));
255046d884bbSDavid du Colombier 	if(encode(sig, &sigbytes) != ASN_OK)
255146d884bbSDavid du Colombier 		goto errret;
255246d884bbSDavid du Colombier 	pkcs1 = pkcs1pad(sigbytes, pk->n);
255346d884bbSDavid du Colombier 	freebytes(sigbytes);
255446d884bbSDavid du Colombier 	rsadecrypt(priv, pkcs1, pkcs1);
255546d884bbSDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &buf);
255646d884bbSDavid du Colombier 	mpfree(pkcs1);
255746d884bbSDavid du Colombier 	e = mkseq(
255846d884bbSDavid du Colombier 		mkel(certinfo,
255946d884bbSDavid du Colombier 		mkel(mkalg(ALG_md5WithRSAEncryption),
256046d884bbSDavid du Colombier 		mkel(mkbits(buf, buflen),
256146d884bbSDavid du Colombier 		nil))));
256246d884bbSDavid du Colombier 	free(buf);
256346d884bbSDavid du Colombier 	if(encode(e, &certbytes) != ASN_OK)
256446d884bbSDavid du Colombier 		goto errret;
256546d884bbSDavid du Colombier 	if(certlen)
256646d884bbSDavid du Colombier 		*certlen = certbytes->len;
256746d884bbSDavid du Colombier 	cert = certbytes->data;
256846d884bbSDavid du Colombier errret:
256946d884bbSDavid du Colombier 	freevalfields(&e.val);
257046d884bbSDavid du Colombier 	return cert;
257146d884bbSDavid du Colombier }
257246d884bbSDavid du Colombier 
257346d884bbSDavid du Colombier uchar*
X509req(RSApriv * priv,char * subj,int * certlen)257446d884bbSDavid du Colombier X509req(RSApriv *priv, char *subj, int *certlen)
257546d884bbSDavid du Colombier {
257646d884bbSDavid du Colombier 	/* RFC 2314, PKCS #10 Certification Request Syntax */
257746d884bbSDavid du Colombier 	int version = 0;
257846d884bbSDavid du Colombier 	uchar *cert = nil;
257946d884bbSDavid du Colombier 	RSApub *pk = rsaprivtopub(priv);
258046d884bbSDavid du Colombier 	Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
258146d884bbSDavid du Colombier 	Elem e, certinfo, subject, pubkey, sig;
258246d884bbSDavid du Colombier 	uchar digest[MD5dlen], *buf;
258346d884bbSDavid du Colombier 	int buflen;
258446d884bbSDavid du Colombier 	mpint *pkcs1;
258546d884bbSDavid du Colombier 
258646d884bbSDavid du Colombier 	e.val.tag = VInt;  /* so freevalfields at errret is no-op */
258746d884bbSDavid du Colombier 	subject = mkDN(subj);
258846d884bbSDavid du Colombier 	pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
258946d884bbSDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
259046d884bbSDavid du Colombier 		goto errret;
259146d884bbSDavid du Colombier 	freevalfields(&pubkey.val);
259246d884bbSDavid du Colombier 	pubkey = mkseq(
259346d884bbSDavid du Colombier 		mkel(mkalg(ALG_rsaEncryption),
259446d884bbSDavid du Colombier 		mkel(mkbits(pkbytes->data, pkbytes->len),
259546d884bbSDavid du Colombier 		nil)));
259646d884bbSDavid du Colombier 	freebytes(pkbytes);
259746d884bbSDavid du Colombier 	certinfo = mkseq(
259846d884bbSDavid du Colombier 		mkel(mkint(version),
259946d884bbSDavid du Colombier 		mkel(subject,
260046d884bbSDavid du Colombier 		mkel(pubkey,
260146d884bbSDavid du Colombier 		nil))));
260246d884bbSDavid du Colombier 	if(encode(certinfo, &certinfobytes) != ASN_OK)
260346d884bbSDavid du Colombier 		goto errret;
260446d884bbSDavid du Colombier 	md5(certinfobytes->data, certinfobytes->len, digest, 0);
260546d884bbSDavid du Colombier 	freebytes(certinfobytes);
260646d884bbSDavid du Colombier 	sig = mkseq(
260746d884bbSDavid du Colombier 		mkel(mkalg(ALG_md5),
260846d884bbSDavid du Colombier 		mkel(mkoctet(digest, MD5dlen),
260946d884bbSDavid du Colombier 		nil)));
261046d884bbSDavid du Colombier 	if(encode(sig, &sigbytes) != ASN_OK)
261146d884bbSDavid du Colombier 		goto errret;
261246d884bbSDavid du Colombier 	pkcs1 = pkcs1pad(sigbytes, pk->n);
261346d884bbSDavid du Colombier 	freebytes(sigbytes);
261446d884bbSDavid du Colombier 	rsadecrypt(priv, pkcs1, pkcs1);
261546d884bbSDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &buf);
261646d884bbSDavid du Colombier 	mpfree(pkcs1);
261746d884bbSDavid du Colombier 	e = mkseq(
261846d884bbSDavid du Colombier 		mkel(certinfo,
261946d884bbSDavid du Colombier 		mkel(mkalg(ALG_md5),
262046d884bbSDavid du Colombier 		mkel(mkbits(buf, buflen),
262146d884bbSDavid du Colombier 		nil))));
262246d884bbSDavid du Colombier 	free(buf);
262346d884bbSDavid du Colombier 	if(encode(e, &certbytes) != ASN_OK)
262446d884bbSDavid du Colombier 		goto errret;
262546d884bbSDavid du Colombier 	if(certlen)
262646d884bbSDavid du Colombier 		*certlen = certbytes->len;
262746d884bbSDavid du Colombier 	cert = certbytes->data;
262846d884bbSDavid du Colombier errret:
262946d884bbSDavid du Colombier 	freevalfields(&e.val);
263046d884bbSDavid du Colombier 	return cert;
263146d884bbSDavid du Colombier }
263246d884bbSDavid du Colombier 
263346d884bbSDavid du Colombier static char*
tagdump(Tag tag)263446d884bbSDavid du Colombier tagdump(Tag tag)
263546d884bbSDavid du Colombier {
263646d884bbSDavid du Colombier 	if(tag.class != Universal)
263746d884bbSDavid du Colombier 		return smprint("class%d,num%d", tag.class, tag.num);
263846d884bbSDavid du Colombier 	switch(tag.num){
263946d884bbSDavid du Colombier 	case BOOLEAN: return "BOOLEAN";
264046d884bbSDavid du Colombier 	case INTEGER: return "INTEGER";
264146d884bbSDavid du Colombier 	case BIT_STRING: return "BIT STRING";
264246d884bbSDavid du Colombier 	case OCTET_STRING: return "OCTET STRING";
264346d884bbSDavid du Colombier 	case NULLTAG: return "NULLTAG";
264446d884bbSDavid du Colombier 	case OBJECT_ID: return "OID";
264546d884bbSDavid du Colombier 	case ObjectDescriptor: return "OBJECT_DES";
264646d884bbSDavid du Colombier 	case EXTERNAL: return "EXTERNAL";
264746d884bbSDavid du Colombier 	case REAL: return "REAL";
264846d884bbSDavid du Colombier 	case ENUMERATED: return "ENUMERATED";
264946d884bbSDavid du Colombier 	case EMBEDDED_PDV: return "EMBEDDED PDV";
265046d884bbSDavid du Colombier 	case SEQUENCE: return "SEQUENCE";
265146d884bbSDavid du Colombier 	case SETOF: return "SETOF";
265246d884bbSDavid du Colombier 	case UTF8String: return "UTF8String";
265346d884bbSDavid du Colombier 	case NumericString: return "NumericString";
265446d884bbSDavid du Colombier 	case PrintableString: return "PrintableString";
265546d884bbSDavid du Colombier 	case TeletexString: return "TeletexString";
265646d884bbSDavid du Colombier 	case VideotexString: return "VideotexString";
265746d884bbSDavid du Colombier 	case IA5String: return "IA5String";
265846d884bbSDavid du Colombier 	case UTCTime: return "UTCTime";
265946d884bbSDavid du Colombier 	case GeneralizedTime: return "GeneralizedTime";
266046d884bbSDavid du Colombier 	case GraphicString: return "GraphicString";
266146d884bbSDavid du Colombier 	case VisibleString: return "VisibleString";
266246d884bbSDavid du Colombier 	case GeneralString: return "GeneralString";
266346d884bbSDavid du Colombier 	case UniversalString: return "UniversalString";
266446d884bbSDavid du Colombier 	case BMPString: return "BMPString";
266546d884bbSDavid du Colombier 	default:
266646d884bbSDavid du Colombier 		return smprint("Universal,num%d", tag.num);
266746d884bbSDavid du Colombier 	}
266846d884bbSDavid du Colombier }
266946d884bbSDavid du Colombier 
267046d884bbSDavid du Colombier static void
edump(Elem e)267146d884bbSDavid du Colombier edump(Elem e)
267246d884bbSDavid du Colombier {
267346d884bbSDavid du Colombier 	Value v;
267446d884bbSDavid du Colombier 	Elist *el;
267546d884bbSDavid du Colombier 	int i;
267646d884bbSDavid du Colombier 
267746d884bbSDavid du Colombier 	print("%s{", tagdump(e.tag));
267846d884bbSDavid du Colombier 	v = e.val;
267946d884bbSDavid du Colombier 	switch(v.tag){
268046d884bbSDavid du Colombier 	case VBool: print("Bool %d",v.u.boolval); break;
268146d884bbSDavid du Colombier 	case VInt: print("Int %d",v.u.intval); break;
268246d884bbSDavid du Colombier 	case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break;
268346d884bbSDavid du Colombier 	case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
268446d884bbSDavid du Colombier 	case VReal: print("Real..."); break;
268546d884bbSDavid du Colombier 	case VOther: print("Other..."); break;
2686*f591d971SDavid du Colombier 	case VBitString: print("BitString");
2687*f591d971SDavid du Colombier 		for(i = 0; i<v.u.bitstringval->len; i++)
2688*f591d971SDavid du Colombier 			print(" %02x", v.u.bitstringval->data[i]);
2689*f591d971SDavid du Colombier 		break;
269046d884bbSDavid du Colombier 	case VNull: print("Null"); break;
269146d884bbSDavid du Colombier 	case VEOC: print("EOC..."); break;
269246d884bbSDavid du Colombier 	case VObjId: print("ObjId");
269346d884bbSDavid du Colombier 		for(i = 0; i<v.u.objidval->len; i++)
269446d884bbSDavid du Colombier 			print(" %d", v.u.objidval->data[i]);
269546d884bbSDavid du Colombier 		break;
269646d884bbSDavid du Colombier 	case VString: print("String \"%s\"",v.u.stringval); break;
269746d884bbSDavid du Colombier 	case VSeq: print("Seq\n");
269846d884bbSDavid du Colombier 		for(el = v.u.seqval; el!=nil; el = el->tl)
269946d884bbSDavid du Colombier 			edump(el->hd);
270046d884bbSDavid du Colombier 		break;
270146d884bbSDavid du Colombier 	case VSet: print("Set\n");
270246d884bbSDavid du Colombier 		for(el = v.u.setval; el!=nil; el = el->tl)
270346d884bbSDavid du Colombier 			edump(el->hd);
270446d884bbSDavid du Colombier 		break;
270546d884bbSDavid du Colombier 	}
270646d884bbSDavid du Colombier 	print("}\n");
270746d884bbSDavid du Colombier }
270846d884bbSDavid du Colombier 
270946d884bbSDavid du Colombier void
asn1dump(uchar * der,int len)271046d884bbSDavid du Colombier asn1dump(uchar *der, int len)
271146d884bbSDavid du Colombier {
271246d884bbSDavid du Colombier 	Elem e;
271346d884bbSDavid du Colombier 
271446d884bbSDavid du Colombier 	if(decode(der, len, &e) != ASN_OK){
271546d884bbSDavid du Colombier 		print("didn't parse\n");
271646d884bbSDavid du Colombier 		exits("didn't parse");
271746d884bbSDavid du Colombier 	}
271846d884bbSDavid du Colombier 	edump(e);
271946d884bbSDavid du Colombier }
272046d884bbSDavid du Colombier 
272146d884bbSDavid du Colombier void
X509dump(uchar * cert,int ncert)272246d884bbSDavid du Colombier X509dump(uchar *cert, int ncert)
272346d884bbSDavid du Colombier {
272446d884bbSDavid du Colombier 	char *e;
272546d884bbSDavid du Colombier 	Bytes *b;
272646d884bbSDavid du Colombier 	CertX509 *c;
272746d884bbSDavid du Colombier 	RSApub *pk;
272846d884bbSDavid du Colombier 	uchar digest[SHA1dlen];
272946d884bbSDavid du Colombier 	Elem *sigalg;
273046d884bbSDavid du Colombier 
273146d884bbSDavid du Colombier 	print("begin X509dump\n");
273246d884bbSDavid du Colombier 	b = makebytes(cert, ncert);
273346d884bbSDavid du Colombier 	c = decode_cert(b);
273446d884bbSDavid du Colombier 	if(c != nil)
273546d884bbSDavid du Colombier 		digest_certinfo(b, digestalg[c->signature_alg], digest);
273646d884bbSDavid du Colombier 	freebytes(b);
273746d884bbSDavid du Colombier 	if(c == nil){
273846d884bbSDavid du Colombier 		print("cannot decode cert");
273946d884bbSDavid du Colombier 		return;
274046d884bbSDavid du Colombier 	}
274146d884bbSDavid du Colombier 
274246d884bbSDavid du Colombier 	print("serial %d\n", c->serial);
274346d884bbSDavid du Colombier 	print("issuer %s\n", c->issuer);
274446d884bbSDavid du Colombier 	print("validity %s %s\n", c->validity_start, c->validity_end);
274546d884bbSDavid du Colombier 	print("subject %s\n", c->subject);
274646d884bbSDavid du Colombier 	pk = decode_rsapubkey(c->publickey);
274746d884bbSDavid du Colombier 	print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n);
274846d884bbSDavid du Colombier 
274946d884bbSDavid du Colombier 	print("sigalg=%d digest=%.*H\n", c->signature_alg, MD5dlen, digest);
275046d884bbSDavid du Colombier 	e = verify_signature(c->signature, pk, digest, &sigalg);
275146d884bbSDavid du Colombier 	if(e==nil){
275246d884bbSDavid du Colombier 		e = "nil (meaning ok)";
275346d884bbSDavid du Colombier 		print("sigalg=\n");
275446d884bbSDavid du Colombier 		if(sigalg)
275546d884bbSDavid du Colombier 			edump(*sigalg);
275646d884bbSDavid du Colombier 	}
275746d884bbSDavid du Colombier 	print("self-signed verify_signature returns: %s\n", e);
275846d884bbSDavid du Colombier 
275946d884bbSDavid du Colombier 	rsapubfree(pk);
276046d884bbSDavid du Colombier 	freecert(c);
276146d884bbSDavid du Colombier 	print("end X509dump\n");
276246d884bbSDavid du Colombier }
2763