xref: /plan9/sys/src/libsec/port/x509.c (revision 39734e7ed1eb944f5e7b41936007d0d38b560d7f)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <mp.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier 
63ff48bf5SDavid du Colombier typedef DigestState*(*DigestFun)(uchar*,ulong,uchar*,DigestState*);
73ff48bf5SDavid du Colombier 
89a747e4fSDavid du Colombier /* ANSI offsetof, backwards. */
99a747e4fSDavid du Colombier #define	OFFSETOF(a, b)	offsetof(b, a)
109a747e4fSDavid du Colombier 
1180ee5cbfSDavid du Colombier /*=============================================================*/
1280ee5cbfSDavid du Colombier /*  general ASN1 declarations and parsing
1380ee5cbfSDavid du Colombier  *
1480ee5cbfSDavid du Colombier  *  For now, this is used only for extracting the key from an
1580ee5cbfSDavid du Colombier  *  X509 certificate, so the entire collection is hidden.  But
1680ee5cbfSDavid du Colombier  *  someday we should probably make the functions visible and
1780ee5cbfSDavid du Colombier  *  give them their own man page.
1880ee5cbfSDavid du Colombier  */
1980ee5cbfSDavid du Colombier typedef struct Elem Elem;
2080ee5cbfSDavid du Colombier typedef struct Tag Tag;
2180ee5cbfSDavid du Colombier typedef struct Value Value;
2280ee5cbfSDavid du Colombier typedef struct Bytes Bytes;
2380ee5cbfSDavid du Colombier typedef struct Ints Ints;
2480ee5cbfSDavid du Colombier typedef struct Bits Bits;
2580ee5cbfSDavid du Colombier typedef struct Elist Elist;
2680ee5cbfSDavid du Colombier 
2780ee5cbfSDavid du Colombier /* tag classes */
2880ee5cbfSDavid du Colombier #define Universal 0
2980ee5cbfSDavid du Colombier #define Context 0x80
3080ee5cbfSDavid du Colombier 
3180ee5cbfSDavid du Colombier /* universal tags */
3280ee5cbfSDavid du Colombier #define BOOLEAN 1
3380ee5cbfSDavid du Colombier #define INTEGER 2
3480ee5cbfSDavid du Colombier #define BIT_STRING 3
3580ee5cbfSDavid du Colombier #define OCTET_STRING 4
3680ee5cbfSDavid du Colombier #define NULLTAG 5
3780ee5cbfSDavid du Colombier #define OBJECT_ID 6
3880ee5cbfSDavid du Colombier #define ObjectDescriptor 7
3980ee5cbfSDavid du Colombier #define EXTERNAL 8
4080ee5cbfSDavid du Colombier #define REAL 9
4180ee5cbfSDavid du Colombier #define ENUMERATED 10
4280ee5cbfSDavid du Colombier #define EMBEDDED_PDV 11
4380ee5cbfSDavid du Colombier #define SEQUENCE 16		/* also SEQUENCE OF */
449a747e4fSDavid du Colombier #define SETOF 17				/* also SETOF OF */
4580ee5cbfSDavid du Colombier #define NumericString 18
4680ee5cbfSDavid du Colombier #define PrintableString 19
4780ee5cbfSDavid du Colombier #define TeletexString 20
4880ee5cbfSDavid du Colombier #define VideotexString 21
4980ee5cbfSDavid du Colombier #define IA5String 22
5080ee5cbfSDavid du Colombier #define UTCTime 23
5180ee5cbfSDavid du Colombier #define GeneralizedTime 24
5280ee5cbfSDavid du Colombier #define GraphicString 25
5380ee5cbfSDavid du Colombier #define VisibleString 26
5480ee5cbfSDavid du Colombier #define GeneralString 27
5580ee5cbfSDavid du Colombier #define UniversalString 28
5680ee5cbfSDavid du Colombier #define BMPString 30
5780ee5cbfSDavid du Colombier 
5880ee5cbfSDavid du Colombier struct Bytes {
5980ee5cbfSDavid du Colombier 	int	len;
6080ee5cbfSDavid du Colombier 	uchar	data[1];
6180ee5cbfSDavid du Colombier };
6280ee5cbfSDavid du Colombier 
6380ee5cbfSDavid du Colombier struct Ints {
6480ee5cbfSDavid du Colombier 	int	len;
6580ee5cbfSDavid du Colombier 	int	data[1];
6680ee5cbfSDavid du Colombier };
6780ee5cbfSDavid du Colombier 
6880ee5cbfSDavid du Colombier struct Bits {
6980ee5cbfSDavid du Colombier 	int	len;		/* number of bytes */
7080ee5cbfSDavid du Colombier 	int	unusedbits;	/* unused bits in last byte */
7180ee5cbfSDavid du Colombier 	uchar	data[1];	/* most-significant bit first */
7280ee5cbfSDavid du Colombier };
7380ee5cbfSDavid du Colombier 
7480ee5cbfSDavid du Colombier struct Tag {
7580ee5cbfSDavid du Colombier 	int	class;
7680ee5cbfSDavid du Colombier 	int	num;
7780ee5cbfSDavid du Colombier };
7880ee5cbfSDavid du Colombier 
7980ee5cbfSDavid du Colombier enum { VBool, VInt, VOctets, VBigInt, VReal, VOther,
8080ee5cbfSDavid du Colombier 	VBitString, VNull, VEOC, VObjId, VString, VSeq, VSet };
8180ee5cbfSDavid du Colombier struct Value {
8280ee5cbfSDavid du Colombier 	int	tag;		/* VBool, etc. */
8380ee5cbfSDavid du Colombier 	union {
8480ee5cbfSDavid du Colombier 		int	boolval;
8580ee5cbfSDavid du Colombier 		int	intval;
8680ee5cbfSDavid du Colombier 		Bytes*	octetsval;
8780ee5cbfSDavid du Colombier 		Bytes*	bigintval;
8880ee5cbfSDavid du Colombier 		Bytes*	realval;	/* undecoded; hardly ever used */
8980ee5cbfSDavid du Colombier 		Bytes*	otherval;
9080ee5cbfSDavid du Colombier 		Bits*	bitstringval;
9180ee5cbfSDavid du Colombier 		Ints*	objidval;
9280ee5cbfSDavid du Colombier 		char*	stringval;
9380ee5cbfSDavid du Colombier 		Elist*	seqval;
9480ee5cbfSDavid du Colombier 		Elist*	setval;
9580ee5cbfSDavid du Colombier 	} u;  /* (Don't use anonymous unions, for ease of porting) */
9680ee5cbfSDavid du Colombier };
9780ee5cbfSDavid du Colombier 
9880ee5cbfSDavid du Colombier struct Elem {
9980ee5cbfSDavid du Colombier 	Tag	tag;
10080ee5cbfSDavid du Colombier 	Value	val;
10180ee5cbfSDavid du Colombier };
10280ee5cbfSDavid du Colombier 
10380ee5cbfSDavid du Colombier struct Elist {
10480ee5cbfSDavid du Colombier 	Elist*	tl;
10580ee5cbfSDavid du Colombier 	Elem	hd;
10680ee5cbfSDavid du Colombier };
10780ee5cbfSDavid du Colombier 
10880ee5cbfSDavid du Colombier /* decoding errors */
10980ee5cbfSDavid du Colombier enum { ASN_OK, ASN_ESHORT, ASN_ETOOBIG, ASN_EVALLEN,
11080ee5cbfSDavid du Colombier 		ASN_ECONSTR, ASN_EPRIM, ASN_EINVAL, ASN_EUNIMPL };
11180ee5cbfSDavid du Colombier 
11280ee5cbfSDavid du Colombier 
11380ee5cbfSDavid du Colombier /* here are the functions to consider making extern someday */
11480ee5cbfSDavid du Colombier static Bytes*	newbytes(int len);
11580ee5cbfSDavid du Colombier static Bytes*	makebytes(uchar* buf, int len);
11680ee5cbfSDavid du Colombier static void	freebytes(Bytes* b);
11780ee5cbfSDavid du Colombier static Bytes*	catbytes(Bytes* b1, Bytes* b2);
11880ee5cbfSDavid du Colombier static Ints*	newints(int len);
11980ee5cbfSDavid du Colombier static Ints*	makeints(int* buf, int len);
12080ee5cbfSDavid du Colombier static void	freeints(Ints* b);
12180ee5cbfSDavid du Colombier static Bits*	newbits(int len);
12280ee5cbfSDavid du Colombier static Bits*	makebits(uchar* buf, int len, int unusedbits);
12380ee5cbfSDavid du Colombier static void	freebits(Bits* b);
124d9306527SDavid du Colombier static Elist*	mkel(Elem e, Elist* tail);
12580ee5cbfSDavid du Colombier static void	freeelist(Elist* el);
12680ee5cbfSDavid du Colombier static int	elistlen(Elist* el);
12780ee5cbfSDavid du Colombier static int	is_seq(Elem* pe, Elist** pseq);
12880ee5cbfSDavid du Colombier static int	is_set(Elem* pe, Elist** pset);
12980ee5cbfSDavid du Colombier static int	is_int(Elem* pe, int* pint);
13080ee5cbfSDavid du Colombier static int	is_bigint(Elem* pe, Bytes** pbigint);
13180ee5cbfSDavid du Colombier static int	is_bitstring(Elem* pe, Bits** pbits);
13280ee5cbfSDavid du Colombier static int	is_octetstring(Elem* pe, Bytes** poctets);
13380ee5cbfSDavid du Colombier static int	is_oid(Elem* pe, Ints** poid);
13480ee5cbfSDavid du Colombier static int	is_string(Elem* pe, char** pstring);
13580ee5cbfSDavid du Colombier static int	is_time(Elem* pe, char** ptime);
13680ee5cbfSDavid du Colombier static int	decode(uchar* a, int alen, Elem* pelem);
13780ee5cbfSDavid du Colombier static int	decode_seq(uchar* a, int alen, Elist** pelist);
13880ee5cbfSDavid du Colombier static int	decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval);
13980ee5cbfSDavid du Colombier static int	encode(Elem e, Bytes** pbytes);
14080ee5cbfSDavid du Colombier static int	oid_lookup(Ints* o, Ints** tab);
14180ee5cbfSDavid du Colombier static void	freevalfields(Value* v);
1429a747e4fSDavid du Colombier static mpint	*asn1mpint(Elem *e);
14380ee5cbfSDavid du Colombier 
14480ee5cbfSDavid du Colombier 
14580ee5cbfSDavid du Colombier 
14680ee5cbfSDavid du Colombier #define TAG_MASK 0x1F
14780ee5cbfSDavid du Colombier #define CONSTR_MASK 0x20
14880ee5cbfSDavid du Colombier #define CLASS_MASK 0xC0
14980ee5cbfSDavid du Colombier #define MAXOBJIDLEN 20
15080ee5cbfSDavid du Colombier 
15180ee5cbfSDavid du Colombier static int ber_decode(uchar** pp, uchar* pend, Elem* pelem);
15280ee5cbfSDavid du Colombier static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr);
15380ee5cbfSDavid du Colombier static int length_decode(uchar** pp, uchar* pend, int* plength);
15480ee5cbfSDavid du Colombier static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval);
15580ee5cbfSDavid du Colombier static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint);
15680ee5cbfSDavid du Colombier static int uint7_decode(uchar** pp, uchar* pend, int* pint);
15780ee5cbfSDavid du Colombier static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes);
15880ee5cbfSDavid du Colombier static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist);
15980ee5cbfSDavid du Colombier static int enc(uchar** pp, Elem e, int lenonly);
16080ee5cbfSDavid du Colombier static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly);
16180ee5cbfSDavid du Colombier static void uint7_enc(uchar** pp, int num, int lenonly);
16280ee5cbfSDavid du Colombier static void int_enc(uchar** pp, int num, int unsgned, int lenonly);
16380ee5cbfSDavid du Colombier 
164d9306527SDavid du Colombier static void *
165d9306527SDavid du Colombier emalloc(int n)
166d9306527SDavid du Colombier {
167d9306527SDavid du Colombier 	void *p;
168d9306527SDavid du Colombier 	if(n==0)
169d9306527SDavid du Colombier 		n=1;
170d9306527SDavid du Colombier 	p = malloc(n);
171d9306527SDavid du Colombier 	if(p == nil){
172d9306527SDavid du Colombier 		exits("out of memory");
173d9306527SDavid du Colombier 	}
174d9306527SDavid du Colombier 	memset(p, 0, n);
175d9306527SDavid du Colombier 	return p;
176d9306527SDavid du Colombier }
177d9306527SDavid du Colombier 
178d9306527SDavid du Colombier static char*
179d9306527SDavid du Colombier estrdup(char *s)
180d9306527SDavid du Colombier {
181d9306527SDavid du Colombier 	char *d, *d0;
182d9306527SDavid du Colombier 
183d9306527SDavid du Colombier 	if(!s)
184d9306527SDavid du Colombier 		return 0;
185d9306527SDavid du Colombier 	d = d0 = emalloc(strlen(s)+1);
186d9306527SDavid du Colombier 	while(*d++ = *s++)
187d9306527SDavid du Colombier 		;
188d9306527SDavid du Colombier 	return d0;
189d9306527SDavid du Colombier }
190d9306527SDavid du Colombier 
19180ee5cbfSDavid du Colombier 
19280ee5cbfSDavid du Colombier /*
19380ee5cbfSDavid du Colombier  * Decode a[0..len] as a BER encoding of an ASN1 type.
19480ee5cbfSDavid du Colombier  * The return value is one of ASN_OK, etc.
19580ee5cbfSDavid du Colombier  * Depending on the error, the returned elem may or may not
19680ee5cbfSDavid du Colombier  * be nil.
19780ee5cbfSDavid du Colombier  */
19880ee5cbfSDavid du Colombier static int
19980ee5cbfSDavid du Colombier decode(uchar* a, int alen, Elem* pelem)
20080ee5cbfSDavid du Colombier {
20180ee5cbfSDavid du Colombier 	uchar* p = a;
20280ee5cbfSDavid du Colombier 
20380ee5cbfSDavid du Colombier 	return  ber_decode(&p, &a[alen], pelem);
20480ee5cbfSDavid du Colombier }
20580ee5cbfSDavid du Colombier 
20680ee5cbfSDavid du Colombier /*
20780ee5cbfSDavid du Colombier  * Like decode, but continue decoding after first element
20880ee5cbfSDavid du Colombier  * of array ends.
20980ee5cbfSDavid du Colombier  */
21080ee5cbfSDavid du Colombier static int
21180ee5cbfSDavid du Colombier decode_seq(uchar* a, int alen, Elist** pelist)
21280ee5cbfSDavid du Colombier {
21380ee5cbfSDavid du Colombier 	uchar* p = a;
21480ee5cbfSDavid du Colombier 
21580ee5cbfSDavid du Colombier 	return seq_decode(&p, &a[alen], -1, 1, pelist);
21680ee5cbfSDavid du Colombier }
21780ee5cbfSDavid du Colombier 
21880ee5cbfSDavid du Colombier /*
21980ee5cbfSDavid du Colombier  * Decode the whole array as a BER encoding of an ASN1 value,
22080ee5cbfSDavid du Colombier  * (i.e., the part after the tag and length).
22180ee5cbfSDavid du Colombier  * Assume the value is encoded as universal tag "kind".
22280ee5cbfSDavid du Colombier  * The constr arg is 1 if the value is constructed, 0 if primitive.
22380ee5cbfSDavid du Colombier  * If there's an error, the return string will contain the error.
22480ee5cbfSDavid du Colombier  * Depending on the error, the returned value may or may not
22580ee5cbfSDavid du Colombier  * be nil.
22680ee5cbfSDavid du Colombier  */
22780ee5cbfSDavid du Colombier static int
22880ee5cbfSDavid du Colombier decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval)
22980ee5cbfSDavid du Colombier {
23080ee5cbfSDavid du Colombier 	uchar* p = a;
23180ee5cbfSDavid du Colombier 
23280ee5cbfSDavid du Colombier 	return value_decode(&p, &a[alen], alen, kind, isconstr, pval);
23380ee5cbfSDavid du Colombier }
23480ee5cbfSDavid du Colombier 
23580ee5cbfSDavid du Colombier /*
23680ee5cbfSDavid du Colombier  * All of the following decoding routines take arguments:
23780ee5cbfSDavid du Colombier  *	uchar **pp;
23880ee5cbfSDavid du Colombier  *	uchar *pend;
23980ee5cbfSDavid du Colombier  * Where parsing is supposed to start at **pp, and when parsing
24080ee5cbfSDavid du Colombier  * is done, *pp is updated to point at next char to be parsed.
24180ee5cbfSDavid du Colombier  * The pend pointer is just past end of string; an error should
24280ee5cbfSDavid du Colombier  * be returned parsing hasn't finished by then.
24380ee5cbfSDavid du Colombier  *
24480ee5cbfSDavid du Colombier  * The returned int is ASN_OK if all went fine, else ASN_ESHORT, etc.
24580ee5cbfSDavid du Colombier  * The remaining argument(s) are pointers to where parsed entity goes.
24680ee5cbfSDavid du Colombier  */
24780ee5cbfSDavid du Colombier 
24880ee5cbfSDavid du Colombier /* Decode an ASN1 'Elem' (tag, length, value) */
24980ee5cbfSDavid du Colombier static int
25080ee5cbfSDavid du Colombier ber_decode(uchar** pp, uchar* pend, Elem* pelem)
25180ee5cbfSDavid du Colombier {
25280ee5cbfSDavid du Colombier 	int err;
25380ee5cbfSDavid du Colombier 	int isconstr;
25480ee5cbfSDavid du Colombier 	int length;
25580ee5cbfSDavid du Colombier 	Tag tag;
25680ee5cbfSDavid du Colombier 	Value val;
25780ee5cbfSDavid du Colombier 
25880ee5cbfSDavid du Colombier 	err = tag_decode(pp, pend, &tag, &isconstr);
25980ee5cbfSDavid du Colombier 	if(err == ASN_OK) {
26080ee5cbfSDavid du Colombier 		err = length_decode(pp, pend, &length);
26180ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
26280ee5cbfSDavid du Colombier 			if(tag.class == Universal)
26380ee5cbfSDavid du Colombier 				err = value_decode(pp, pend, length, tag.num, isconstr, &val);
26480ee5cbfSDavid du Colombier 			else
26580ee5cbfSDavid du Colombier 				err = value_decode(pp, pend, length, OCTET_STRING, 0, &val);
26680ee5cbfSDavid du Colombier 			if(err == ASN_OK) {
26780ee5cbfSDavid du Colombier 				pelem->tag = tag;
26880ee5cbfSDavid du Colombier 				pelem->val = val;
26980ee5cbfSDavid du Colombier 			}
27080ee5cbfSDavid du Colombier 		}
27180ee5cbfSDavid du Colombier 	}
27280ee5cbfSDavid du Colombier 	return err;
27380ee5cbfSDavid du Colombier }
27480ee5cbfSDavid du Colombier 
27580ee5cbfSDavid du Colombier /* Decode a tag field */
27680ee5cbfSDavid du Colombier static int
27780ee5cbfSDavid du Colombier tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr)
27880ee5cbfSDavid du Colombier {
27980ee5cbfSDavid du Colombier 	int err;
28080ee5cbfSDavid du Colombier 	int v;
28180ee5cbfSDavid du Colombier 	uchar* p;
28280ee5cbfSDavid du Colombier 
28380ee5cbfSDavid du Colombier 	err = ASN_OK;
28480ee5cbfSDavid du Colombier 	p = *pp;
28580ee5cbfSDavid du Colombier 	if(pend-p >= 2) {
28680ee5cbfSDavid du Colombier 		v = *p++;
28780ee5cbfSDavid du Colombier 		ptag->class = v&CLASS_MASK;
28880ee5cbfSDavid du Colombier 		if(v&CONSTR_MASK)
28980ee5cbfSDavid du Colombier 			*pisconstr = 1;
29080ee5cbfSDavid du Colombier 		else
29180ee5cbfSDavid du Colombier 			*pisconstr = 0;
29280ee5cbfSDavid du Colombier 		v &= TAG_MASK;
29380ee5cbfSDavid du Colombier 		if(v == TAG_MASK)
29480ee5cbfSDavid du Colombier 			err = uint7_decode(&p, pend, &v);
29580ee5cbfSDavid du Colombier 		ptag->num = v;
29680ee5cbfSDavid du Colombier 	}
29780ee5cbfSDavid du Colombier 	else
29880ee5cbfSDavid du Colombier 		err = ASN_ESHORT;
29980ee5cbfSDavid du Colombier 	*pp = p;
30080ee5cbfSDavid du Colombier 	return err;
30180ee5cbfSDavid du Colombier }
30280ee5cbfSDavid du Colombier 
30380ee5cbfSDavid du Colombier /* Decode a length field */
30480ee5cbfSDavid du Colombier static int
30580ee5cbfSDavid du Colombier length_decode(uchar** pp, uchar* pend, int* plength)
30680ee5cbfSDavid du Colombier {
30780ee5cbfSDavid du Colombier 	int err;
30880ee5cbfSDavid du Colombier 	int num;
30980ee5cbfSDavid du Colombier 	int v;
31080ee5cbfSDavid du Colombier 	uchar* p;
31180ee5cbfSDavid du Colombier 
31280ee5cbfSDavid du Colombier 	err = ASN_OK;
31380ee5cbfSDavid du Colombier 	num = 0;
31480ee5cbfSDavid du Colombier 	p = *pp;
31580ee5cbfSDavid du Colombier 	if(p < pend) {
31680ee5cbfSDavid du Colombier 		v = *p++;
31780ee5cbfSDavid du Colombier 		if(v&0x80)
31880ee5cbfSDavid du Colombier 			err = int_decode(&p, pend, v&0x7F, 1, &num);
31980ee5cbfSDavid du Colombier 		else
32080ee5cbfSDavid du Colombier 			num = v;
32180ee5cbfSDavid du Colombier 	}
32280ee5cbfSDavid du Colombier 	else
32380ee5cbfSDavid du Colombier 		err = ASN_ESHORT;
32480ee5cbfSDavid du Colombier 	*pp = p;
32580ee5cbfSDavid du Colombier 	*plength = num;
32680ee5cbfSDavid du Colombier 	return err;
32780ee5cbfSDavid du Colombier }
32880ee5cbfSDavid du Colombier 
32980ee5cbfSDavid du Colombier /* Decode a value field  */
33080ee5cbfSDavid du Colombier static int
33180ee5cbfSDavid du Colombier value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval)
33280ee5cbfSDavid du Colombier {
33380ee5cbfSDavid du Colombier 	int err;
33480ee5cbfSDavid du Colombier 	Bytes* va;
33580ee5cbfSDavid du Colombier 	int num;
33680ee5cbfSDavid du Colombier 	int bitsunused;
33780ee5cbfSDavid du Colombier 	int subids[MAXOBJIDLEN];
33880ee5cbfSDavid du Colombier 	int isubid;
33980ee5cbfSDavid du Colombier 	Elist*	vl;
34080ee5cbfSDavid du Colombier 	uchar* p;
34180ee5cbfSDavid du Colombier 	uchar* pe;
34280ee5cbfSDavid du Colombier 
34380ee5cbfSDavid du Colombier 	err = ASN_OK;
34480ee5cbfSDavid du Colombier 	p = *pp;
34580ee5cbfSDavid du Colombier 	if(length == -1) {	/* "indefinite" length spec */
34680ee5cbfSDavid du Colombier 		if(!isconstr)
34780ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
34880ee5cbfSDavid du Colombier 	}
34980ee5cbfSDavid du Colombier 	else if(p + length > pend)
35080ee5cbfSDavid du Colombier 		err = ASN_EVALLEN;
35180ee5cbfSDavid du Colombier 	if(err != ASN_OK)
35280ee5cbfSDavid du Colombier 		return err;
35380ee5cbfSDavid du Colombier 
35480ee5cbfSDavid du Colombier 	switch(kind) {
35580ee5cbfSDavid du Colombier 	case 0:
35680ee5cbfSDavid du Colombier 		/* marker for end of indefinite constructions */
35780ee5cbfSDavid du Colombier 		if(length == 0)
35880ee5cbfSDavid du Colombier 			pval->tag = VNull;
35980ee5cbfSDavid du Colombier 		else
36080ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
36180ee5cbfSDavid du Colombier 		break;
36280ee5cbfSDavid du Colombier 
36380ee5cbfSDavid du Colombier 	case BOOLEAN:
36480ee5cbfSDavid du Colombier 		if(isconstr)
36580ee5cbfSDavid du Colombier 			err = ASN_ECONSTR;
36680ee5cbfSDavid du Colombier 		else if(length != 1)
36780ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
36880ee5cbfSDavid du Colombier 		else {
36980ee5cbfSDavid du Colombier 			pval->tag = VBool;
37080ee5cbfSDavid du Colombier 			pval->u.boolval = (*p++ != 0);
37180ee5cbfSDavid du Colombier 		}
37280ee5cbfSDavid du Colombier 		break;
37380ee5cbfSDavid du Colombier 
37480ee5cbfSDavid du Colombier 	case INTEGER:
37580ee5cbfSDavid du Colombier 	case ENUMERATED:
37680ee5cbfSDavid du Colombier 		if(isconstr)
37780ee5cbfSDavid du Colombier 			err = ASN_ECONSTR;
37880ee5cbfSDavid du Colombier 		else if(length <= 4) {
37980ee5cbfSDavid du Colombier 			err = int_decode(&p, pend, length, 0, &num);
38080ee5cbfSDavid du Colombier 			if(err == ASN_OK) {
38180ee5cbfSDavid du Colombier 				pval->tag = VInt;
38280ee5cbfSDavid du Colombier 				pval->u.intval = num;
38380ee5cbfSDavid du Colombier 			}
38480ee5cbfSDavid du Colombier 		}
38580ee5cbfSDavid du Colombier 		else {
38680ee5cbfSDavid du Colombier 			pval->tag = VBigInt;
38780ee5cbfSDavid du Colombier 			pval->u.bigintval = makebytes(p, length);
38880ee5cbfSDavid du Colombier 			p += length;
38980ee5cbfSDavid du Colombier 		}
39080ee5cbfSDavid du Colombier 		break;
39180ee5cbfSDavid du Colombier 
39280ee5cbfSDavid du Colombier 	case BIT_STRING:
39380ee5cbfSDavid du Colombier 		pval->tag = VBitString;
39480ee5cbfSDavid du Colombier 		if(isconstr) {
39580ee5cbfSDavid du Colombier 			if(length == -1 && p + 2 <= pend && *p == 0 && *(p+1) ==0) {
39680ee5cbfSDavid du Colombier 				pval->u.bitstringval = makebits(0, 0, 0);
39780ee5cbfSDavid du Colombier 				p += 2;
39880ee5cbfSDavid du Colombier 			}
39980ee5cbfSDavid du Colombier 			else
40080ee5cbfSDavid du Colombier 				/* TODO: recurse and concat results */
40180ee5cbfSDavid du Colombier 				err = ASN_EUNIMPL;
40280ee5cbfSDavid du Colombier 		}
40380ee5cbfSDavid du Colombier 		else {
40480ee5cbfSDavid du Colombier 			if(length < 2) {
40580ee5cbfSDavid du Colombier 				if(length == 1 && *p == 0) {
40680ee5cbfSDavid du Colombier 					pval->u.bitstringval = makebits(0, 0, 0);
40780ee5cbfSDavid du Colombier 					p++;
40880ee5cbfSDavid du Colombier 				}
40980ee5cbfSDavid du Colombier 				else
41080ee5cbfSDavid du Colombier 					err = ASN_EINVAL;
41180ee5cbfSDavid du Colombier 			}
41280ee5cbfSDavid du Colombier 			else {
41380ee5cbfSDavid du Colombier 				bitsunused = *p;
41480ee5cbfSDavid du Colombier 				if(bitsunused > 7)
41580ee5cbfSDavid du Colombier 					err = ASN_EINVAL;
41680ee5cbfSDavid du Colombier 				else if(length > 0x0FFFFFFF)
41780ee5cbfSDavid du Colombier 					err = ASN_ETOOBIG;
41880ee5cbfSDavid du Colombier 				else {
41980ee5cbfSDavid du Colombier 					pval->u.bitstringval = makebits(p+1, length-1, bitsunused);
42080ee5cbfSDavid du Colombier 					p += length;
42180ee5cbfSDavid du Colombier 				}
42280ee5cbfSDavid du Colombier 			}
42380ee5cbfSDavid du Colombier 		}
42480ee5cbfSDavid du Colombier 		break;
42580ee5cbfSDavid du Colombier 
42680ee5cbfSDavid du Colombier 	case OCTET_STRING:
42780ee5cbfSDavid du Colombier 	case ObjectDescriptor:
42880ee5cbfSDavid du Colombier 		err = octet_decode(&p, pend, length, isconstr, &va);
42980ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
43080ee5cbfSDavid du Colombier 			pval->tag = VOctets;
43180ee5cbfSDavid du Colombier 			pval->u.octetsval = va;
43280ee5cbfSDavid du Colombier 		}
43380ee5cbfSDavid du Colombier 		break;
43480ee5cbfSDavid du Colombier 
43580ee5cbfSDavid du Colombier 	case NULLTAG:
43680ee5cbfSDavid du Colombier 		if(isconstr)
43780ee5cbfSDavid du Colombier 			err = ASN_ECONSTR;
43880ee5cbfSDavid du Colombier 		else if(length != 0)
43980ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
44080ee5cbfSDavid du Colombier 		else
44180ee5cbfSDavid du Colombier 			pval->tag = VNull;
44280ee5cbfSDavid du Colombier 		break;
44380ee5cbfSDavid du Colombier 
44480ee5cbfSDavid du Colombier 	case OBJECT_ID:
44580ee5cbfSDavid du Colombier 		if(isconstr)
44680ee5cbfSDavid du Colombier 			err = ASN_ECONSTR;
44780ee5cbfSDavid du Colombier 		else if(length == 0)
44880ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
44980ee5cbfSDavid du Colombier 		else {
45080ee5cbfSDavid du Colombier 			isubid = 0;
45180ee5cbfSDavid du Colombier 			pe = p+length;
45280ee5cbfSDavid du Colombier 			while(p < pe && isubid < MAXOBJIDLEN) {
45380ee5cbfSDavid du Colombier 				err = uint7_decode(&p, pend, &num);
45480ee5cbfSDavid du Colombier 				if(err != ASN_OK)
45580ee5cbfSDavid du Colombier 					break;
45680ee5cbfSDavid du Colombier 				if(isubid == 0) {
45780ee5cbfSDavid du Colombier 					subids[isubid++] = num / 40;
45880ee5cbfSDavid du Colombier 					subids[isubid++] = num % 40;
45980ee5cbfSDavid du Colombier 				}
46080ee5cbfSDavid du Colombier 				else
46180ee5cbfSDavid du Colombier 					subids[isubid++] = num;
46280ee5cbfSDavid du Colombier 			}
46380ee5cbfSDavid du Colombier 			if(err == ASN_OK) {
46480ee5cbfSDavid du Colombier 				if(p != pe)
46580ee5cbfSDavid du Colombier 					err = ASN_EVALLEN;
46680ee5cbfSDavid du Colombier 				else {
46780ee5cbfSDavid du Colombier 					pval->tag = VObjId;
46880ee5cbfSDavid du Colombier 					pval->u.objidval = makeints(subids, isubid);
46980ee5cbfSDavid du Colombier 				}
47080ee5cbfSDavid du Colombier 			}
47180ee5cbfSDavid du Colombier 		}
47280ee5cbfSDavid du Colombier 		break;
47380ee5cbfSDavid du Colombier 
47480ee5cbfSDavid du Colombier 	case EXTERNAL:
47580ee5cbfSDavid du Colombier 	case EMBEDDED_PDV:
47680ee5cbfSDavid du Colombier 		/* TODO: parse this internally */
47780ee5cbfSDavid du Colombier 		if(p+length > pend)
47880ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
47980ee5cbfSDavid du Colombier 		else {
48080ee5cbfSDavid du Colombier 			pval->tag = VOther;
48180ee5cbfSDavid du Colombier 			pval->u.otherval = makebytes(p, length);
48280ee5cbfSDavid du Colombier 			p += length;
48380ee5cbfSDavid du Colombier 		}
48480ee5cbfSDavid du Colombier 		break;
48580ee5cbfSDavid du Colombier 
48680ee5cbfSDavid du Colombier 	case REAL:
48780ee5cbfSDavid du Colombier 		/* Let the application decode */
48880ee5cbfSDavid du Colombier 		if(isconstr)
48980ee5cbfSDavid du Colombier 			err = ASN_ECONSTR;
49080ee5cbfSDavid du Colombier 		else if(p+length > pend)
49180ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
49280ee5cbfSDavid du Colombier 		else {
49380ee5cbfSDavid du Colombier 			pval->tag = VReal;
49480ee5cbfSDavid du Colombier 			pval->u.realval = makebytes(p, length);
49580ee5cbfSDavid du Colombier 			p += length;
49680ee5cbfSDavid du Colombier 		}
49780ee5cbfSDavid du Colombier 		break;
49880ee5cbfSDavid du Colombier 
49980ee5cbfSDavid du Colombier 	case SEQUENCE:
50080ee5cbfSDavid du Colombier 		err = seq_decode(&p, pend, length, isconstr, &vl);
50180ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
50280ee5cbfSDavid du Colombier 			pval->tag = VSeq ;
50380ee5cbfSDavid du Colombier 			pval->u.seqval = vl;
50480ee5cbfSDavid du Colombier 		}
50580ee5cbfSDavid du Colombier 		break;
50680ee5cbfSDavid du Colombier 
5079a747e4fSDavid du Colombier 	case SETOF:
50880ee5cbfSDavid du Colombier 		err = seq_decode(&p, pend, length, isconstr, &vl);
50980ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
51080ee5cbfSDavid du Colombier 			pval->tag = VSet;
51180ee5cbfSDavid du Colombier 			pval->u.setval = vl;
51280ee5cbfSDavid du Colombier 		}
51380ee5cbfSDavid du Colombier 		break;
51480ee5cbfSDavid du Colombier 
51580ee5cbfSDavid du Colombier 	case NumericString:
51680ee5cbfSDavid du Colombier 	case PrintableString:
51780ee5cbfSDavid du Colombier 	case TeletexString:
51880ee5cbfSDavid du Colombier 	case VideotexString:
51980ee5cbfSDavid du Colombier 	case IA5String:
52080ee5cbfSDavid du Colombier 	case UTCTime:
52180ee5cbfSDavid du Colombier 	case GeneralizedTime:
52280ee5cbfSDavid du Colombier 	case GraphicString:
52380ee5cbfSDavid du Colombier 	case VisibleString:
52480ee5cbfSDavid du Colombier 	case GeneralString:
52580ee5cbfSDavid du Colombier 	case UniversalString:
52680ee5cbfSDavid du Colombier 	case BMPString:
52780ee5cbfSDavid du Colombier 		/* TODO: figure out when character set conversion is necessary */
52880ee5cbfSDavid du Colombier 		err = octet_decode(&p, pend, length, isconstr, &va);
52980ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
53080ee5cbfSDavid du Colombier 			pval->tag = VString;
531d9306527SDavid du Colombier 			pval->u.stringval = (char*)emalloc(va->len+1);
53280ee5cbfSDavid du Colombier 			memmove(pval->u.stringval, va->data, va->len);
53380ee5cbfSDavid du Colombier 			pval->u.stringval[va->len] = 0;
53480ee5cbfSDavid du Colombier 			free(va);
53580ee5cbfSDavid du Colombier 		}
53680ee5cbfSDavid du Colombier 		break;
53780ee5cbfSDavid du Colombier 
53880ee5cbfSDavid du Colombier 	default:
53980ee5cbfSDavid du Colombier 		if(p+length > pend)
54080ee5cbfSDavid du Colombier 			err = ASN_EVALLEN;
54180ee5cbfSDavid du Colombier 		else {
54280ee5cbfSDavid du Colombier 			pval->tag = VOther;
54380ee5cbfSDavid du Colombier 			pval->u.otherval = makebytes(p, length);
54480ee5cbfSDavid du Colombier 			p += length;
54580ee5cbfSDavid du Colombier 		}
54680ee5cbfSDavid du Colombier 		break;
54780ee5cbfSDavid du Colombier 	}
54880ee5cbfSDavid du Colombier 	*pp = p;
54980ee5cbfSDavid du Colombier 	return err;
55080ee5cbfSDavid du Colombier }
55180ee5cbfSDavid du Colombier 
55280ee5cbfSDavid du Colombier /*
55380ee5cbfSDavid du Colombier  * Decode an int in format where count bytes are
55480ee5cbfSDavid du Colombier  * concatenated to form value.
55580ee5cbfSDavid du Colombier  * Although ASN1 allows any size integer, we return
55680ee5cbfSDavid du Colombier  * an error if the result doesn't fit in a 32-bit int.
55780ee5cbfSDavid du Colombier  * If unsgned is not set, make sure to propagate sign bit.
55880ee5cbfSDavid du Colombier  */
55980ee5cbfSDavid du Colombier static int
56080ee5cbfSDavid du Colombier int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint)
56180ee5cbfSDavid du Colombier {
56280ee5cbfSDavid du Colombier 	int err;
56380ee5cbfSDavid du Colombier 	int num;
56480ee5cbfSDavid du Colombier 	uchar* p;
56580ee5cbfSDavid du Colombier 
56680ee5cbfSDavid du Colombier 	p = *pp;
56780ee5cbfSDavid du Colombier 	err = ASN_OK;
56880ee5cbfSDavid du Colombier 	num = 0;
56980ee5cbfSDavid du Colombier 	if(p+count <= pend) {
57080ee5cbfSDavid du Colombier 		if((count > 4) || (unsgned && count == 4 && (*p&0x80)))
57180ee5cbfSDavid du Colombier 			err = ASN_ETOOBIG;
57280ee5cbfSDavid du Colombier 		else {
57380ee5cbfSDavid du Colombier 			if(!unsgned && count > 0 && count < 4 && (*p&0x80))
57480ee5cbfSDavid du Colombier 				num = -1;		// set all bits, initially
57580ee5cbfSDavid du Colombier 			while(count--)
57680ee5cbfSDavid du Colombier 				num = (num << 8)|(*p++);
57780ee5cbfSDavid du Colombier 		}
57880ee5cbfSDavid du Colombier 	}
57980ee5cbfSDavid du Colombier 	else
58080ee5cbfSDavid du Colombier 		err = ASN_ESHORT;
58180ee5cbfSDavid du Colombier 	*pint = num;
58280ee5cbfSDavid du Colombier 	*pp = p;
58380ee5cbfSDavid du Colombier 	return err;
58480ee5cbfSDavid du Colombier }
58580ee5cbfSDavid du Colombier 
58680ee5cbfSDavid du Colombier /*
58780ee5cbfSDavid du Colombier  * Decode an unsigned int in format where each
58880ee5cbfSDavid du Colombier  * byte except last has high bit set, and remaining
58980ee5cbfSDavid du Colombier  * seven bits of each byte are concatenated to form value.
59080ee5cbfSDavid du Colombier  * Although ASN1 allows any size integer, we return
59180ee5cbfSDavid du Colombier  * an error if the result doesn't fit in a 32 bit int.
59280ee5cbfSDavid du Colombier  */
59380ee5cbfSDavid du Colombier static int
59480ee5cbfSDavid du Colombier uint7_decode(uchar** pp, uchar* pend, int* pint)
59580ee5cbfSDavid du Colombier {
59680ee5cbfSDavid du Colombier 	int err;
59780ee5cbfSDavid du Colombier 	int num;
59880ee5cbfSDavid du Colombier 	int more;
59980ee5cbfSDavid du Colombier 	int v;
60080ee5cbfSDavid du Colombier 	uchar* p;
60180ee5cbfSDavid du Colombier 
60280ee5cbfSDavid du Colombier 	p = *pp;
60380ee5cbfSDavid du Colombier 	err = ASN_OK;
60480ee5cbfSDavid du Colombier 	num = 0;
60580ee5cbfSDavid du Colombier 	more = 1;
60680ee5cbfSDavid du Colombier 	while(more && p < pend) {
60780ee5cbfSDavid du Colombier 		v = *p++;
60880ee5cbfSDavid du Colombier 		if(num&0x7F000000) {
60980ee5cbfSDavid du Colombier 			err = ASN_ETOOBIG;
61080ee5cbfSDavid du Colombier 			break;
61180ee5cbfSDavid du Colombier 		}
61280ee5cbfSDavid du Colombier 		num <<= 7;
61380ee5cbfSDavid du Colombier 		more = v&0x80;
61480ee5cbfSDavid du Colombier 		num |= (v&0x7F);
61580ee5cbfSDavid du Colombier 	}
61680ee5cbfSDavid du Colombier 	if(p == pend)
61780ee5cbfSDavid du Colombier 		err = ASN_ESHORT;
61880ee5cbfSDavid du Colombier 	*pint = num;
61980ee5cbfSDavid du Colombier 	*pp = p;
62080ee5cbfSDavid du Colombier 	return err;
62180ee5cbfSDavid du Colombier }
62280ee5cbfSDavid du Colombier 
62380ee5cbfSDavid du Colombier /*
62480ee5cbfSDavid du Colombier  * Decode an octet string, recursively if isconstr.
62580ee5cbfSDavid du Colombier  * We've already checked that length==-1 implies isconstr==1,
62680ee5cbfSDavid du Colombier  * and otherwise that specified length fits within (*pp..pend)
62780ee5cbfSDavid du Colombier  */
62880ee5cbfSDavid du Colombier static int
62980ee5cbfSDavid du Colombier octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes)
63080ee5cbfSDavid du Colombier {
63180ee5cbfSDavid du Colombier 	int err;
63280ee5cbfSDavid du Colombier 	uchar* p;
63380ee5cbfSDavid du Colombier 	Bytes* ans;
63480ee5cbfSDavid du Colombier 	Bytes* newans;
63580ee5cbfSDavid du Colombier 	uchar* pstart;
63680ee5cbfSDavid du Colombier 	uchar* pold;
63780ee5cbfSDavid du Colombier 	Elem	elem;
63880ee5cbfSDavid du Colombier 
63980ee5cbfSDavid du Colombier 	err = ASN_OK;
64080ee5cbfSDavid du Colombier 	p = *pp;
64180ee5cbfSDavid du Colombier 	ans = nil;
64280ee5cbfSDavid du Colombier 	if(length >= 0 && !isconstr) {
64380ee5cbfSDavid du Colombier 		ans = makebytes(p, length);
64480ee5cbfSDavid du Colombier 		p += length;
64580ee5cbfSDavid du Colombier 	}
64680ee5cbfSDavid du Colombier 	else {
64780ee5cbfSDavid du Colombier 		/* constructed, either definite or indefinite length */
64880ee5cbfSDavid du Colombier 		pstart = p;
64980ee5cbfSDavid du Colombier 		for(;;) {
65080ee5cbfSDavid du Colombier 			if(length >= 0 && p >= pstart + length) {
65180ee5cbfSDavid du Colombier 				if(p != pstart + length)
65280ee5cbfSDavid du Colombier 					err = ASN_EVALLEN;
65380ee5cbfSDavid du Colombier 				break;
65480ee5cbfSDavid du Colombier 			}
65580ee5cbfSDavid du Colombier 			pold = p;
65680ee5cbfSDavid du Colombier 			err = ber_decode(&p, pend, &elem);
65780ee5cbfSDavid du Colombier 			if(err != ASN_OK)
65880ee5cbfSDavid du Colombier 				break;
65980ee5cbfSDavid du Colombier 			switch(elem.val.tag) {
66080ee5cbfSDavid du Colombier 			case VOctets:
66180ee5cbfSDavid du Colombier 				newans = catbytes(ans, elem.val.u.octetsval);
66280ee5cbfSDavid du Colombier 				freebytes(ans);
66380ee5cbfSDavid du Colombier 				ans = newans;
66480ee5cbfSDavid du Colombier 				break;
66580ee5cbfSDavid du Colombier 
66680ee5cbfSDavid du Colombier 			case VEOC:
66780ee5cbfSDavid du Colombier 				if(length != -1) {
66880ee5cbfSDavid du Colombier 					p = pold;
66980ee5cbfSDavid du Colombier 					err = ASN_EINVAL;
67080ee5cbfSDavid du Colombier 				}
67180ee5cbfSDavid du Colombier 				goto cloop_done;
67280ee5cbfSDavid du Colombier 
67380ee5cbfSDavid du Colombier 			default:
67480ee5cbfSDavid du Colombier 				p = pold;
67580ee5cbfSDavid du Colombier 				err = ASN_EINVAL;
67680ee5cbfSDavid du Colombier 				goto cloop_done;
67780ee5cbfSDavid du Colombier 			}
67880ee5cbfSDavid du Colombier 		}
67980ee5cbfSDavid du Colombier cloop_done:
68080ee5cbfSDavid du Colombier 		;
68180ee5cbfSDavid du Colombier 	}
68280ee5cbfSDavid du Colombier 	*pp = p;
68380ee5cbfSDavid du Colombier 	*pbytes = ans;
68480ee5cbfSDavid du Colombier 	return err;
68580ee5cbfSDavid du Colombier }
68680ee5cbfSDavid du Colombier 
68780ee5cbfSDavid du Colombier /*
68880ee5cbfSDavid du Colombier  * Decode a sequence or set.
68980ee5cbfSDavid du Colombier  * We've already checked that length==-1 implies isconstr==1,
69080ee5cbfSDavid du Colombier  * and otherwise that specified length fits within (*p..pend)
69180ee5cbfSDavid du Colombier  */
69280ee5cbfSDavid du Colombier static int
69380ee5cbfSDavid du Colombier seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist)
69480ee5cbfSDavid du Colombier {
69580ee5cbfSDavid du Colombier 	int err;
69680ee5cbfSDavid du Colombier 	uchar* p;
69780ee5cbfSDavid du Colombier 	uchar* pstart;
69880ee5cbfSDavid du Colombier 	uchar* pold;
69980ee5cbfSDavid du Colombier 	Elist* ans;
70080ee5cbfSDavid du Colombier 	Elem elem;
70180ee5cbfSDavid du Colombier 	Elist* lve;
70280ee5cbfSDavid du Colombier 	Elist* lveold;
70380ee5cbfSDavid du Colombier 
70480ee5cbfSDavid du Colombier 	err = ASN_OK;
70580ee5cbfSDavid du Colombier 	ans = nil;
70680ee5cbfSDavid du Colombier 	p = *pp;
70780ee5cbfSDavid du Colombier 	if(!isconstr)
70880ee5cbfSDavid du Colombier 		err = ASN_EPRIM;
70980ee5cbfSDavid du Colombier 	else {
71080ee5cbfSDavid du Colombier 		/* constructed, either definite or indefinite length */
71180ee5cbfSDavid du Colombier 		lve = nil;
71280ee5cbfSDavid du Colombier 		pstart = p;
71380ee5cbfSDavid du Colombier 		for(;;) {
71480ee5cbfSDavid du Colombier 			if(length >= 0 && p >= pstart + length) {
71580ee5cbfSDavid du Colombier 				if(p != pstart + length)
71680ee5cbfSDavid du Colombier 					err = ASN_EVALLEN;
71780ee5cbfSDavid du Colombier 				break;
71880ee5cbfSDavid du Colombier 			}
71980ee5cbfSDavid du Colombier 			pold = p;
72080ee5cbfSDavid du Colombier 			err = ber_decode(&p, pend, &elem);
72180ee5cbfSDavid du Colombier 			if(err != ASN_OK)
72280ee5cbfSDavid du Colombier 				break;
72380ee5cbfSDavid du Colombier 			if(elem.val.tag == VEOC) {
72480ee5cbfSDavid du Colombier 				if(length != -1) {
72580ee5cbfSDavid du Colombier 					p = pold;
72680ee5cbfSDavid du Colombier 					err = ASN_EINVAL;
72780ee5cbfSDavid du Colombier 				}
72880ee5cbfSDavid du Colombier 				break;
72980ee5cbfSDavid du Colombier 			}
73080ee5cbfSDavid du Colombier 			else
731d9306527SDavid du Colombier 				lve = mkel(elem, lve);
73280ee5cbfSDavid du Colombier 		}
73380ee5cbfSDavid du Colombier 		if(err == ASN_OK) {
73480ee5cbfSDavid du Colombier 			/* reverse back to original order */
73580ee5cbfSDavid du Colombier 			while(lve != nil) {
73680ee5cbfSDavid du Colombier 				lveold = lve;
73780ee5cbfSDavid du Colombier 				lve = lve->tl;
73880ee5cbfSDavid du Colombier 				lveold->tl = ans;
73980ee5cbfSDavid du Colombier 				ans = lveold;
74080ee5cbfSDavid du Colombier 			}
74180ee5cbfSDavid du Colombier 		}
74280ee5cbfSDavid du Colombier 	}
74380ee5cbfSDavid du Colombier 	*pp = p;
74480ee5cbfSDavid du Colombier 	*pelist = ans;
74580ee5cbfSDavid du Colombier 	return err;
74680ee5cbfSDavid du Colombier }
74780ee5cbfSDavid du Colombier 
74880ee5cbfSDavid du Colombier /*
74980ee5cbfSDavid du Colombier  * Encode e by BER rules, putting answer in *pbytes.
75080ee5cbfSDavid du Colombier  * This is done by first calling enc with lenonly==1
75180ee5cbfSDavid du Colombier  * to get the length of the needed buffer,
75280ee5cbfSDavid du Colombier  * then allocating the buffer and using enc again to fill it up.
75380ee5cbfSDavid du Colombier  */
75480ee5cbfSDavid du Colombier static int
75580ee5cbfSDavid du Colombier encode(Elem e, Bytes** pbytes)
75680ee5cbfSDavid du Colombier {
75780ee5cbfSDavid du Colombier 	uchar* p;
75880ee5cbfSDavid du Colombier 	Bytes* ans;
75980ee5cbfSDavid du Colombier 	int err;
76080ee5cbfSDavid du Colombier 	uchar uc;
76180ee5cbfSDavid du Colombier 
76280ee5cbfSDavid du Colombier 	p = &uc;
76380ee5cbfSDavid du Colombier 	err = enc(&p, e, 1);
76480ee5cbfSDavid du Colombier 	if(err == ASN_OK) {
76580ee5cbfSDavid du Colombier 		ans = newbytes(p-&uc);
76680ee5cbfSDavid du Colombier 		p = ans->data;
76780ee5cbfSDavid du Colombier 		err = enc(&p, e, 0);
76880ee5cbfSDavid du Colombier 		*pbytes = ans;
76980ee5cbfSDavid du Colombier 	}
77080ee5cbfSDavid du Colombier 	return err;
77180ee5cbfSDavid du Colombier }
77280ee5cbfSDavid du Colombier 
77380ee5cbfSDavid du Colombier /*
77480ee5cbfSDavid du Colombier  * The various enc functions take a pointer to a pointer
77580ee5cbfSDavid du Colombier  * into a buffer, and encode their entity starting there,
77680ee5cbfSDavid du Colombier  * updating the pointer afterwards.
77780ee5cbfSDavid du Colombier  * If lenonly is 1, only the pointer update is done,
77880ee5cbfSDavid du Colombier  * allowing enc to be called first to calculate the needed
77980ee5cbfSDavid du Colombier  * buffer length.
78080ee5cbfSDavid du Colombier  * If lenonly is 0, it is assumed that the answer will fit.
78180ee5cbfSDavid du Colombier  */
78280ee5cbfSDavid du Colombier 
78380ee5cbfSDavid du Colombier static int
78480ee5cbfSDavid du Colombier enc(uchar** pp, Elem e, int lenonly)
78580ee5cbfSDavid du Colombier {
78680ee5cbfSDavid du Colombier 	int err;
78780ee5cbfSDavid du Colombier 	int vlen;
78880ee5cbfSDavid du Colombier 	int constr;
78980ee5cbfSDavid du Colombier 	Tag tag;
79080ee5cbfSDavid du Colombier 	int v;
79180ee5cbfSDavid du Colombier 	int ilen;
79280ee5cbfSDavid du Colombier 	uchar* p;
79380ee5cbfSDavid du Colombier 	uchar* psave;
79480ee5cbfSDavid du Colombier 
79580ee5cbfSDavid du Colombier 	p = *pp;
79680ee5cbfSDavid du Colombier 	err = val_enc(&p, e, &constr, 1);
79780ee5cbfSDavid du Colombier 	if(err != ASN_OK)
79880ee5cbfSDavid du Colombier 		return err;
79980ee5cbfSDavid du Colombier 	vlen = p - *pp;
80080ee5cbfSDavid du Colombier 	p = *pp;
80180ee5cbfSDavid du Colombier 	tag = e.tag;
80280ee5cbfSDavid du Colombier 	v = tag.class|constr;
80380ee5cbfSDavid du Colombier 	if(tag.num < 31) {
80480ee5cbfSDavid du Colombier 		if(!lenonly)
80580ee5cbfSDavid du Colombier 			*p = (v|tag.num);
80680ee5cbfSDavid du Colombier 		p++;
80780ee5cbfSDavid du Colombier 	}
80880ee5cbfSDavid du Colombier 	else {
80980ee5cbfSDavid du Colombier 		if(!lenonly)
81080ee5cbfSDavid du Colombier 			*p = (v|31);
81180ee5cbfSDavid du Colombier 		p++;
81280ee5cbfSDavid du Colombier 		if(tag.num < 0)
81380ee5cbfSDavid du Colombier 			return ASN_EINVAL;
81480ee5cbfSDavid du Colombier 		uint7_enc(&p, tag.num, lenonly);
81580ee5cbfSDavid du Colombier 	}
81680ee5cbfSDavid du Colombier 	if(vlen < 0x80) {
81780ee5cbfSDavid du Colombier 		if(!lenonly)
81880ee5cbfSDavid du Colombier 			*p = vlen;
81980ee5cbfSDavid du Colombier 		p++;
82080ee5cbfSDavid du Colombier 	}
82180ee5cbfSDavid du Colombier 	else {
82280ee5cbfSDavid du Colombier 		psave = p;
82380ee5cbfSDavid du Colombier 		int_enc(&p, vlen, 1, 1);
82480ee5cbfSDavid du Colombier 		ilen = p-psave;
82580ee5cbfSDavid du Colombier 		p = psave;
82680ee5cbfSDavid du Colombier 		if(!lenonly) {
82780ee5cbfSDavid du Colombier 			*p++ = (0x80 | ilen);
82880ee5cbfSDavid du Colombier 			int_enc(&p, vlen, 1, 0);
82980ee5cbfSDavid du Colombier 		}
83080ee5cbfSDavid du Colombier 		else
83180ee5cbfSDavid du Colombier 			p += 1 + ilen;
83280ee5cbfSDavid du Colombier 	}
83380ee5cbfSDavid du Colombier 	if(!lenonly)
83480ee5cbfSDavid du Colombier 		val_enc(&p, e, &constr, 0);
83580ee5cbfSDavid du Colombier 	else
83680ee5cbfSDavid du Colombier 		p += vlen;
83780ee5cbfSDavid du Colombier 	*pp = p;
83880ee5cbfSDavid du Colombier 	return err;
83980ee5cbfSDavid du Colombier }
84080ee5cbfSDavid du Colombier 
84180ee5cbfSDavid du Colombier static int
84280ee5cbfSDavid du Colombier val_enc(uchar** pp, Elem e, int *pconstr, int lenonly)
84380ee5cbfSDavid du Colombier {
84480ee5cbfSDavid du Colombier 	int err;
84580ee5cbfSDavid du Colombier 	uchar* p;
84680ee5cbfSDavid du Colombier 	int kind;
84780ee5cbfSDavid du Colombier 	int cl;
84880ee5cbfSDavid du Colombier 	int v;
84980ee5cbfSDavid du Colombier 	Bytes* bb = nil;
85080ee5cbfSDavid du Colombier 	Bits* bits;
85180ee5cbfSDavid du Colombier 	Ints* oid;
85280ee5cbfSDavid du Colombier 	int k;
85380ee5cbfSDavid du Colombier 	Elist* el;
85480ee5cbfSDavid du Colombier 	char* s;
85580ee5cbfSDavid du Colombier 
85680ee5cbfSDavid du Colombier 	p = *pp;
85780ee5cbfSDavid du Colombier 	err = ASN_OK;
85880ee5cbfSDavid du Colombier 	kind = e.tag.num;
85980ee5cbfSDavid du Colombier 	cl = e.tag.class;
86080ee5cbfSDavid du Colombier 	*pconstr = 0;
86180ee5cbfSDavid du Colombier 	if(cl != Universal) {
86280ee5cbfSDavid du Colombier 		switch(e.val.tag) {
86380ee5cbfSDavid du Colombier 		case VBool:
86480ee5cbfSDavid du Colombier 			kind = BOOLEAN;
86580ee5cbfSDavid du Colombier 			break;
86680ee5cbfSDavid du Colombier 		case VInt:
86780ee5cbfSDavid du Colombier 			kind = INTEGER;
86880ee5cbfSDavid du Colombier 			break;
86980ee5cbfSDavid du Colombier 		case VBigInt:
87080ee5cbfSDavid du Colombier 			kind = INTEGER;
87180ee5cbfSDavid du Colombier 			break;
87280ee5cbfSDavid du Colombier 		case VOctets:
87380ee5cbfSDavid du Colombier 			kind = OCTET_STRING;
87480ee5cbfSDavid du Colombier 			break;
87580ee5cbfSDavid du Colombier 		case VReal:
87680ee5cbfSDavid du Colombier 			kind = REAL;
87780ee5cbfSDavid du Colombier 			break;
87880ee5cbfSDavid du Colombier 		case VOther:
87980ee5cbfSDavid du Colombier 			kind = OCTET_STRING;
88080ee5cbfSDavid du Colombier 			break;
88180ee5cbfSDavid du Colombier 		case VBitString:
88280ee5cbfSDavid du Colombier 			kind = BIT_STRING;
88380ee5cbfSDavid du Colombier 			break;
88480ee5cbfSDavid du Colombier 		case VNull:
88580ee5cbfSDavid du Colombier 			kind = NULLTAG;
88680ee5cbfSDavid du Colombier 			break;
88780ee5cbfSDavid du Colombier 		case VObjId:
88880ee5cbfSDavid du Colombier 			kind = OBJECT_ID;
88980ee5cbfSDavid du Colombier 			break;
89080ee5cbfSDavid du Colombier 		case VString:
89180ee5cbfSDavid du Colombier 			kind = UniversalString;
89280ee5cbfSDavid du Colombier 			break;
89380ee5cbfSDavid du Colombier 		case VSeq:
89480ee5cbfSDavid du Colombier 			kind = SEQUENCE;
89580ee5cbfSDavid du Colombier 			break;
89680ee5cbfSDavid du Colombier 		case VSet:
8979a747e4fSDavid du Colombier 			kind = SETOF;
89880ee5cbfSDavid du Colombier 			break;
89980ee5cbfSDavid du Colombier 		}
90080ee5cbfSDavid du Colombier 	}
90180ee5cbfSDavid du Colombier 	switch(kind) {
90280ee5cbfSDavid du Colombier 	case BOOLEAN:
90380ee5cbfSDavid du Colombier 		if(is_int(&e, &v)) {
90480ee5cbfSDavid du Colombier 			if(v != 0)
90580ee5cbfSDavid du Colombier 				v = 255;
90680ee5cbfSDavid du Colombier 			 int_enc(&p, v, 1, lenonly);
90780ee5cbfSDavid du Colombier 		}
90880ee5cbfSDavid du Colombier 		else
90980ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
91080ee5cbfSDavid du Colombier 		break;
91180ee5cbfSDavid du Colombier 
91280ee5cbfSDavid du Colombier 	case INTEGER:
91380ee5cbfSDavid du Colombier 	case ENUMERATED:
91480ee5cbfSDavid du Colombier 		if(is_int(&e, &v))
91580ee5cbfSDavid du Colombier 			int_enc(&p, v, 0, lenonly);
91680ee5cbfSDavid du Colombier 		else {
91780ee5cbfSDavid du Colombier 			if(is_bigint(&e, &bb)) {
91880ee5cbfSDavid du Colombier 				if(!lenonly)
91980ee5cbfSDavid du Colombier 					memmove(p, bb->data, bb->len);
92080ee5cbfSDavid du Colombier 				p += bb->len;
92180ee5cbfSDavid du Colombier 			}
92280ee5cbfSDavid du Colombier 			else
92380ee5cbfSDavid du Colombier 				err = ASN_EINVAL;
92480ee5cbfSDavid du Colombier 		}
92580ee5cbfSDavid du Colombier 		break;
92680ee5cbfSDavid du Colombier 
92780ee5cbfSDavid du Colombier 	case BIT_STRING:
92880ee5cbfSDavid du Colombier 		if(is_bitstring(&e, &bits)) {
92980ee5cbfSDavid du Colombier 			if(bits->len == 0) {
93080ee5cbfSDavid du Colombier 				if(!lenonly)
93180ee5cbfSDavid du Colombier 					*p = 0;
93280ee5cbfSDavid du Colombier 				p++;
93380ee5cbfSDavid du Colombier 			}
93480ee5cbfSDavid du Colombier 			else {
93580ee5cbfSDavid du Colombier 				v = bits->unusedbits;
93680ee5cbfSDavid du Colombier 				if(v < 0 || v > 7)
93780ee5cbfSDavid du Colombier 					err = ASN_EINVAL;
93880ee5cbfSDavid du Colombier 				else {
93980ee5cbfSDavid du Colombier 					if(!lenonly) {
94080ee5cbfSDavid du Colombier 						*p = v;
94180ee5cbfSDavid du Colombier 						memmove(p+1, bits->data, bits->len);
94280ee5cbfSDavid du Colombier 					}
94380ee5cbfSDavid du Colombier 					p += 1 + bits->len;
94480ee5cbfSDavid du Colombier 				}
94580ee5cbfSDavid du Colombier 			}
94680ee5cbfSDavid du Colombier 		}
94780ee5cbfSDavid du Colombier 		else
94880ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
94980ee5cbfSDavid du Colombier 		break;
95080ee5cbfSDavid du Colombier 
95180ee5cbfSDavid du Colombier 	case OCTET_STRING:
95280ee5cbfSDavid du Colombier 	case ObjectDescriptor:
95380ee5cbfSDavid du Colombier 	case EXTERNAL:
95480ee5cbfSDavid du Colombier 	case REAL:
95580ee5cbfSDavid du Colombier 	case EMBEDDED_PDV:
95680ee5cbfSDavid du Colombier 		bb = nil;
95780ee5cbfSDavid du Colombier 		switch(e.val.tag) {
95880ee5cbfSDavid du Colombier 		case VOctets:
95980ee5cbfSDavid du Colombier 			bb = e.val.u.octetsval;
96080ee5cbfSDavid du Colombier 			break;
96180ee5cbfSDavid du Colombier 		case VReal:
96280ee5cbfSDavid du Colombier 			bb = e.val.u.realval;
96380ee5cbfSDavid du Colombier 			break;
96480ee5cbfSDavid du Colombier 		case VOther:
96580ee5cbfSDavid du Colombier 			bb = e.val.u.otherval;
96680ee5cbfSDavid du Colombier 			break;
96780ee5cbfSDavid du Colombier 		}
96880ee5cbfSDavid du Colombier 		if(bb != nil) {
96980ee5cbfSDavid du Colombier 			if(!lenonly)
97080ee5cbfSDavid du Colombier 				memmove(p, bb->data, bb->len);
97180ee5cbfSDavid du Colombier 			p += bb->len;
97280ee5cbfSDavid du Colombier 		}
97380ee5cbfSDavid du Colombier 			else
97480ee5cbfSDavid du Colombier 				err = ASN_EINVAL;
97580ee5cbfSDavid du Colombier 		break;
97680ee5cbfSDavid du Colombier 
97780ee5cbfSDavid du Colombier 	case NULLTAG:
97880ee5cbfSDavid du Colombier 		break;
97980ee5cbfSDavid du Colombier 
98080ee5cbfSDavid du Colombier 	case OBJECT_ID:
98180ee5cbfSDavid du Colombier 		if(is_oid(&e, &oid)) {
98280ee5cbfSDavid du Colombier 			for(k = 0; k < oid->len; k++) {
98380ee5cbfSDavid du Colombier 				v = oid->data[k];
98480ee5cbfSDavid du Colombier 				if(k == 0) {
98580ee5cbfSDavid du Colombier 					v *= 40;
98680ee5cbfSDavid du Colombier 					if(oid->len > 1)
98780ee5cbfSDavid du Colombier 						v += oid->data[++k];
98880ee5cbfSDavid du Colombier 				}
98980ee5cbfSDavid du Colombier 				uint7_enc(&p, v, lenonly);
99080ee5cbfSDavid du Colombier 			}
99180ee5cbfSDavid du Colombier 		}
99280ee5cbfSDavid du Colombier 		else
99380ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
99480ee5cbfSDavid du Colombier 		break;
99580ee5cbfSDavid du Colombier 
99680ee5cbfSDavid du Colombier 	case SEQUENCE:
9979a747e4fSDavid du Colombier 	case SETOF:
99880ee5cbfSDavid du Colombier 		el = nil;
99980ee5cbfSDavid du Colombier 		if(e.val.tag == VSeq)
100080ee5cbfSDavid du Colombier 			el = e.val.u.seqval;
100180ee5cbfSDavid du Colombier 		else if(e.val.tag == VSet)
100280ee5cbfSDavid du Colombier 			el = e.val.u.setval;
100380ee5cbfSDavid du Colombier 		else
100480ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
100580ee5cbfSDavid du Colombier 		if(el != nil) {
100680ee5cbfSDavid du Colombier 			*pconstr = CONSTR_MASK;
100780ee5cbfSDavid du Colombier 			for(; el != nil; el = el->tl) {
100880ee5cbfSDavid du Colombier 				err = enc(&p, el->hd, lenonly);
100980ee5cbfSDavid du Colombier 				if(err != ASN_OK)
101080ee5cbfSDavid du Colombier 					break;
101180ee5cbfSDavid du Colombier 			}
101280ee5cbfSDavid du Colombier 		}
101380ee5cbfSDavid du Colombier 		break;
101480ee5cbfSDavid du Colombier 
101580ee5cbfSDavid du Colombier 	case NumericString:
101680ee5cbfSDavid du Colombier 	case PrintableString:
101780ee5cbfSDavid du Colombier 	case TeletexString:
101880ee5cbfSDavid du Colombier 	case VideotexString:
101980ee5cbfSDavid du Colombier 	case IA5String:
102080ee5cbfSDavid du Colombier 	case UTCTime:
102180ee5cbfSDavid du Colombier 	case GeneralizedTime:
102280ee5cbfSDavid du Colombier 	case GraphicString:
102380ee5cbfSDavid du Colombier 	case VisibleString:
102480ee5cbfSDavid du Colombier 	case GeneralString:
102580ee5cbfSDavid du Colombier 	case UniversalString:
102680ee5cbfSDavid du Colombier 	case BMPString:
102780ee5cbfSDavid du Colombier 		if(e.val.tag == VString) {
102880ee5cbfSDavid du Colombier 			s = e.val.u.stringval;
102980ee5cbfSDavid du Colombier 			if(s != nil) {
103080ee5cbfSDavid du Colombier 				v = strlen(s);
1031d9306527SDavid du Colombier 				if(!lenonly)
103280ee5cbfSDavid du Colombier 					memmove(p, s, v);
103380ee5cbfSDavid du Colombier 				p += v;
103480ee5cbfSDavid du Colombier 			}
103580ee5cbfSDavid du Colombier 		}
103680ee5cbfSDavid du Colombier 		else
103780ee5cbfSDavid du Colombier 			err = ASN_EINVAL;
103880ee5cbfSDavid du Colombier 		break;
103980ee5cbfSDavid du Colombier 
104080ee5cbfSDavid du Colombier 	default:
104180ee5cbfSDavid du Colombier 		err = ASN_EINVAL;
104280ee5cbfSDavid du Colombier 	}
104380ee5cbfSDavid du Colombier 	*pp = p;
104480ee5cbfSDavid du Colombier 	return err;
104580ee5cbfSDavid du Colombier }
104680ee5cbfSDavid du Colombier 
104780ee5cbfSDavid du Colombier /*
104880ee5cbfSDavid du Colombier  * Encode num as unsigned 7 bit values with top bit 1 on all bytes
104980ee5cbfSDavid du Colombier  * except last, only putting in bytes if !lenonly.
105080ee5cbfSDavid du Colombier  */
105180ee5cbfSDavid du Colombier static void
105280ee5cbfSDavid du Colombier uint7_enc(uchar** pp, int num, int lenonly)
105380ee5cbfSDavid du Colombier {
105480ee5cbfSDavid du Colombier 	int n;
105580ee5cbfSDavid du Colombier 	int v;
105680ee5cbfSDavid du Colombier 	int k;
105780ee5cbfSDavid du Colombier 	uchar* p;
105880ee5cbfSDavid du Colombier 
105980ee5cbfSDavid du Colombier 	p = *pp;
106080ee5cbfSDavid du Colombier 	n = 1;
106180ee5cbfSDavid du Colombier 	v = num >> 7;
106280ee5cbfSDavid du Colombier 	while(v > 0) {
106380ee5cbfSDavid du Colombier 		v >>= 7;
106480ee5cbfSDavid du Colombier 		n++;
106580ee5cbfSDavid du Colombier 	}
106680ee5cbfSDavid du Colombier 	if(lenonly)
106780ee5cbfSDavid du Colombier 		p += n;
106880ee5cbfSDavid du Colombier 	else {
106980ee5cbfSDavid du Colombier 		for(k = (n - 1)*7; k > 0; k -= 7)
107080ee5cbfSDavid du Colombier 			*p++= ((num >> k)|0x80);
107180ee5cbfSDavid du Colombier 		*p++ = (num&0x7F);
107280ee5cbfSDavid du Colombier 	}
107380ee5cbfSDavid du Colombier 	*pp = p;
107480ee5cbfSDavid du Colombier }
107580ee5cbfSDavid du Colombier 
107680ee5cbfSDavid du Colombier /*
107780ee5cbfSDavid du Colombier  * Encode num as unsigned or signed integer,
107880ee5cbfSDavid du Colombier  * only putting in bytes if !lenonly.
107980ee5cbfSDavid du Colombier  * Encoding is length followed by bytes to concatenate.
108080ee5cbfSDavid du Colombier  */
108180ee5cbfSDavid du Colombier static void
108280ee5cbfSDavid du Colombier int_enc(uchar** pp, int num, int unsgned, int lenonly)
108380ee5cbfSDavid du Colombier {
108480ee5cbfSDavid du Colombier 	int v;
108580ee5cbfSDavid du Colombier 	int n;
108680ee5cbfSDavid du Colombier 	int prevv;
108780ee5cbfSDavid du Colombier 	int k;
108880ee5cbfSDavid du Colombier 	uchar* p;
108980ee5cbfSDavid du Colombier 
109080ee5cbfSDavid du Colombier 	p = *pp;
109180ee5cbfSDavid du Colombier 	v = num;
109280ee5cbfSDavid du Colombier 	if(v < 0)
109380ee5cbfSDavid du Colombier 		v = -(v + 1);
109480ee5cbfSDavid du Colombier 	n = 1;
109580ee5cbfSDavid du Colombier 	prevv = v;
109680ee5cbfSDavid du Colombier 	v >>= 8;
109780ee5cbfSDavid du Colombier 	while(v > 0) {
109880ee5cbfSDavid du Colombier 		prevv = v;
109980ee5cbfSDavid du Colombier 		v >>= 8;
110080ee5cbfSDavid du Colombier 		n++;
110180ee5cbfSDavid du Colombier 	}
110280ee5cbfSDavid du Colombier 	if(!unsgned && (prevv&0x80))
110380ee5cbfSDavid du Colombier 		n++;
110480ee5cbfSDavid du Colombier 	if(lenonly)
110580ee5cbfSDavid du Colombier 		p += n;
110680ee5cbfSDavid du Colombier 	else {
110780ee5cbfSDavid du Colombier 		for(k = (n - 1)*8; k >= 0; k -= 8)
110880ee5cbfSDavid du Colombier 			*p++ = (num >> k);
110980ee5cbfSDavid du Colombier 	}
111080ee5cbfSDavid du Colombier 	*pp = p;
111180ee5cbfSDavid du Colombier }
111280ee5cbfSDavid du Colombier 
111380ee5cbfSDavid du Colombier static int
111480ee5cbfSDavid du Colombier ints_eq(Ints* a, Ints* b)
111580ee5cbfSDavid du Colombier {
111680ee5cbfSDavid du Colombier 	int	alen;
111780ee5cbfSDavid du Colombier 	int	i;
111880ee5cbfSDavid du Colombier 
111980ee5cbfSDavid du Colombier 	alen = a->len;
112080ee5cbfSDavid du Colombier 	if(alen != b->len)
112180ee5cbfSDavid du Colombier 		return 0;
112280ee5cbfSDavid du Colombier 	for(i = 0; i < alen; i++)
112380ee5cbfSDavid du Colombier 		if(a->data[i] != b->data[i])
112480ee5cbfSDavid du Colombier 			return 0;
112580ee5cbfSDavid du Colombier 	return 1;
112680ee5cbfSDavid du Colombier }
112780ee5cbfSDavid du Colombier 
112880ee5cbfSDavid du Colombier /*
112980ee5cbfSDavid du Colombier  * Look up o in tab (which must have nil entry to terminate).
113080ee5cbfSDavid du Colombier  * Return index of matching entry, or -1 if none.
113180ee5cbfSDavid du Colombier  */
113280ee5cbfSDavid du Colombier static int
113380ee5cbfSDavid du Colombier oid_lookup(Ints* o, Ints** tab)
113480ee5cbfSDavid du Colombier {
113580ee5cbfSDavid du Colombier 	int i;
113680ee5cbfSDavid du Colombier 
113780ee5cbfSDavid du Colombier 	for(i = 0; tab[i] != nil; i++)
113880ee5cbfSDavid du Colombier 		if(ints_eq(o, tab[i]))
113980ee5cbfSDavid du Colombier 			return  i;
114080ee5cbfSDavid du Colombier 	return -1;
114180ee5cbfSDavid du Colombier }
114280ee5cbfSDavid du Colombier 
114380ee5cbfSDavid du Colombier /*
114480ee5cbfSDavid du Colombier  * Return true if *pe is a SEQUENCE, and set *pseq to
114580ee5cbfSDavid du Colombier  * the value of the sequence if so.
114680ee5cbfSDavid du Colombier  */
114780ee5cbfSDavid du Colombier static int
114880ee5cbfSDavid du Colombier is_seq(Elem* pe, Elist** pseq)
114980ee5cbfSDavid du Colombier {
115080ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == SEQUENCE && pe->val.tag == VSeq) {
115180ee5cbfSDavid du Colombier 		*pseq = pe->val.u.seqval;
115280ee5cbfSDavid du Colombier 		return 1;
115380ee5cbfSDavid du Colombier 	}
115480ee5cbfSDavid du Colombier 	return 0;
115580ee5cbfSDavid du Colombier }
115680ee5cbfSDavid du Colombier 
115780ee5cbfSDavid du Colombier static int
115880ee5cbfSDavid du Colombier is_set(Elem* pe, Elist** pset)
115980ee5cbfSDavid du Colombier {
11609a747e4fSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == SETOF && pe->val.tag == VSet) {
116180ee5cbfSDavid du Colombier 		*pset = pe->val.u.setval;
116280ee5cbfSDavid du Colombier 		return 1;
116380ee5cbfSDavid du Colombier 	}
116480ee5cbfSDavid du Colombier 	return 0;
116580ee5cbfSDavid du Colombier }
116680ee5cbfSDavid du Colombier 
116780ee5cbfSDavid du Colombier static int
116880ee5cbfSDavid du Colombier is_int(Elem* pe, int* pint)
116980ee5cbfSDavid du Colombier {
117080ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal) {
117180ee5cbfSDavid du Colombier 		if(pe->tag.num == INTEGER && pe->val.tag == VInt) {
117280ee5cbfSDavid du Colombier 			*pint = pe->val.u.intval;
117380ee5cbfSDavid du Colombier 			return 1;
117480ee5cbfSDavid du Colombier 		}
117580ee5cbfSDavid du Colombier 		else if(pe->tag.num == BOOLEAN && pe->val.tag == VBool) {
117680ee5cbfSDavid du Colombier 			*pint = pe->val.u.boolval;
117780ee5cbfSDavid du Colombier 			return 1;
117880ee5cbfSDavid du Colombier 		}
117980ee5cbfSDavid du Colombier 	}
118080ee5cbfSDavid du Colombier 	return 0;
118180ee5cbfSDavid du Colombier }
118280ee5cbfSDavid du Colombier 
11839a747e4fSDavid du Colombier /*
11849a747e4fSDavid du Colombier  * for convience, all VInt's are readable via this routine,
11859a747e4fSDavid du Colombier  * as well as all VBigInt's
11869a747e4fSDavid du Colombier  */
118780ee5cbfSDavid du Colombier static int
118880ee5cbfSDavid du Colombier is_bigint(Elem* pe, Bytes** pbigint)
118980ee5cbfSDavid du Colombier {
11909a747e4fSDavid du Colombier 	int v, n, i;
11919a747e4fSDavid du Colombier 
11929a747e4fSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == INTEGER) {
11939a747e4fSDavid du Colombier 		if(pe->val.tag == VBigInt)
119480ee5cbfSDavid du Colombier 			*pbigint = pe->val.u.bigintval;
11959a747e4fSDavid du Colombier 		else if(pe->val.tag == VInt){
11969a747e4fSDavid du Colombier 			v = pe->val.u.intval;
11979a747e4fSDavid du Colombier 			for(n = 1; n < 4; n++)
11989a747e4fSDavid du Colombier 				if((1 << (8 * n)) > v)
11999a747e4fSDavid du Colombier 					break;
12009a747e4fSDavid du Colombier 			*pbigint = newbytes(n);
12019a747e4fSDavid du Colombier 			for(i = 0; i < n; i++)
12029a747e4fSDavid du Colombier 				(*pbigint)->data[i] = (v >> ((n - 1 - i) * 8));
12039a747e4fSDavid du Colombier 		}else
12049a747e4fSDavid du Colombier 			return 0;
120580ee5cbfSDavid du Colombier 		return 1;
120680ee5cbfSDavid du Colombier 	}
120780ee5cbfSDavid du Colombier 	return 0;
120880ee5cbfSDavid du Colombier }
120980ee5cbfSDavid du Colombier 
121080ee5cbfSDavid du Colombier static int
121180ee5cbfSDavid du Colombier is_bitstring(Elem* pe, Bits** pbits)
121280ee5cbfSDavid du Colombier {
121380ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == BIT_STRING && pe->val.tag == VBitString) {
121480ee5cbfSDavid du Colombier 		*pbits = pe->val.u.bitstringval;
121580ee5cbfSDavid du Colombier 		return 1;
121680ee5cbfSDavid du Colombier 	}
121780ee5cbfSDavid du Colombier 	return 0;
121880ee5cbfSDavid du Colombier }
121980ee5cbfSDavid du Colombier 
122080ee5cbfSDavid du Colombier static int
122180ee5cbfSDavid du Colombier is_octetstring(Elem* pe, Bytes** poctets)
122280ee5cbfSDavid du Colombier {
122380ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == OCTET_STRING && pe->val.tag == VOctets) {
122480ee5cbfSDavid du Colombier 		*poctets = pe->val.u.octetsval;
122580ee5cbfSDavid du Colombier 		return 1;
122680ee5cbfSDavid du Colombier 	}
122780ee5cbfSDavid du Colombier 	return 0;
122880ee5cbfSDavid du Colombier }
122980ee5cbfSDavid du Colombier 
123080ee5cbfSDavid du Colombier static int
123180ee5cbfSDavid du Colombier is_oid(Elem* pe, Ints** poid)
123280ee5cbfSDavid du Colombier {
123380ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal && pe->tag.num == OBJECT_ID && pe->val.tag == VObjId) {
123480ee5cbfSDavid du Colombier 		*poid = pe->val.u.objidval;
123580ee5cbfSDavid du Colombier 		return 1;
123680ee5cbfSDavid du Colombier 	}
123780ee5cbfSDavid du Colombier 	return 0;
123880ee5cbfSDavid du Colombier }
123980ee5cbfSDavid du Colombier 
124080ee5cbfSDavid du Colombier static int
124180ee5cbfSDavid du Colombier is_string(Elem* pe, char** pstring)
124280ee5cbfSDavid du Colombier {
124380ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal) {
124480ee5cbfSDavid du Colombier 		switch(pe->tag.num) {
124580ee5cbfSDavid du Colombier 		case NumericString:
124680ee5cbfSDavid du Colombier 		case PrintableString:
124780ee5cbfSDavid du Colombier 		case TeletexString:
124880ee5cbfSDavid du Colombier 		case VideotexString:
124980ee5cbfSDavid du Colombier 		case IA5String:
125080ee5cbfSDavid du Colombier 		case GraphicString:
125180ee5cbfSDavid du Colombier 		case VisibleString:
125280ee5cbfSDavid du Colombier 		case GeneralString:
125380ee5cbfSDavid du Colombier 		case UniversalString:
125480ee5cbfSDavid du Colombier 		case BMPString:
125580ee5cbfSDavid du Colombier 			if(pe->val.tag == VString) {
125680ee5cbfSDavid du Colombier 				*pstring = pe->val.u.stringval;
125780ee5cbfSDavid du Colombier 				return 1;
125880ee5cbfSDavid du Colombier 			}
125980ee5cbfSDavid du Colombier 		}
126080ee5cbfSDavid du Colombier 	}
126180ee5cbfSDavid du Colombier 	return 0;
126280ee5cbfSDavid du Colombier }
126380ee5cbfSDavid du Colombier 
126480ee5cbfSDavid du Colombier static int
126580ee5cbfSDavid du Colombier is_time(Elem* pe, char** ptime)
126680ee5cbfSDavid du Colombier {
126780ee5cbfSDavid du Colombier 	if(pe->tag.class == Universal
126880ee5cbfSDavid du Colombier 	   && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
126980ee5cbfSDavid du Colombier 	   && pe->val.tag == VString) {
127080ee5cbfSDavid du Colombier 		*ptime = pe->val.u.stringval;
127180ee5cbfSDavid du Colombier 		return 1;
127280ee5cbfSDavid du Colombier 	}
127380ee5cbfSDavid du Colombier 	return 0;
127480ee5cbfSDavid du Colombier }
127580ee5cbfSDavid du Colombier 
127680ee5cbfSDavid du Colombier 
127780ee5cbfSDavid du Colombier /*
127880ee5cbfSDavid du Colombier  * malloc and return a new Bytes structure capable of
127980ee5cbfSDavid du Colombier  * holding len bytes. (len >= 0)
128080ee5cbfSDavid du Colombier  */
128180ee5cbfSDavid du Colombier static Bytes*
128280ee5cbfSDavid du Colombier newbytes(int len)
128380ee5cbfSDavid du Colombier {
128480ee5cbfSDavid du Colombier 	Bytes* ans;
128580ee5cbfSDavid du Colombier 
1286d9306527SDavid du Colombier 	ans = (Bytes*)emalloc(OFFSETOF(data[0], Bytes) + len);
128780ee5cbfSDavid du Colombier 	ans->len = len;
128880ee5cbfSDavid du Colombier 	return ans;
128980ee5cbfSDavid du Colombier }
129080ee5cbfSDavid du Colombier 
129180ee5cbfSDavid du Colombier /*
129280ee5cbfSDavid du Colombier  * newbytes(len), with data initialized from buf
129380ee5cbfSDavid du Colombier  */
129480ee5cbfSDavid du Colombier static Bytes*
129580ee5cbfSDavid du Colombier makebytes(uchar* buf, int len)
129680ee5cbfSDavid du Colombier {
129780ee5cbfSDavid du Colombier 	Bytes* ans;
129880ee5cbfSDavid du Colombier 
129980ee5cbfSDavid du Colombier 	ans = newbytes(len);
130080ee5cbfSDavid du Colombier 	memmove(ans->data, buf, len);
130180ee5cbfSDavid du Colombier 	return ans;
130280ee5cbfSDavid du Colombier }
130380ee5cbfSDavid du Colombier 
130480ee5cbfSDavid du Colombier static void
130580ee5cbfSDavid du Colombier freebytes(Bytes* b)
130680ee5cbfSDavid du Colombier {
130780ee5cbfSDavid du Colombier 	if(b != nil)
130880ee5cbfSDavid du Colombier 		free(b);
130980ee5cbfSDavid du Colombier }
131080ee5cbfSDavid du Colombier 
131180ee5cbfSDavid du Colombier /*
131280ee5cbfSDavid du Colombier  * Make a new Bytes, containing bytes of b1 followed by those of b2.
131380ee5cbfSDavid du Colombier  * Either b1 or b2 or both can be nil.
131480ee5cbfSDavid du Colombier  */
131580ee5cbfSDavid du Colombier static Bytes*
131680ee5cbfSDavid du Colombier catbytes(Bytes* b1, Bytes* b2)
131780ee5cbfSDavid du Colombier {
131880ee5cbfSDavid du Colombier 	Bytes* ans;
131980ee5cbfSDavid du Colombier 	int n;
132080ee5cbfSDavid du Colombier 
132180ee5cbfSDavid du Colombier 	if(b1 == nil) {
132280ee5cbfSDavid du Colombier 		if(b2 == nil)
132380ee5cbfSDavid du Colombier 			ans = newbytes(0);
132480ee5cbfSDavid du Colombier 		else
132580ee5cbfSDavid du Colombier 			ans = makebytes(b2->data, b2->len);
132680ee5cbfSDavid du Colombier 	}
132780ee5cbfSDavid du Colombier 	else if(b2 == nil) {
132880ee5cbfSDavid du Colombier 		ans = makebytes(b1->data, b1->len);
132980ee5cbfSDavid du Colombier 	}
133080ee5cbfSDavid du Colombier 	else {
133180ee5cbfSDavid du Colombier 		n = b1->len + b2->len;
133280ee5cbfSDavid du Colombier 		ans = newbytes(n);
133380ee5cbfSDavid du Colombier 		ans->len = n;
133480ee5cbfSDavid du Colombier 		memmove(ans->data, b1->data, b1->len);
133580ee5cbfSDavid du Colombier 		memmove(ans->data+b1->len, b2->data, b2->len);
133680ee5cbfSDavid du Colombier 	}
133780ee5cbfSDavid du Colombier 	return ans;
133880ee5cbfSDavid du Colombier }
133980ee5cbfSDavid du Colombier 
134080ee5cbfSDavid du Colombier /* len is number of ints */
134180ee5cbfSDavid du Colombier static Ints*
134280ee5cbfSDavid du Colombier newints(int len)
134380ee5cbfSDavid du Colombier {
134480ee5cbfSDavid du Colombier 	Ints* ans;
134580ee5cbfSDavid du Colombier 
1346d9306527SDavid du Colombier 	ans = (Ints*)emalloc(OFFSETOF(data[0], Ints) + len*sizeof(int));
134780ee5cbfSDavid du Colombier 	ans->len = len;
134880ee5cbfSDavid du Colombier 	return ans;
134980ee5cbfSDavid du Colombier }
135080ee5cbfSDavid du Colombier 
135180ee5cbfSDavid du Colombier static Ints*
135280ee5cbfSDavid du Colombier makeints(int* buf, int len)
135380ee5cbfSDavid du Colombier {
135480ee5cbfSDavid du Colombier 	Ints* ans;
135580ee5cbfSDavid du Colombier 
135680ee5cbfSDavid du Colombier 	ans = newints(len);
135780ee5cbfSDavid du Colombier 	if(len > 0)
135880ee5cbfSDavid du Colombier 		memmove(ans->data, buf, len*sizeof(int));
135980ee5cbfSDavid du Colombier 	return ans;
136080ee5cbfSDavid du Colombier }
136180ee5cbfSDavid du Colombier 
136280ee5cbfSDavid du Colombier static void
136380ee5cbfSDavid du Colombier freeints(Ints* b)
136480ee5cbfSDavid du Colombier {
136580ee5cbfSDavid du Colombier 	if(b != nil)
136680ee5cbfSDavid du Colombier 		free(b);
136780ee5cbfSDavid du Colombier }
136880ee5cbfSDavid du Colombier 
136980ee5cbfSDavid du Colombier /* len is number of bytes */
137080ee5cbfSDavid du Colombier static Bits*
137180ee5cbfSDavid du Colombier newbits(int len)
137280ee5cbfSDavid du Colombier {
137380ee5cbfSDavid du Colombier 	Bits* ans;
137480ee5cbfSDavid du Colombier 
1375d9306527SDavid du Colombier 	ans = (Bits*)emalloc(OFFSETOF(data[0], Bits) + len);
137680ee5cbfSDavid du Colombier 	ans->len = len;
137780ee5cbfSDavid du Colombier 	ans->unusedbits = 0;
137880ee5cbfSDavid du Colombier 	return ans;
137980ee5cbfSDavid du Colombier }
138080ee5cbfSDavid du Colombier 
138180ee5cbfSDavid du Colombier static Bits*
138280ee5cbfSDavid du Colombier makebits(uchar* buf, int len, int unusedbits)
138380ee5cbfSDavid du Colombier {
138480ee5cbfSDavid du Colombier 	Bits* ans;
138580ee5cbfSDavid du Colombier 
138680ee5cbfSDavid du Colombier 	ans = newbits(len);
138780ee5cbfSDavid du Colombier 	memmove(ans->data, buf, len);
138880ee5cbfSDavid du Colombier 	ans->unusedbits = unusedbits;
138980ee5cbfSDavid du Colombier 	return ans;
139080ee5cbfSDavid du Colombier }
139180ee5cbfSDavid du Colombier 
139280ee5cbfSDavid du Colombier static void
139380ee5cbfSDavid du Colombier freebits(Bits* b)
139480ee5cbfSDavid du Colombier {
139580ee5cbfSDavid du Colombier 	if(b != nil)
139680ee5cbfSDavid du Colombier 		free(b);
139780ee5cbfSDavid du Colombier }
139880ee5cbfSDavid du Colombier 
139980ee5cbfSDavid du Colombier static Elist*
1400d9306527SDavid du Colombier mkel(Elem e, Elist* tail)
140180ee5cbfSDavid du Colombier {
140280ee5cbfSDavid du Colombier 	Elist* el;
140380ee5cbfSDavid du Colombier 
1404d9306527SDavid du Colombier 	el = (Elist*)emalloc(sizeof(Elist));
140580ee5cbfSDavid du Colombier 	el->hd = e;
140680ee5cbfSDavid du Colombier 	el->tl = tail;
140780ee5cbfSDavid du Colombier 	return el;
140880ee5cbfSDavid du Colombier }
140980ee5cbfSDavid du Colombier 
141080ee5cbfSDavid du Colombier static int
141180ee5cbfSDavid du Colombier elistlen(Elist* el)
141280ee5cbfSDavid du Colombier {
141380ee5cbfSDavid du Colombier 	int ans = 0;
141480ee5cbfSDavid du Colombier 	while(el != nil) {
141580ee5cbfSDavid du Colombier 		ans++;
141680ee5cbfSDavid du Colombier 		el = el->tl;
141780ee5cbfSDavid du Colombier 	}
141880ee5cbfSDavid du Colombier 	return ans;
141980ee5cbfSDavid du Colombier }
142080ee5cbfSDavid du Colombier 
142180ee5cbfSDavid du Colombier /* Frees elist, but not fields inside values of constituent elems */
142280ee5cbfSDavid du Colombier static void
142380ee5cbfSDavid du Colombier freeelist(Elist* el)
142480ee5cbfSDavid du Colombier {
142580ee5cbfSDavid du Colombier 	Elist* next;
142680ee5cbfSDavid du Colombier 
142780ee5cbfSDavid du Colombier 	while(el != nil) {
142880ee5cbfSDavid du Colombier 		next = el->tl;
142980ee5cbfSDavid du Colombier 		free(el);
143080ee5cbfSDavid du Colombier 		el = next;
143180ee5cbfSDavid du Colombier 	}
143280ee5cbfSDavid du Colombier }
143380ee5cbfSDavid du Colombier 
143480ee5cbfSDavid du Colombier /* free any allocated structures inside v (recursively freeing Elists) */
143580ee5cbfSDavid du Colombier static void
143680ee5cbfSDavid du Colombier freevalfields(Value* v)
143780ee5cbfSDavid du Colombier {
143880ee5cbfSDavid du Colombier 	Elist* el;
143980ee5cbfSDavid du Colombier 	Elist* l;
144080ee5cbfSDavid du Colombier 	if(v == nil)
144180ee5cbfSDavid du Colombier 		return;
144280ee5cbfSDavid du Colombier 	switch(v->tag) {
144380ee5cbfSDavid du Colombier  	case VOctets:
144480ee5cbfSDavid du Colombier 		freebytes(v->u.octetsval);
144580ee5cbfSDavid du Colombier 		break;
144680ee5cbfSDavid du Colombier 	case VBigInt:
144780ee5cbfSDavid du Colombier 		freebytes(v->u.bigintval);
144880ee5cbfSDavid du Colombier 		break;
144980ee5cbfSDavid du Colombier 	case VReal:
145080ee5cbfSDavid du Colombier 		freebytes(v->u.realval);
145180ee5cbfSDavid du Colombier 		break;
145280ee5cbfSDavid du Colombier 	case VOther:
145380ee5cbfSDavid du Colombier 		freebytes(v->u.otherval);
145480ee5cbfSDavid du Colombier 		break;
145580ee5cbfSDavid du Colombier 	case VBitString:
145680ee5cbfSDavid du Colombier 		freebits(v->u.bitstringval);
145780ee5cbfSDavid du Colombier 		break;
145880ee5cbfSDavid du Colombier 	case VObjId:
145980ee5cbfSDavid du Colombier 		freeints(v->u.objidval);
146080ee5cbfSDavid du Colombier 		break;
146180ee5cbfSDavid du Colombier 	case VString:
146280ee5cbfSDavid du Colombier 		if (v->u.stringval)
146380ee5cbfSDavid du Colombier 			free(v->u.stringval);
146480ee5cbfSDavid du Colombier 		break;
146580ee5cbfSDavid du Colombier 	case VSeq:
146680ee5cbfSDavid du Colombier 		el = v->u.seqval;
146780ee5cbfSDavid du Colombier 		for(l = el; l != nil; l = l->tl)
146880ee5cbfSDavid du Colombier 			freevalfields(&l->hd.val);
146980ee5cbfSDavid du Colombier 		if (el)
147080ee5cbfSDavid du Colombier 			freeelist(el);
147180ee5cbfSDavid du Colombier 		break;
147280ee5cbfSDavid du Colombier 	case VSet:
147380ee5cbfSDavid du Colombier 		el = v->u.setval;
147480ee5cbfSDavid du Colombier 		for(l = el; l != nil; l = l->tl)
147580ee5cbfSDavid du Colombier 			freevalfields(&l->hd.val);
147680ee5cbfSDavid du Colombier 		if (el)
147780ee5cbfSDavid du Colombier 			freeelist(el);
147880ee5cbfSDavid du Colombier 		break;
147980ee5cbfSDavid du Colombier 	}
148080ee5cbfSDavid du Colombier }
148180ee5cbfSDavid du Colombier 
148280ee5cbfSDavid du Colombier /* end of general ASN1 functions */
148380ee5cbfSDavid du Colombier 
148480ee5cbfSDavid du Colombier 
148580ee5cbfSDavid du Colombier 
148680ee5cbfSDavid du Colombier 
148780ee5cbfSDavid du Colombier 
148880ee5cbfSDavid du Colombier /*=============================================================*/
148980ee5cbfSDavid du Colombier /*
149080ee5cbfSDavid du Colombier  * Decode and parse an X.509 Certificate, defined by this ASN1:
149180ee5cbfSDavid du Colombier  *	Certificate ::= SEQUENCE {
149280ee5cbfSDavid du Colombier  *		certificateInfo CertificateInfo,
149380ee5cbfSDavid du Colombier  *		signatureAlgorithm AlgorithmIdentifier,
149480ee5cbfSDavid du Colombier  *		signature BIT STRING }
149580ee5cbfSDavid du Colombier  *
149680ee5cbfSDavid du Colombier  *	CertificateInfo ::= SEQUENCE {
149780ee5cbfSDavid du Colombier  *		version [0] INTEGER DEFAULT v1 (0),
149880ee5cbfSDavid du Colombier  *		serialNumber INTEGER,
149980ee5cbfSDavid du Colombier  *		signature AlgorithmIdentifier,
150080ee5cbfSDavid du Colombier  *		issuer Name,
150180ee5cbfSDavid du Colombier  *		validity Validity,
150280ee5cbfSDavid du Colombier  *		subject Name,
150380ee5cbfSDavid du Colombier  *		subjectPublicKeyInfo SubjectPublicKeyInfo }
15043ff48bf5SDavid du Colombier  *	(version v2 has two more fields, optional unique identifiers for
15053ff48bf5SDavid du Colombier  *  issuer and subject; since we ignore these anyway, we won't parse them)
150680ee5cbfSDavid du Colombier  *
150780ee5cbfSDavid du Colombier  *	Validity ::= SEQUENCE {
150880ee5cbfSDavid du Colombier  *		notBefore UTCTime,
150980ee5cbfSDavid du Colombier  *		notAfter UTCTime }
151080ee5cbfSDavid du Colombier  *
151180ee5cbfSDavid du Colombier  *	SubjectPublicKeyInfo ::= SEQUENCE {
151280ee5cbfSDavid du Colombier  *		algorithm AlgorithmIdentifier,
151380ee5cbfSDavid du Colombier  *		subjectPublicKey BIT STRING }
151480ee5cbfSDavid du Colombier  *
151580ee5cbfSDavid du Colombier  *	AlgorithmIdentifier ::= SEQUENCE {
151680ee5cbfSDavid du Colombier  *		algorithm OBJECT IDENTIFER,
151780ee5cbfSDavid du Colombier  *		parameters ANY DEFINED BY ALGORITHM OPTIONAL }
151880ee5cbfSDavid du Colombier  *
151980ee5cbfSDavid du Colombier  *	Name ::= SEQUENCE OF RelativeDistinguishedName
152080ee5cbfSDavid du Colombier  *
15219a747e4fSDavid du Colombier  *	RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue
152280ee5cbfSDavid du Colombier  *
152380ee5cbfSDavid du Colombier  *	AttributeTypeAndValue ::= SEQUENCE {
152480ee5cbfSDavid du Colombier  *		type OBJECT IDENTIFER,
152580ee5cbfSDavid du Colombier  *		value DirectoryString }
152680ee5cbfSDavid du Colombier  *	(selected attributes have these Object Ids:
152780ee5cbfSDavid du Colombier  *		commonName {2 5 4 3}
152880ee5cbfSDavid du Colombier  *		countryName {2 5 4 6}
152980ee5cbfSDavid du Colombier  *		localityName {2 5 4 7}
153080ee5cbfSDavid du Colombier  *		stateOrProvinceName {2 5 4 8}
153180ee5cbfSDavid du Colombier  *		organizationName {2 5 4 10}
153280ee5cbfSDavid du Colombier  *		organizationalUnitName {2 5 4 11}
153380ee5cbfSDavid du Colombier  *	)
153480ee5cbfSDavid du Colombier  *
153580ee5cbfSDavid du Colombier  *	DirectoryString ::= CHOICE {
153680ee5cbfSDavid du Colombier  *		teletexString TeletexString,
153780ee5cbfSDavid du Colombier  *		printableString PrintableString,
153880ee5cbfSDavid du Colombier  *		universalString UniversalString }
153980ee5cbfSDavid du Colombier  *
15403ff48bf5SDavid du Colombier  *  See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature.
15413ff48bf5SDavid du Colombier  *
15423ff48bf5SDavid du Colombier  *  Not yet implemented:
15433ff48bf5SDavid du Colombier  *   CertificateRevocationList ::= SIGNED SEQUENCE{
15443ff48bf5SDavid du Colombier  *           signature       AlgorithmIdentifier,
15453ff48bf5SDavid du Colombier  *           issuer          Name,
15463ff48bf5SDavid du Colombier  *           lastUpdate      UTCTime,
15473ff48bf5SDavid du Colombier  *           nextUpdate      UTCTime,
15483ff48bf5SDavid du Colombier  *           revokedCertificates
15493ff48bf5SDavid du Colombier  *                           SEQUENCE OF CRLEntry OPTIONAL}
15503ff48bf5SDavid du Colombier  *   CRLEntry ::= SEQUENCE{
15513ff48bf5SDavid du Colombier  *           userCertificate SerialNumber,
15523ff48bf5SDavid du Colombier  *           revocationDate UTCTime}
155380ee5cbfSDavid du Colombier  */
155480ee5cbfSDavid du Colombier 
155580ee5cbfSDavid du Colombier typedef struct CertX509 {
155680ee5cbfSDavid du Colombier 	int	serial;
155780ee5cbfSDavid du Colombier 	char*	issuer;
155880ee5cbfSDavid du Colombier 	char*	validity_start;
155980ee5cbfSDavid du Colombier 	char*	validity_end;
156080ee5cbfSDavid du Colombier 	char*	subject;
156180ee5cbfSDavid du Colombier 	int	publickey_alg;
156280ee5cbfSDavid du Colombier 	Bytes*	publickey;
156380ee5cbfSDavid du Colombier 	int	signature_alg;
156480ee5cbfSDavid du Colombier 	Bytes*	signature;
156580ee5cbfSDavid du Colombier } CertX509;
156680ee5cbfSDavid du Colombier 
156780ee5cbfSDavid du Colombier /* Algorithm object-ids */
156880ee5cbfSDavid du Colombier enum {
156980ee5cbfSDavid du Colombier 	ALG_rsaEncryption,
157080ee5cbfSDavid du Colombier 	ALG_md2WithRSAEncryption,
157180ee5cbfSDavid du Colombier 	ALG_md4WithRSAEncryption,
157280ee5cbfSDavid du Colombier 	ALG_md5WithRSAEncryption,
15739a747e4fSDavid du Colombier 	ALG_sha1WithRSAEncryption,
15741075affeSDavid du Colombier 	ALG_md5,
157580ee5cbfSDavid du Colombier 	NUMALGS
157680ee5cbfSDavid du Colombier };
157780ee5cbfSDavid du Colombier typedef struct Ints7 {
157880ee5cbfSDavid du Colombier 	int		len;
157980ee5cbfSDavid du Colombier 	int		data[7];
158080ee5cbfSDavid du Colombier } Ints7;
158180ee5cbfSDavid du Colombier static Ints7 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 };
158280ee5cbfSDavid du Colombier static Ints7 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 };
158380ee5cbfSDavid du Colombier static Ints7 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 };
158480ee5cbfSDavid du Colombier static Ints7 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 };
15859a747e4fSDavid du Colombier static Ints7 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 };
15861075affeSDavid du Colombier static Ints7 oid_md5 ={6, 1, 2, 840, 113549, 2, 5, 0 };
158780ee5cbfSDavid du Colombier static Ints *alg_oid_tab[NUMALGS+1] = {
158880ee5cbfSDavid du Colombier 	(Ints*)&oid_rsaEncryption,
158980ee5cbfSDavid du Colombier 	(Ints*)&oid_md2WithRSAEncryption,
159080ee5cbfSDavid du Colombier 	(Ints*)&oid_md4WithRSAEncryption,
159180ee5cbfSDavid du Colombier 	(Ints*)&oid_md5WithRSAEncryption,
15929a747e4fSDavid du Colombier 	(Ints*)&oid_sha1WithRSAEncryption,
15931075affeSDavid du Colombier 	(Ints*)&oid_md5,
159480ee5cbfSDavid du Colombier 	nil
159580ee5cbfSDavid du Colombier };
15961075affeSDavid du Colombier static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, md5, nil };
159780ee5cbfSDavid du Colombier 
159880ee5cbfSDavid du Colombier static void
159980ee5cbfSDavid du Colombier freecert(CertX509* c)
160080ee5cbfSDavid du Colombier {
160180ee5cbfSDavid du Colombier 	if (!c) return;
160280ee5cbfSDavid du Colombier 	if(c->issuer != nil)
160380ee5cbfSDavid du Colombier 		free(c->issuer);
160480ee5cbfSDavid du Colombier 	if(c->validity_start != nil)
160580ee5cbfSDavid du Colombier 		free(c->validity_start);
160680ee5cbfSDavid du Colombier 	if(c->validity_end != nil)
160780ee5cbfSDavid du Colombier 		free(c->validity_end);
160880ee5cbfSDavid du Colombier 	if(c->subject != nil)
160980ee5cbfSDavid du Colombier 		free(c->subject);
161080ee5cbfSDavid du Colombier 	freebytes(c->publickey);
161180ee5cbfSDavid du Colombier 	freebytes(c->signature);
161280ee5cbfSDavid du Colombier }
161380ee5cbfSDavid du Colombier 
161480ee5cbfSDavid du Colombier /*
161580ee5cbfSDavid du Colombier  * Parse the Name ASN1 type.
161680ee5cbfSDavid du Colombier  * The sequence of RelativeDistinguishedName's gives a sort of pathname,
161780ee5cbfSDavid du Colombier  * from most general to most specific.  Each element of the path can be
161880ee5cbfSDavid du Colombier  * one or more (but usually just one) attribute-value pair, such as
161980ee5cbfSDavid du Colombier  * countryName="US".
162080ee5cbfSDavid du Colombier  * We'll just form a "postal-style" address string by concatenating the elements
162180ee5cbfSDavid du Colombier  * from most specific to least specific, separated by commas.
162280ee5cbfSDavid du Colombier  * Return name-as-string (which must be freed by caller).
162380ee5cbfSDavid du Colombier  */
162480ee5cbfSDavid du Colombier static char*
162580ee5cbfSDavid du Colombier parse_name(Elem* e)
162680ee5cbfSDavid du Colombier {
162780ee5cbfSDavid du Colombier 	Elist* el;
162880ee5cbfSDavid du Colombier 	Elem* es;
162980ee5cbfSDavid du Colombier 	Elist* esetl;
163080ee5cbfSDavid du Colombier 	Elem* eat;
163180ee5cbfSDavid du Colombier 	Elist* eatl;
163280ee5cbfSDavid du Colombier 	char* s;
163380ee5cbfSDavid du Colombier 	enum { MAXPARTS = 100 };
163480ee5cbfSDavid du Colombier 	char* parts[MAXPARTS];
163580ee5cbfSDavid du Colombier 	int i;
163680ee5cbfSDavid du Colombier 	int plen;
163780ee5cbfSDavid du Colombier 	char* ans = nil;
163880ee5cbfSDavid du Colombier 
163980ee5cbfSDavid du Colombier 	if(!is_seq(e, &el))
164080ee5cbfSDavid du Colombier 		goto errret;
164180ee5cbfSDavid du Colombier 	i = 0;
164280ee5cbfSDavid du Colombier 	plen = 0;
164380ee5cbfSDavid du Colombier 	while(el != nil) {
164480ee5cbfSDavid du Colombier 		es = &el->hd;
164580ee5cbfSDavid du Colombier 		if(!is_set(es, &esetl))
164680ee5cbfSDavid du Colombier 			goto errret;
164780ee5cbfSDavid du Colombier 		while(esetl != nil) {
164880ee5cbfSDavid du Colombier 			eat = &esetl->hd;
164980ee5cbfSDavid du Colombier 			if(!is_seq(eat, &eatl) || elistlen(eatl) != 2)
165080ee5cbfSDavid du Colombier 				goto errret;
16513ff48bf5SDavid du Colombier 			if(!is_string(&eatl->tl->hd, &s) || i>=MAXPARTS)
165280ee5cbfSDavid du Colombier 				goto errret;
165380ee5cbfSDavid du Colombier 			parts[i++] = s;
165480ee5cbfSDavid du Colombier 			plen += strlen(s) + 2;		/* room for ", " after */
165580ee5cbfSDavid du Colombier 			esetl = esetl->tl;
165680ee5cbfSDavid du Colombier 		}
165780ee5cbfSDavid du Colombier 		el = el->tl;
165880ee5cbfSDavid du Colombier 	}
165980ee5cbfSDavid du Colombier 	if(i > 0) {
1660d9306527SDavid du Colombier 		ans = (char*)emalloc(plen);
166180ee5cbfSDavid du Colombier 		*ans = '\0';
166280ee5cbfSDavid du Colombier 		while(--i >= 0) {
166380ee5cbfSDavid du Colombier 			s = parts[i];
166480ee5cbfSDavid du Colombier 			strcat(ans, s);
166580ee5cbfSDavid du Colombier 			if(i > 0)
166680ee5cbfSDavid du Colombier 				strcat(ans, ", ");
166780ee5cbfSDavid du Colombier 		}
166880ee5cbfSDavid du Colombier 	}
166980ee5cbfSDavid du Colombier 
167080ee5cbfSDavid du Colombier errret:
167180ee5cbfSDavid du Colombier 	return ans;
167280ee5cbfSDavid du Colombier }
167380ee5cbfSDavid du Colombier 
167480ee5cbfSDavid du Colombier /*
167580ee5cbfSDavid du Colombier  * Parse an AlgorithmIdentifer ASN1 type.
167680ee5cbfSDavid du Colombier  * Look up the oid in oid_tab and return one of OID_rsaEncryption, etc..,
167780ee5cbfSDavid du Colombier  * or -1 if not found.
167880ee5cbfSDavid du Colombier  * For now, ignore parameters, since none of our algorithms need them.
167980ee5cbfSDavid du Colombier  */
168080ee5cbfSDavid du Colombier static int
168180ee5cbfSDavid du Colombier parse_alg(Elem* e)
168280ee5cbfSDavid du Colombier {
168380ee5cbfSDavid du Colombier 	Elist* el;
168480ee5cbfSDavid du Colombier 	Ints* oid;
168580ee5cbfSDavid du Colombier 
168680ee5cbfSDavid du Colombier 	if(!is_seq(e, &el) || el == nil || !is_oid(&el->hd, &oid))
168780ee5cbfSDavid du Colombier 		return -1;
168880ee5cbfSDavid du Colombier 	return oid_lookup(oid, alg_oid_tab);
168980ee5cbfSDavid du Colombier }
169080ee5cbfSDavid du Colombier 
169180ee5cbfSDavid du Colombier static CertX509*
169280ee5cbfSDavid du Colombier decode_cert(Bytes* a)
169380ee5cbfSDavid du Colombier {
169480ee5cbfSDavid du Colombier 	int ok = 0;
169580ee5cbfSDavid du Colombier 	int n;
169680ee5cbfSDavid du Colombier 	CertX509* c = nil;
169780ee5cbfSDavid du Colombier 	Elem  ecert;
169880ee5cbfSDavid du Colombier 	Elem* ecertinfo;
169980ee5cbfSDavid du Colombier 	Elem* esigalg;
170080ee5cbfSDavid du Colombier 	Elem* esig;
170180ee5cbfSDavid du Colombier 	Elem* eserial;
170280ee5cbfSDavid du Colombier 	Elem* eissuer;
170380ee5cbfSDavid du Colombier 	Elem* evalidity;
170480ee5cbfSDavid du Colombier 	Elem* esubj;
170580ee5cbfSDavid du Colombier 	Elem* epubkey;
170680ee5cbfSDavid du Colombier 	Elist* el;
170780ee5cbfSDavid du Colombier 	Elist* elcert = nil;
170880ee5cbfSDavid du Colombier 	Elist* elcertinfo = nil;
170980ee5cbfSDavid du Colombier 	Elist* elvalidity = nil;
171080ee5cbfSDavid du Colombier 	Elist* elpubkey = nil;
171180ee5cbfSDavid du Colombier 	Bits* bits = nil;
171280ee5cbfSDavid du Colombier 	Bytes* b;
171380ee5cbfSDavid du Colombier 	Elem* e;
171480ee5cbfSDavid du Colombier 
171580ee5cbfSDavid du Colombier 	if(decode(a->data, a->len, &ecert) != ASN_OK)
171680ee5cbfSDavid du Colombier 		goto errret;
171780ee5cbfSDavid du Colombier 
1718d9306527SDavid du Colombier 	c = (CertX509*)emalloc(sizeof(CertX509));
171980ee5cbfSDavid du Colombier 	c->serial = -1;
172080ee5cbfSDavid du Colombier 	c->issuer = nil;
172180ee5cbfSDavid du Colombier 	c->validity_start = nil;
172280ee5cbfSDavid du Colombier 	c->validity_end = nil;
172380ee5cbfSDavid du Colombier 	c->subject = nil;
172480ee5cbfSDavid du Colombier 	c->publickey_alg = -1;
172580ee5cbfSDavid du Colombier 	c->publickey = nil;
172680ee5cbfSDavid du Colombier 	c->signature_alg = -1;
172780ee5cbfSDavid du Colombier 	c->signature = nil;
172880ee5cbfSDavid du Colombier 
172980ee5cbfSDavid du Colombier 	/* Certificate */
173080ee5cbfSDavid du Colombier  	if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
173180ee5cbfSDavid du Colombier 		goto errret;
173280ee5cbfSDavid du Colombier  	ecertinfo = &elcert->hd;
173380ee5cbfSDavid du Colombier  	el = elcert->tl;
173480ee5cbfSDavid du Colombier  	esigalg = &el->hd;
17353ff48bf5SDavid du Colombier 	c->signature_alg = parse_alg(esigalg);
173680ee5cbfSDavid du Colombier  	el = el->tl;
173780ee5cbfSDavid du Colombier  	esig = &el->hd;
173880ee5cbfSDavid du Colombier 
173980ee5cbfSDavid du Colombier 	/* Certificate Info */
174080ee5cbfSDavid du Colombier 	if(!is_seq(ecertinfo, &elcertinfo))
174180ee5cbfSDavid du Colombier 		goto errret;
174280ee5cbfSDavid du Colombier 	n = elistlen(elcertinfo);
174380ee5cbfSDavid du Colombier   	if(n < 6)
174480ee5cbfSDavid du Colombier 		goto errret;
174580ee5cbfSDavid du Colombier 	eserial =&elcertinfo->hd;
174680ee5cbfSDavid du Colombier  	el = elcertinfo->tl;
174780ee5cbfSDavid du Colombier  	/* check for optional version, marked by explicit context tag 0 */
174880ee5cbfSDavid du Colombier 	if(eserial->tag.class == Context && eserial->tag.num == 0) {
174980ee5cbfSDavid du Colombier  		eserial = &el->hd;
175080ee5cbfSDavid du Colombier  		if(n < 7)
175180ee5cbfSDavid du Colombier  			goto errret;
175280ee5cbfSDavid du Colombier  		el = el->tl;
175380ee5cbfSDavid du Colombier  	}
175480ee5cbfSDavid du Colombier 
17553ff48bf5SDavid du Colombier 	if(parse_alg(&el->hd) != c->signature_alg)
17563ff48bf5SDavid du Colombier 		goto errret;
175780ee5cbfSDavid du Colombier  	el = el->tl;
175880ee5cbfSDavid du Colombier  	eissuer = &el->hd;
175980ee5cbfSDavid du Colombier  	el = el->tl;
176080ee5cbfSDavid du Colombier  	evalidity = &el->hd;
176180ee5cbfSDavid du Colombier  	el = el->tl;
176280ee5cbfSDavid du Colombier  	esubj = &el->hd;
176380ee5cbfSDavid du Colombier  	el = el->tl;
176480ee5cbfSDavid du Colombier  	epubkey = &el->hd;
176580ee5cbfSDavid du Colombier  	if(!is_int(eserial, &c->serial)) {
176680ee5cbfSDavid du Colombier 		if(!is_bigint(eserial, &b))
176780ee5cbfSDavid du Colombier 			goto errret;
176880ee5cbfSDavid du Colombier 		c->serial = -1;	/* else we have to change cert struct */
176980ee5cbfSDavid du Colombier   	}
177080ee5cbfSDavid du Colombier 	c->issuer = parse_name(eissuer);
177180ee5cbfSDavid du Colombier 	if(c->issuer == nil)
177280ee5cbfSDavid du Colombier 		goto errret;
177380ee5cbfSDavid du Colombier 	/* Validity */
177480ee5cbfSDavid du Colombier   	if(!is_seq(evalidity, &elvalidity))
177580ee5cbfSDavid du Colombier 		goto errret;
177680ee5cbfSDavid du Colombier 	if(elistlen(elvalidity) != 2)
177780ee5cbfSDavid du Colombier 		goto errret;
177880ee5cbfSDavid du Colombier 	e = &elvalidity->hd;
177980ee5cbfSDavid du Colombier 	if(!is_time(e, &c->validity_start))
178080ee5cbfSDavid du Colombier 		goto errret;
178180ee5cbfSDavid du Colombier 	e->val.u.stringval = nil;	/* string ownership transfer */
178280ee5cbfSDavid du Colombier 	e = &elvalidity->tl->hd;
178380ee5cbfSDavid du Colombier  	if(!is_time(e, &c->validity_end))
178480ee5cbfSDavid du Colombier 		goto errret;
178580ee5cbfSDavid du Colombier 	e->val.u.stringval = nil;	/* string ownership transfer */
178680ee5cbfSDavid du Colombier 
178780ee5cbfSDavid du Colombier 	/* resume CertificateInfo */
178880ee5cbfSDavid du Colombier  	c->subject = parse_name(esubj);
178980ee5cbfSDavid du Colombier 	if(c->subject == nil)
179080ee5cbfSDavid du Colombier 		goto errret;
179180ee5cbfSDavid du Colombier 
179280ee5cbfSDavid du Colombier 	/* SubjectPublicKeyInfo */
179380ee5cbfSDavid du Colombier  	if(!is_seq(epubkey, &elpubkey))
179480ee5cbfSDavid du Colombier 		goto errret;
179580ee5cbfSDavid du Colombier 	if(elistlen(elpubkey) != 2)
179680ee5cbfSDavid du Colombier 		goto errret;
179780ee5cbfSDavid du Colombier 
179880ee5cbfSDavid du Colombier 	c->publickey_alg = parse_alg(&elpubkey->hd);
179980ee5cbfSDavid du Colombier 	if(c->publickey_alg < 0)
180080ee5cbfSDavid du Colombier 		goto errret;
180180ee5cbfSDavid du Colombier   	if(!is_bitstring(&elpubkey->tl->hd, &bits))
180280ee5cbfSDavid du Colombier 		goto errret;
180380ee5cbfSDavid du Colombier 	if(bits->unusedbits != 0)
180480ee5cbfSDavid du Colombier 		goto errret;
180580ee5cbfSDavid du Colombier  	c->publickey = makebytes(bits->data, bits->len);
180680ee5cbfSDavid du Colombier 
180780ee5cbfSDavid du Colombier 	/*resume Certificate */
180880ee5cbfSDavid du Colombier 	if(c->signature_alg < 0)
180980ee5cbfSDavid du Colombier 		goto errret;
181080ee5cbfSDavid du Colombier  	if(!is_bitstring(esig, &bits))
181180ee5cbfSDavid du Colombier 		goto errret;
181280ee5cbfSDavid du Colombier  	c->signature = makebytes(bits->data, bits->len);
181380ee5cbfSDavid du Colombier 	ok = 1;
181480ee5cbfSDavid du Colombier 
181580ee5cbfSDavid du Colombier errret:
181680ee5cbfSDavid du Colombier 	freevalfields(&ecert.val);	/* recurses through lists, too */
181780ee5cbfSDavid du Colombier 	if(!ok){
181880ee5cbfSDavid du Colombier 		freecert(c);
181980ee5cbfSDavid du Colombier 		c = nil;
182080ee5cbfSDavid du Colombier 	}
182180ee5cbfSDavid du Colombier 	return c;
182280ee5cbfSDavid du Colombier }
182380ee5cbfSDavid du Colombier 
18249a747e4fSDavid du Colombier /*
18259a747e4fSDavid du Colombier  *	RSAPublickKey :: SEQUENCE {
18269a747e4fSDavid du Colombier  *		modulus INTEGER,
18279a747e4fSDavid du Colombier  *		publicExponent INTEGER
18289a747e4fSDavid du Colombier  *	}
18299a747e4fSDavid du Colombier  */
183080ee5cbfSDavid du Colombier static RSApub*
183180ee5cbfSDavid du Colombier decode_rsapubkey(Bytes* a)
183280ee5cbfSDavid du Colombier {
183380ee5cbfSDavid du Colombier 	Elem e;
183480ee5cbfSDavid du Colombier 	Elist *el;
18359a747e4fSDavid du Colombier 	mpint *mp;
18369a747e4fSDavid du Colombier 	RSApub* key;
183780ee5cbfSDavid du Colombier 
18389a747e4fSDavid du Colombier 	key = rsapuballoc();
183980ee5cbfSDavid du Colombier 	if(decode(a->data, a->len, &e) != ASN_OK)
184080ee5cbfSDavid du Colombier 		goto errret;
184180ee5cbfSDavid du Colombier 	if(!is_seq(&e, &el) || elistlen(el) != 2)
184280ee5cbfSDavid du Colombier 		goto errret;
18439a747e4fSDavid du Colombier 
18449a747e4fSDavid du Colombier 	key->n = mp = asn1mpint(&el->hd);
18459a747e4fSDavid du Colombier 	if(mp == nil)
184680ee5cbfSDavid du Colombier 		goto errret;
18479a747e4fSDavid du Colombier 
18489a747e4fSDavid du Colombier 	el = el->tl;
18499a747e4fSDavid du Colombier 	key->ek = mp = asn1mpint(&el->hd);
18509a747e4fSDavid du Colombier 	if(mp == nil)
185180ee5cbfSDavid du Colombier 		goto errret;
18529a747e4fSDavid du Colombier 	return key;
185380ee5cbfSDavid du Colombier errret:
18549a747e4fSDavid du Colombier 	rsapubfree(key);
185580ee5cbfSDavid du Colombier 	return nil;
185680ee5cbfSDavid du Colombier }
185780ee5cbfSDavid du Colombier 
18589a747e4fSDavid du Colombier /*
18599a747e4fSDavid du Colombier  *	RSAPrivateKey ::= SEQUENCE {
18609a747e4fSDavid du Colombier  *		version Version,
18619a747e4fSDavid du Colombier  *		modulus INTEGER, -- n
18629a747e4fSDavid du Colombier  *		publicExponent INTEGER, -- e
18639a747e4fSDavid du Colombier  *		privateExponent INTEGER, -- d
18649a747e4fSDavid du Colombier  *		prime1 INTEGER, -- p
18659a747e4fSDavid du Colombier  *		prime2 INTEGER, -- q
18669a747e4fSDavid du Colombier  *		exponent1 INTEGER, -- d mod (p-1)
18679a747e4fSDavid du Colombier  *		exponent2 INTEGER, -- d mod (q-1)
18689a747e4fSDavid du Colombier  *		coefficient INTEGER -- (inverse of q) mod p }
18699a747e4fSDavid du Colombier  */
18709a747e4fSDavid du Colombier static RSApriv*
18719a747e4fSDavid du Colombier decode_rsaprivkey(Bytes* a)
18729a747e4fSDavid du Colombier {
18739a747e4fSDavid du Colombier 	int version;
18749a747e4fSDavid du Colombier 	Elem e;
18759a747e4fSDavid du Colombier 	Elist *el;
18769a747e4fSDavid du Colombier 	mpint *mp;
18779a747e4fSDavid du Colombier 	RSApriv* key;
18789a747e4fSDavid du Colombier 
18799a747e4fSDavid du Colombier 	key = rsaprivalloc();
18809a747e4fSDavid du Colombier 	if(decode(a->data, a->len, &e) != ASN_OK)
18819a747e4fSDavid du Colombier 		goto errret;
18829a747e4fSDavid du Colombier 	if(!is_seq(&e, &el) || elistlen(el) != 9)
18839a747e4fSDavid du Colombier 		goto errret;
18849a747e4fSDavid du Colombier 	if(!is_int(&el->hd, &version) || version != 0)
18859a747e4fSDavid du Colombier 		goto errret;
18869a747e4fSDavid du Colombier 
18879a747e4fSDavid du Colombier 	el = el->tl;
18889a747e4fSDavid du Colombier 	key->pub.n = mp = asn1mpint(&el->hd);
18899a747e4fSDavid du Colombier 	if(mp == nil)
18909a747e4fSDavid du Colombier 		goto errret;
18919a747e4fSDavid du Colombier 
18929a747e4fSDavid du Colombier 	el = el->tl;
18939a747e4fSDavid du Colombier 	key->pub.ek = mp = asn1mpint(&el->hd);
18949a747e4fSDavid du Colombier 	if(mp == nil)
18959a747e4fSDavid du Colombier 		goto errret;
18969a747e4fSDavid du Colombier 
18979a747e4fSDavid du Colombier 	el = el->tl;
18989a747e4fSDavid du Colombier 	key->dk = mp = asn1mpint(&el->hd);
18999a747e4fSDavid du Colombier 	if(mp == nil)
19009a747e4fSDavid du Colombier 		goto errret;
19019a747e4fSDavid du Colombier 
19029a747e4fSDavid du Colombier 	el = el->tl;
19039a747e4fSDavid du Colombier 	key->q = mp = asn1mpint(&el->hd);
19049a747e4fSDavid du Colombier 	if(mp == nil)
19059a747e4fSDavid du Colombier 		goto errret;
19069a747e4fSDavid du Colombier 
19079a747e4fSDavid du Colombier 	el = el->tl;
19089a747e4fSDavid du Colombier 	key->p = mp = asn1mpint(&el->hd);
19099a747e4fSDavid du Colombier 	if(mp == nil)
19109a747e4fSDavid du Colombier 		goto errret;
19119a747e4fSDavid du Colombier 
19129a747e4fSDavid du Colombier 	el = el->tl;
19139a747e4fSDavid du Colombier 	key->kq = mp = asn1mpint(&el->hd);
19149a747e4fSDavid du Colombier 	if(mp == nil)
19159a747e4fSDavid du Colombier 		goto errret;
19169a747e4fSDavid du Colombier 
19179a747e4fSDavid du Colombier 	el = el->tl;
19189a747e4fSDavid du Colombier 	key->kp = mp = asn1mpint(&el->hd);
19199a747e4fSDavid du Colombier 	if(mp == nil)
19209a747e4fSDavid du Colombier 		goto errret;
19219a747e4fSDavid du Colombier 
19229a747e4fSDavid du Colombier 	el = el->tl;
19239a747e4fSDavid du Colombier 	key->c2 = mp = asn1mpint(&el->hd);
19249a747e4fSDavid du Colombier 	if(mp == nil)
19259a747e4fSDavid du Colombier 		goto errret;
19269a747e4fSDavid du Colombier 
19279a747e4fSDavid du Colombier 	return key;
19289a747e4fSDavid du Colombier errret:
19299a747e4fSDavid du Colombier 	rsaprivfree(key);
19309a747e4fSDavid du Colombier 	return nil;
19319a747e4fSDavid du Colombier }
19329a747e4fSDavid du Colombier 
19339a747e4fSDavid du Colombier static mpint*
19349a747e4fSDavid du Colombier asn1mpint(Elem *e)
19359a747e4fSDavid du Colombier {
19369a747e4fSDavid du Colombier 	Bytes *b;
19379a747e4fSDavid du Colombier 	mpint *mp;
19389a747e4fSDavid du Colombier 	int v;
19399a747e4fSDavid du Colombier 
19409a747e4fSDavid du Colombier 	if(is_int(e, &v))
19419a747e4fSDavid du Colombier 		return itomp(v, nil);
19429a747e4fSDavid du Colombier 	if(is_bigint(e, &b)) {
19439a747e4fSDavid du Colombier 		mp = betomp(b->data, b->len, nil);
19449a747e4fSDavid du Colombier 		freebytes(b);
19459a747e4fSDavid du Colombier 		return mp;
19469a747e4fSDavid du Colombier 	}
19479a747e4fSDavid du Colombier 	return nil;
19489a747e4fSDavid du Colombier }
19499a747e4fSDavid du Colombier 
1950d9306527SDavid du Colombier static mpint*
1951d9306527SDavid du Colombier pkcs1pad(Bytes *b, mpint *modulus)
1952d9306527SDavid du Colombier {
1953d9306527SDavid du Colombier 	int n = (mpsignif(modulus)+7)/8;
1954d9306527SDavid du Colombier 	int pm1, i;
1955d9306527SDavid du Colombier 	uchar *p;
1956d9306527SDavid du Colombier 	mpint *mp;
1957d9306527SDavid du Colombier 
1958d9306527SDavid du Colombier 	pm1 = n - 1 - b->len;
1959d9306527SDavid du Colombier 	p = (uchar*)emalloc(n);
1960d9306527SDavid du Colombier 	p[0] = 0;
1961d9306527SDavid du Colombier 	p[1] = 1;
1962d9306527SDavid du Colombier 	for(i = 2; i < pm1; i++)
1963d9306527SDavid du Colombier 		p[i] = 0xFF;
1964d9306527SDavid du Colombier 	p[pm1] = 0;
1965d9306527SDavid du Colombier 	memcpy(&p[pm1+1], b->data, b->len);
1966d9306527SDavid du Colombier 	mp = betomp(p, n, nil);
1967d9306527SDavid du Colombier 	free(p);
1968d9306527SDavid du Colombier 	return mp;
1969d9306527SDavid du Colombier }
1970d9306527SDavid du Colombier 
19719a747e4fSDavid du Colombier RSApriv*
19729a747e4fSDavid du Colombier asn1toRSApriv(uchar *kd, int kn)
19739a747e4fSDavid du Colombier {
19749a747e4fSDavid du Colombier 	Bytes *b;
19759a747e4fSDavid du Colombier 	RSApriv *key;
19769a747e4fSDavid du Colombier 
19779a747e4fSDavid du Colombier 	b = makebytes(kd, kn);
19789a747e4fSDavid du Colombier 	key = decode_rsaprivkey(b);
19799a747e4fSDavid du Colombier 	freebytes(b);
19809a747e4fSDavid du Colombier 	return key;
19819a747e4fSDavid du Colombier }
198280ee5cbfSDavid du Colombier 
19833ff48bf5SDavid du Colombier /*
19843ff48bf5SDavid du Colombier  * digest(CertificateInfo)
19853ff48bf5SDavid du Colombier  * Our ASN.1 library doesn't return pointers into the original
19863ff48bf5SDavid du Colombier  * data array, so we need to do a little hand decoding.
19873ff48bf5SDavid du Colombier  */
19883ff48bf5SDavid du Colombier static void
19893ff48bf5SDavid du Colombier digest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest)
19903ff48bf5SDavid du Colombier {
19913ff48bf5SDavid du Colombier 	uchar *info, *p, *pend;
19923ff48bf5SDavid du Colombier 	ulong infolen;
19933ff48bf5SDavid du Colombier 	int isconstr, length;
19943ff48bf5SDavid du Colombier 	Tag tag;
19953ff48bf5SDavid du Colombier 	Elem elem;
19963ff48bf5SDavid du Colombier 
19973ff48bf5SDavid du Colombier 	p = cert->data;
19983ff48bf5SDavid du Colombier 	pend = cert->data + cert->len;
19993ff48bf5SDavid du Colombier 	if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK ||
20003ff48bf5SDavid du Colombier 	   tag.class != Universal || tag.num != SEQUENCE ||
20013ff48bf5SDavid du Colombier 	   length_decode(&p, pend, &length) != ASN_OK ||
2002*39734e7eSDavid du Colombier 	   p+length > pend ||
2003*39734e7eSDavid du Colombier 	   p+length < p)
20043ff48bf5SDavid du Colombier 		return;
20053ff48bf5SDavid du Colombier 	info = p;
20063ff48bf5SDavid du Colombier 	if(ber_decode(&p, pend, &elem) != ASN_OK || elem.tag.num != SEQUENCE)
20073ff48bf5SDavid du Colombier 		return;
20083ff48bf5SDavid du Colombier 	infolen = p - info;
20093ff48bf5SDavid du Colombier 	(*digestfun)(info, infolen, digest, nil);
20103ff48bf5SDavid du Colombier }
20113ff48bf5SDavid du Colombier 
20123ff48bf5SDavid du Colombier static char*
20131075affeSDavid du Colombier verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg)
20143ff48bf5SDavid du Colombier {
20153ff48bf5SDavid du Colombier 	Elem e;
20163ff48bf5SDavid du Colombier 	Elist *el;
20173ff48bf5SDavid du Colombier 	Bytes *digest;
20183ff48bf5SDavid du Colombier 	uchar *pkcs1buf, *buf;
20193ff48bf5SDavid du Colombier 	int buflen;
20203ff48bf5SDavid du Colombier 	mpint *pkcs1;
2021*39734e7eSDavid du Colombier 	int nlen;
2022*39734e7eSDavid du Colombier 
2023*39734e7eSDavid du Colombier 	/* one less than the byte length of the modulus */
2024*39734e7eSDavid du Colombier 	nlen = (mpsignif(pk->n)-1)/8;
20253ff48bf5SDavid du Colombier 
20263ff48bf5SDavid du Colombier 	/* see 9.2.1 of rfc2437 */
20273ff48bf5SDavid du Colombier 	pkcs1 = betomp(signature->data, signature->len, nil);
20283ff48bf5SDavid du Colombier 	mpexp(pkcs1, pk->ek, pk->n, pkcs1);
2029*39734e7eSDavid du Colombier 	pkcs1buf = nil;
20303ff48bf5SDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &pkcs1buf);
20313ff48bf5SDavid du Colombier 	buf = pkcs1buf;
2032*39734e7eSDavid du Colombier 	if(buflen != nlen || buf[0] != 1)
20333ff48bf5SDavid du Colombier 		return "expected 1";
20343ff48bf5SDavid du Colombier 	buf++;
20353ff48bf5SDavid du Colombier 	while(buf[0] == 0xff)
20363ff48bf5SDavid du Colombier 		buf++;
20373ff48bf5SDavid du Colombier 	if(buf[0] != 0)
20383ff48bf5SDavid du Colombier 		return "expected 0";
20393ff48bf5SDavid du Colombier 	buf++;
20403ff48bf5SDavid du Colombier 	buflen -= buf-pkcs1buf;
20413ff48bf5SDavid du Colombier 	if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 ||
20423ff48bf5SDavid du Colombier 			!is_octetstring(&el->tl->hd, &digest))
20433ff48bf5SDavid du Colombier 		return "signature parse error";
20441075affeSDavid du Colombier 	*psigalg = &el->hd;
20453ff48bf5SDavid du Colombier 	if(memcmp(digest->data, edigest, digest->len) == 0)
20463ff48bf5SDavid du Colombier 		return nil;
20473ff48bf5SDavid du Colombier 	return "digests did not match";
20483ff48bf5SDavid du Colombier }
20493ff48bf5SDavid du Colombier 
205080ee5cbfSDavid du Colombier RSApub*
205180ee5cbfSDavid du Colombier X509toRSApub(uchar *cert, int ncert, char *name, int nname)
205280ee5cbfSDavid du Colombier {
205380ee5cbfSDavid du Colombier 	char *e;
205480ee5cbfSDavid du Colombier 	Bytes *b;
205580ee5cbfSDavid du Colombier 	CertX509 *c;
205680ee5cbfSDavid du Colombier 	RSApub *pk;
205780ee5cbfSDavid du Colombier 
205880ee5cbfSDavid du Colombier 	b = makebytes(cert, ncert);
205980ee5cbfSDavid du Colombier 	c = decode_cert(b);
206080ee5cbfSDavid du Colombier 	freebytes(b);
206180ee5cbfSDavid du Colombier 	if(c == nil)
206280ee5cbfSDavid du Colombier 		return nil;
206380ee5cbfSDavid du Colombier 	if(name != nil && c->subject != nil){
206480ee5cbfSDavid du Colombier 		e = strchr(c->subject, ',');
206580ee5cbfSDavid du Colombier 		if(e != nil)
206680ee5cbfSDavid du Colombier 			*e = 0;  // take just CN part of Distinguished Name
206780ee5cbfSDavid du Colombier 		strncpy(name, c->subject, nname);
206880ee5cbfSDavid du Colombier 	}
206980ee5cbfSDavid du Colombier 	pk = decode_rsapubkey(c->publickey);
207080ee5cbfSDavid du Colombier 	freecert(c);
207180ee5cbfSDavid du Colombier 	return pk;
207280ee5cbfSDavid du Colombier }
20733ff48bf5SDavid du Colombier 
20743ff48bf5SDavid du Colombier char*
20753ff48bf5SDavid du Colombier X509verify(uchar *cert, int ncert, RSApub *pk)
20763ff48bf5SDavid du Colombier {
20773ff48bf5SDavid du Colombier 	char *e;
20783ff48bf5SDavid du Colombier 	Bytes *b;
20793ff48bf5SDavid du Colombier 	CertX509 *c;
20803ff48bf5SDavid du Colombier 	uchar digest[SHA1dlen];
20811075affeSDavid du Colombier 	Elem *sigalg;
20823ff48bf5SDavid du Colombier 
20833ff48bf5SDavid du Colombier 	b = makebytes(cert, ncert);
20843ff48bf5SDavid du Colombier 	c = decode_cert(b);
20853ff48bf5SDavid du Colombier 	if(c != nil)
20863ff48bf5SDavid du Colombier 		digest_certinfo(b, digestalg[c->signature_alg], digest);
20873ff48bf5SDavid du Colombier 	freebytes(b);
20883ff48bf5SDavid du Colombier 	if(c == nil)
20891075affeSDavid du Colombier 		return "cannot decode cert";
20901075affeSDavid du Colombier 	e = verify_signature(c->signature, pk, digest, &sigalg);
20913ff48bf5SDavid du Colombier 	freecert(c);
20923ff48bf5SDavid du Colombier 	return e;
20933ff48bf5SDavid du Colombier }
2094d9306527SDavid du Colombier 
2095d9306527SDavid du Colombier /* ------- Elem constructors ---------- */
2096d9306527SDavid du Colombier static Elem
2097d9306527SDavid du Colombier Null(void)
2098d9306527SDavid du Colombier {
2099d9306527SDavid du Colombier 	Elem e;
2100d9306527SDavid du Colombier 
2101d9306527SDavid du Colombier 	e.tag.class = Universal;
2102d9306527SDavid du Colombier 	e.tag.num = NULLTAG;
2103d9306527SDavid du Colombier 	e.val.tag = VNull;
2104d9306527SDavid du Colombier 	return e;
2105d9306527SDavid du Colombier }
2106d9306527SDavid du Colombier 
2107d9306527SDavid du Colombier static Elem
2108d9306527SDavid du Colombier mkint(int j)
2109d9306527SDavid du Colombier {
2110d9306527SDavid du Colombier 	Elem e;
2111d9306527SDavid du Colombier 
2112d9306527SDavid du Colombier 	e.tag.class = Universal;
2113d9306527SDavid du Colombier 	e.tag.num = INTEGER;
2114d9306527SDavid du Colombier 	e.val.tag = VInt;
2115d9306527SDavid du Colombier 	e.val.u.intval = j;
2116d9306527SDavid du Colombier 	return e;
2117d9306527SDavid du Colombier }
2118d9306527SDavid du Colombier 
2119d9306527SDavid du Colombier static Elem
2120d9306527SDavid du Colombier mkbigint(mpint *p)
2121d9306527SDavid du Colombier {
2122d9306527SDavid du Colombier 	Elem e;
2123d9306527SDavid du Colombier 	uchar *buf;
2124d9306527SDavid du Colombier 	int buflen;
2125d9306527SDavid du Colombier 
2126d9306527SDavid du Colombier 	e.tag.class = Universal;
2127d9306527SDavid du Colombier 	e.tag.num = INTEGER;
2128d9306527SDavid du Colombier 	e.val.tag = VBigInt;
2129d9306527SDavid du Colombier 	buflen = mptobe(p, nil, 0, &buf);
2130d9306527SDavid du Colombier 	e.val.u.bigintval = makebytes(buf, buflen);
2131d9306527SDavid du Colombier 	free(buf);
2132d9306527SDavid du Colombier 	return e;
2133d9306527SDavid du Colombier }
2134d9306527SDavid du Colombier 
2135d9306527SDavid du Colombier static Elem
2136d9306527SDavid du Colombier mkstring(char *s)
2137d9306527SDavid du Colombier {
2138d9306527SDavid du Colombier 	Elem e;
2139d9306527SDavid du Colombier 
2140d9306527SDavid du Colombier 	e.tag.class = Universal;
2141d9306527SDavid du Colombier 	e.tag.num = IA5String;
2142d9306527SDavid du Colombier 	e.val.tag = VString;
2143d9306527SDavid du Colombier 	e.val.u.stringval = estrdup(s);
2144d9306527SDavid du Colombier 	return e;
2145d9306527SDavid du Colombier }
2146d9306527SDavid du Colombier 
2147d9306527SDavid du Colombier static Elem
2148d9306527SDavid du Colombier mkoctet(uchar *buf, int buflen)
2149d9306527SDavid du Colombier {
2150d9306527SDavid du Colombier 	Elem e;
2151d9306527SDavid du Colombier 
2152d9306527SDavid du Colombier 	e.tag.class = Universal;
2153d9306527SDavid du Colombier 	e.tag.num = OCTET_STRING;
2154d9306527SDavid du Colombier 	e.val.tag = VOctets;
2155d9306527SDavid du Colombier 	e.val.u.octetsval = makebytes(buf, buflen);
2156d9306527SDavid du Colombier 	return e;
2157d9306527SDavid du Colombier }
2158d9306527SDavid du Colombier 
2159d9306527SDavid du Colombier static Elem
2160d9306527SDavid du Colombier mkbits(uchar *buf, int buflen)
2161d9306527SDavid du Colombier {
2162d9306527SDavid du Colombier 	Elem e;
2163d9306527SDavid du Colombier 
2164d9306527SDavid du Colombier 	e.tag.class = Universal;
2165d9306527SDavid du Colombier 	e.tag.num = BIT_STRING;
2166d9306527SDavid du Colombier 	e.val.tag = VBitString;
2167d9306527SDavid du Colombier 	e.val.u.bitstringval = makebits(buf, buflen, 0);
2168d9306527SDavid du Colombier 	return e;
2169d9306527SDavid du Colombier }
2170d9306527SDavid du Colombier 
2171d9306527SDavid du Colombier static Elem
2172d9306527SDavid du Colombier mkutc(long t)
2173d9306527SDavid du Colombier {
2174d9306527SDavid du Colombier 	Elem e;
2175d9306527SDavid du Colombier 	char utc[50];
2176d9306527SDavid du Colombier 	Tm *tm = gmtime(t);
2177d9306527SDavid du Colombier 
2178d9306527SDavid du Colombier 	e.tag.class = Universal;
2179d9306527SDavid du Colombier 	e.tag.num = UTCTime;
2180d9306527SDavid du Colombier 	e.val.tag = VString;
2181d9306527SDavid du Colombier 	snprint(utc, 50, "%.2d%.2d%.2d%.2d%.2d%.2dZ",
2182d9306527SDavid du Colombier 		tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec);
2183d9306527SDavid du Colombier 	e.val.u.stringval = estrdup(utc);
2184d9306527SDavid du Colombier 	return e;
2185d9306527SDavid du Colombier }
2186d9306527SDavid du Colombier 
2187d9306527SDavid du Colombier static Elem
2188d9306527SDavid du Colombier mkoid(Ints *oid)
2189d9306527SDavid du Colombier {
2190d9306527SDavid du Colombier 	Elem e;
2191d9306527SDavid du Colombier 
2192d9306527SDavid du Colombier 	e.tag.class = Universal;
2193d9306527SDavid du Colombier 	e.tag.num = OBJECT_ID;
2194d9306527SDavid du Colombier 	e.val.tag = VObjId;
2195d9306527SDavid du Colombier 	e.val.u.objidval = makeints(oid->data, oid->len);
2196d9306527SDavid du Colombier 	return e;
2197d9306527SDavid du Colombier }
2198d9306527SDavid du Colombier 
2199d9306527SDavid du Colombier static Elem
2200d9306527SDavid du Colombier mkseq(Elist *el)
2201d9306527SDavid du Colombier {
2202d9306527SDavid du Colombier 	Elem e;
2203d9306527SDavid du Colombier 
2204d9306527SDavid du Colombier 	e.tag.class = Universal;
2205d9306527SDavid du Colombier 	e.tag.num = SEQUENCE;
2206d9306527SDavid du Colombier 	e.val.tag = VSeq;
2207d9306527SDavid du Colombier 	e.val.u.seqval = el;
2208d9306527SDavid du Colombier 	return e;
2209d9306527SDavid du Colombier }
2210d9306527SDavid du Colombier 
2211d9306527SDavid du Colombier static Elem
2212d9306527SDavid du Colombier mkset(Elist *el)
2213d9306527SDavid du Colombier {
2214d9306527SDavid du Colombier 	Elem e;
2215d9306527SDavid du Colombier 
2216d9306527SDavid du Colombier 	e.tag.class = Universal;
2217d9306527SDavid du Colombier 	e.tag.num = SETOF;
2218d9306527SDavid du Colombier 	e.val.tag = VSet;
2219d9306527SDavid du Colombier 	e.val.u.setval = el;
2220d9306527SDavid du Colombier 	return e;
2221d9306527SDavid du Colombier }
2222d9306527SDavid du Colombier 
2223d9306527SDavid du Colombier static Elem
2224d9306527SDavid du Colombier mkalg(int alg)
2225d9306527SDavid du Colombier {
2226d9306527SDavid du Colombier 	return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil)));
2227d9306527SDavid du Colombier }
2228d9306527SDavid du Colombier 
22291075affeSDavid du Colombier typedef struct Ints7pref {
2230d9306527SDavid du Colombier 	int		len;
22311075affeSDavid du Colombier 	int		data[7];
2232d9306527SDavid du Colombier 	char	prefix[4];
22331075affeSDavid du Colombier } Ints7pref;
22341075affeSDavid du Colombier Ints7pref DN_oid[] = {
22351075affeSDavid du Colombier 	{4, 2, 5, 4, 6, 0, 0, 0,  "C="},
22361075affeSDavid du Colombier 	{4, 2, 5, 4, 8, 0, 0, 0,  "ST="},
22371075affeSDavid du Colombier 	{4, 2, 5, 4, 7, 0, 0, 0,  "L="},
22381075affeSDavid du Colombier 	{4, 2, 5, 4, 10, 0, 0, 0, "O="},
22391075affeSDavid du Colombier 	{4, 2, 5, 4, 11, 0, 0, 0, "OU="},
22401075affeSDavid du Colombier 	{4, 2, 5, 4, 3, 0, 0, 0,  "CN="},
22411075affeSDavid du Colombier  	{7, 1,2,840,113549,1,9,1, "E="},
2242d9306527SDavid du Colombier };
2243d9306527SDavid du Colombier 
2244d9306527SDavid du Colombier static Elem
22451075affeSDavid du Colombier mkname(Ints7pref *oid, char *subj)
2246d9306527SDavid du Colombier {
2247d9306527SDavid du Colombier 	return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj), nil))), nil));
2248d9306527SDavid du Colombier }
2249d9306527SDavid du Colombier 
2250d9306527SDavid du Colombier static Elem
2251d9306527SDavid du Colombier mkDN(char *dn)
2252d9306527SDavid du Colombier {
2253d9306527SDavid du Colombier 	int i, j, nf;
2254d9306527SDavid du Colombier 	char *f[20], *prefix, *d2 = estrdup(dn);
2255d9306527SDavid du Colombier 	Elist* el = nil;
2256d9306527SDavid du Colombier 
2257d9306527SDavid du Colombier 	nf = tokenize(d2, f, nelem(f));
2258d9306527SDavid du Colombier 	for(i=nf-1; i>=0; i--){
2259d9306527SDavid du Colombier 		for(j=0; j<nelem(DN_oid); j++){
2260d9306527SDavid du Colombier 			prefix = DN_oid[j].prefix;
2261d9306527SDavid du Colombier 			if(strncmp(f[i],prefix,strlen(prefix))==0){
2262d9306527SDavid du Colombier 				el = mkel(mkname(&DN_oid[j],f[i]+strlen(prefix)), el);
2263d9306527SDavid du Colombier 				break;
2264d9306527SDavid du Colombier 			}
2265d9306527SDavid du Colombier 		}
2266d9306527SDavid du Colombier 	}
2267d9306527SDavid du Colombier 	free(d2);
2268d9306527SDavid du Colombier 	return mkseq(el);
2269d9306527SDavid du Colombier }
2270d9306527SDavid du Colombier 
2271d9306527SDavid du Colombier 
2272d9306527SDavid du Colombier uchar*
2273d9306527SDavid du Colombier X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
2274d9306527SDavid du Colombier {
2275d9306527SDavid du Colombier 	int serial = 0;
2276d9306527SDavid du Colombier 	uchar *cert = nil;
2277d9306527SDavid du Colombier 	RSApub *pk = rsaprivtopub(priv);
2278d9306527SDavid du Colombier 	Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
2279d9306527SDavid du Colombier 	Elem e, certinfo, issuer, subject, pubkey, validity, sig;
2280d9306527SDavid du Colombier 	uchar digest[MD5dlen], *buf;
2281d9306527SDavid du Colombier 	int buflen;
2282d9306527SDavid du Colombier 	mpint *pkcs1;
2283d9306527SDavid du Colombier 
2284d9306527SDavid du Colombier 	e.val.tag = VInt;  /* so freevalfields at errret is no-op */
2285d9306527SDavid du Colombier 	issuer = mkDN(subj);
2286d9306527SDavid du Colombier 	subject = mkDN(subj);
2287d9306527SDavid du Colombier 	pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
2288d9306527SDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
2289d9306527SDavid du Colombier 		goto errret;
2290d9306527SDavid du Colombier 	freevalfields(&pubkey.val);
2291d9306527SDavid du Colombier 	pubkey = mkseq(
2292d9306527SDavid du Colombier 		mkel(mkalg(ALG_rsaEncryption),
2293d9306527SDavid du Colombier 		mkel(mkbits(pkbytes->data, pkbytes->len),
2294d9306527SDavid du Colombier 		nil)));
2295d9306527SDavid du Colombier 	freebytes(pkbytes);
2296d9306527SDavid du Colombier 	validity = mkseq(
2297d9306527SDavid du Colombier 		mkel(mkutc(valid[0]),
2298d9306527SDavid du Colombier 		mkel(mkutc(valid[1]),
2299d9306527SDavid du Colombier 		nil)));
2300d9306527SDavid du Colombier 	certinfo = mkseq(
2301d9306527SDavid du Colombier 		mkel(mkint(serial),
2302d9306527SDavid du Colombier 		mkel(mkalg(ALG_md5WithRSAEncryption),
2303d9306527SDavid du Colombier 		mkel(issuer,
2304d9306527SDavid du Colombier 		mkel(validity,
2305d9306527SDavid du Colombier 		mkel(subject,
2306d9306527SDavid du Colombier 		mkel(pubkey,
2307d9306527SDavid du Colombier 		nil)))))));
2308d9306527SDavid du Colombier 	if(encode(certinfo, &certinfobytes) != ASN_OK)
2309d9306527SDavid du Colombier 		goto errret;
2310d9306527SDavid du Colombier 	md5(certinfobytes->data, certinfobytes->len, digest, 0);
2311d9306527SDavid du Colombier 	freebytes(certinfobytes);
2312d9306527SDavid du Colombier 	sig = mkseq(
23131075affeSDavid du Colombier 		mkel(mkalg(ALG_md5),
2314d9306527SDavid du Colombier 		mkel(mkoctet(digest, MD5dlen),
2315d9306527SDavid du Colombier 		nil)));
2316d9306527SDavid du Colombier 	if(encode(sig, &sigbytes) != ASN_OK)
2317d9306527SDavid du Colombier 		goto errret;
2318d9306527SDavid du Colombier 	pkcs1 = pkcs1pad(sigbytes, pk->n);
2319d9306527SDavid du Colombier 	freebytes(sigbytes);
2320d9306527SDavid du Colombier 	rsadecrypt(priv, pkcs1, pkcs1);
2321d9306527SDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &buf);
2322d9306527SDavid du Colombier 	mpfree(pkcs1);
2323d9306527SDavid du Colombier 	e = mkseq(
2324d9306527SDavid du Colombier 		mkel(certinfo,
2325d9306527SDavid du Colombier 		mkel(mkalg(ALG_md5WithRSAEncryption),
2326d9306527SDavid du Colombier 		mkel(mkbits(buf, buflen),
2327d9306527SDavid du Colombier 		nil))));
2328d9306527SDavid du Colombier 	free(buf);
2329d9306527SDavid du Colombier 	if(encode(e, &certbytes) != ASN_OK)
2330d9306527SDavid du Colombier 		goto errret;
2331d9306527SDavid du Colombier 	if(certlen)
2332d9306527SDavid du Colombier 		*certlen = certbytes->len;
2333d9306527SDavid du Colombier 	cert = certbytes->data;
2334d9306527SDavid du Colombier errret:
2335d9306527SDavid du Colombier 	freevalfields(&e.val);
2336d9306527SDavid du Colombier 	return cert;
2337d9306527SDavid du Colombier }
2338d9306527SDavid du Colombier 
23391075affeSDavid du Colombier uchar*
23401075affeSDavid du Colombier X509req(RSApriv *priv, char *subj, int *certlen)
23411075affeSDavid du Colombier {
23421075affeSDavid du Colombier 	/* RFC 2314, PKCS #10 Certification Request Syntax */
23431075affeSDavid du Colombier 	int version = 0;
23441075affeSDavid du Colombier 	uchar *cert = nil;
23451075affeSDavid du Colombier 	RSApub *pk = rsaprivtopub(priv);
23461075affeSDavid du Colombier 	Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
23471075affeSDavid du Colombier 	Elem e, certinfo, subject, pubkey, sig;
23481075affeSDavid du Colombier 	uchar digest[MD5dlen], *buf;
23491075affeSDavid du Colombier 	int buflen;
23501075affeSDavid du Colombier 	mpint *pkcs1;
23511075affeSDavid du Colombier 
23521075affeSDavid du Colombier 	e.val.tag = VInt;  /* so freevalfields at errret is no-op */
23531075affeSDavid du Colombier 	subject = mkDN(subj);
23541075affeSDavid du Colombier 	pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
23551075affeSDavid du Colombier 	if(encode(pubkey, &pkbytes) != ASN_OK)
23561075affeSDavid du Colombier 		goto errret;
23571075affeSDavid du Colombier 	freevalfields(&pubkey.val);
23581075affeSDavid du Colombier 	pubkey = mkseq(
23591075affeSDavid du Colombier 		mkel(mkalg(ALG_rsaEncryption),
23601075affeSDavid du Colombier 		mkel(mkbits(pkbytes->data, pkbytes->len),
23611075affeSDavid du Colombier 		nil)));
23621075affeSDavid du Colombier 	freebytes(pkbytes);
23631075affeSDavid du Colombier 	certinfo = mkseq(
23641075affeSDavid du Colombier 		mkel(mkint(version),
23651075affeSDavid du Colombier 		mkel(subject,
23661075affeSDavid du Colombier 		mkel(pubkey,
23671075affeSDavid du Colombier 		nil))));
23681075affeSDavid du Colombier 	if(encode(certinfo, &certinfobytes) != ASN_OK)
23691075affeSDavid du Colombier 		goto errret;
23701075affeSDavid du Colombier 	md5(certinfobytes->data, certinfobytes->len, digest, 0);
23711075affeSDavid du Colombier 	freebytes(certinfobytes);
23721075affeSDavid du Colombier 	sig = mkseq(
23731075affeSDavid du Colombier 		mkel(mkalg(ALG_md5),
23741075affeSDavid du Colombier 		mkel(mkoctet(digest, MD5dlen),
23751075affeSDavid du Colombier 		nil)));
23761075affeSDavid du Colombier 	if(encode(sig, &sigbytes) != ASN_OK)
23771075affeSDavid du Colombier 		goto errret;
23781075affeSDavid du Colombier 	pkcs1 = pkcs1pad(sigbytes, pk->n);
23791075affeSDavid du Colombier 	freebytes(sigbytes);
23801075affeSDavid du Colombier 	rsadecrypt(priv, pkcs1, pkcs1);
23811075affeSDavid du Colombier 	buflen = mptobe(pkcs1, nil, 0, &buf);
23821075affeSDavid du Colombier 	mpfree(pkcs1);
23831075affeSDavid du Colombier 	e = mkseq(
23841075affeSDavid du Colombier 		mkel(certinfo,
23851075affeSDavid du Colombier 		mkel(mkalg(ALG_md5),
23861075affeSDavid du Colombier 		mkel(mkbits(buf, buflen),
23871075affeSDavid du Colombier 		nil))));
23881075affeSDavid du Colombier 	free(buf);
23891075affeSDavid du Colombier 	if(encode(e, &certbytes) != ASN_OK)
23901075affeSDavid du Colombier 		goto errret;
23911075affeSDavid du Colombier 	if(certlen)
23921075affeSDavid du Colombier 		*certlen = certbytes->len;
23931075affeSDavid du Colombier 	cert = certbytes->data;
23941075affeSDavid du Colombier errret:
23951075affeSDavid du Colombier 	freevalfields(&e.val);
23961075affeSDavid du Colombier 	return cert;
23971075affeSDavid du Colombier }
23981075affeSDavid du Colombier 
2399d9306527SDavid du Colombier static char*
2400d9306527SDavid du Colombier tagdump(Tag tag)
2401d9306527SDavid du Colombier {
2402d9306527SDavid du Colombier 	if(tag.class != Universal)
2403d9306527SDavid du Colombier 		return smprint("class%d,num%d", tag.class, tag.num);
2404d9306527SDavid du Colombier 	switch(tag.num){
2405d9306527SDavid du Colombier 		case BOOLEAN: return "BOOLEAN"; break;
2406d9306527SDavid du Colombier 		case INTEGER: return "INTEGER"; break;
2407d9306527SDavid du Colombier 		case BIT_STRING: return "BIT STRING"; break;
2408d9306527SDavid du Colombier 		case OCTET_STRING: return "OCTET STRING"; break;
2409d9306527SDavid du Colombier 		case NULLTAG: return "NULLTAG"; break;
2410d9306527SDavid du Colombier 		case OBJECT_ID: return "OID"; break;
2411d9306527SDavid du Colombier 		case ObjectDescriptor: return "OBJECT_DES"; break;
2412d9306527SDavid du Colombier 		case EXTERNAL: return "EXTERNAL"; break;
2413d9306527SDavid du Colombier 		case REAL: return "REAL"; break;
2414d9306527SDavid du Colombier 		case ENUMERATED: return "ENUMERATED"; break;
2415d9306527SDavid du Colombier 		case EMBEDDED_PDV: return "EMBEDDED PDV"; break;
2416d9306527SDavid du Colombier 		case SEQUENCE: return "SEQUENCE"; break;
2417d9306527SDavid du Colombier 		case SETOF: return "SETOF"; break;
2418d9306527SDavid du Colombier 		case NumericString: return "NumericString"; break;
2419d9306527SDavid du Colombier 		case PrintableString: return "PrintableString"; break;
2420d9306527SDavid du Colombier 		case TeletexString: return "TeletexString"; break;
2421d9306527SDavid du Colombier 		case VideotexString: return "VideotexString"; break;
2422d9306527SDavid du Colombier 		case IA5String: return "IA5String"; break;
2423d9306527SDavid du Colombier 		case UTCTime: return "UTCTime"; break;
2424d9306527SDavid du Colombier 		case GeneralizedTime: return "GeneralizedTime"; break;
2425d9306527SDavid du Colombier 		case GraphicString: return "GraphicString"; break;
2426d9306527SDavid du Colombier 		case VisibleString: return "VisibleString"; break;
2427d9306527SDavid du Colombier 		case GeneralString: return "GeneralString"; break;
2428d9306527SDavid du Colombier 		case UniversalString: return "UniversalString"; break;
2429d9306527SDavid du Colombier 		case BMPString: return "BMPString"; break;
2430d9306527SDavid du Colombier 		default:
2431d9306527SDavid du Colombier 			return smprint("Universal,num%d", tag.num);
2432d9306527SDavid du Colombier 	}
2433d9306527SDavid du Colombier }
2434d9306527SDavid du Colombier 
2435d9306527SDavid du Colombier static void
2436d9306527SDavid du Colombier edump(Elem e)
2437d9306527SDavid du Colombier {
2438d9306527SDavid du Colombier 	Value v;
2439d9306527SDavid du Colombier 	Elist *el;
2440d9306527SDavid du Colombier 	int i;
2441d9306527SDavid du Colombier 
2442d9306527SDavid du Colombier 	print("%s{", tagdump(e.tag));
2443d9306527SDavid du Colombier 	v = e.val;
2444d9306527SDavid du Colombier 	switch(v.tag){
2445d9306527SDavid du Colombier 	case VBool: print("Bool %d",v.u.boolval); break;
2446d9306527SDavid du Colombier 	case VInt: print("Int %d",v.u.intval); break;
2447d9306527SDavid du Colombier 	case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break;
2448d9306527SDavid du Colombier 	case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
2449d9306527SDavid du Colombier 	case VReal: print("Real..."); break;
2450d9306527SDavid du Colombier 	case VOther: print("Other..."); break;
2451d9306527SDavid du Colombier 	case VBitString: print("BitString..."); break;
2452d9306527SDavid du Colombier 	case VNull: print("Null"); break;
2453d9306527SDavid du Colombier 	case VEOC: print("EOC..."); break;
2454d9306527SDavid du Colombier 	case VObjId: print("ObjId");
2455d9306527SDavid du Colombier 		for(i = 0; i<v.u.objidval->len; i++)
2456d9306527SDavid du Colombier 			print(" %d", v.u.objidval->data[i]);
2457d9306527SDavid du Colombier 		break;
2458d9306527SDavid du Colombier 	case VString: print("String \"%s\"",v.u.stringval); break;
2459d9306527SDavid du Colombier 	case VSeq: print("Seq\n");
2460d9306527SDavid du Colombier 		for(el = v.u.seqval; el!=nil; el = el->tl)
2461d9306527SDavid du Colombier 			edump(el->hd);
2462d9306527SDavid du Colombier 		break;
2463d9306527SDavid du Colombier 	case VSet: print("Set\n");
2464d9306527SDavid du Colombier 		for(el = v.u.setval; el!=nil; el = el->tl)
2465d9306527SDavid du Colombier 			edump(el->hd);
2466d9306527SDavid du Colombier 		break;
2467d9306527SDavid du Colombier 	}
2468d9306527SDavid du Colombier 	print("}\n");
2469d9306527SDavid du Colombier }
2470d9306527SDavid du Colombier 
2471d9306527SDavid du Colombier void
2472d9306527SDavid du Colombier asn1dump(uchar *der, int len)
2473d9306527SDavid du Colombier {
2474d9306527SDavid du Colombier 	Elem e;
2475d9306527SDavid du Colombier 
2476d9306527SDavid du Colombier 	if(decode(der, len, &e) != ASN_OK){
24771075affeSDavid du Colombier 		print("didn't parse\n");
2478d9306527SDavid du Colombier 		exits("didn't parse");
2479d9306527SDavid du Colombier 	}
2480d9306527SDavid du Colombier 	edump(e);
2481d9306527SDavid du Colombier }
24821075affeSDavid du Colombier 
24831075affeSDavid du Colombier void
24841075affeSDavid du Colombier X509dump(uchar *cert, int ncert)
24851075affeSDavid du Colombier {
24861075affeSDavid du Colombier 	char *e;
24871075affeSDavid du Colombier 	Bytes *b;
24881075affeSDavid du Colombier 	CertX509 *c;
24891075affeSDavid du Colombier 	RSApub *pk;
24901075affeSDavid du Colombier 	uchar digest[SHA1dlen];
24911075affeSDavid du Colombier 	Elem *sigalg;
24921075affeSDavid du Colombier 
24931075affeSDavid du Colombier 	print("begin X509dump\n");
24941075affeSDavid du Colombier 	b = makebytes(cert, ncert);
24951075affeSDavid du Colombier 	c = decode_cert(b);
24961075affeSDavid du Colombier 	if(c != nil)
24971075affeSDavid du Colombier 		digest_certinfo(b, digestalg[c->signature_alg], digest);
24981075affeSDavid du Colombier 	freebytes(b);
24991075affeSDavid du Colombier 	if(c == nil){
25001075affeSDavid du Colombier 		print("cannot decode cert");
25011075affeSDavid du Colombier 		return;
25021075affeSDavid du Colombier 	}
25031075affeSDavid du Colombier 
25041075affeSDavid du Colombier 	print("serial %d\n", c->serial);
25051075affeSDavid du Colombier 	print("issuer %s\n", c->issuer);
25061075affeSDavid du Colombier 	print("validity %s %s\n", c->validity_start, c->validity_end);
25071075affeSDavid du Colombier 	print("subject %s\n", c->subject);
25081075affeSDavid du Colombier 	pk = decode_rsapubkey(c->publickey);
25091075affeSDavid du Colombier 	print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n);
25101075affeSDavid du Colombier 
25111075affeSDavid du Colombier 	print("sigalg=%d digest=%.*H\n", c->signature_alg, MD5dlen, digest);
25121075affeSDavid du Colombier 	e = verify_signature(c->signature, pk, digest, &sigalg);
25131075affeSDavid du Colombier 	if(e==nil){
25141075affeSDavid du Colombier 		e = "nil (meaning ok)";
25151075affeSDavid du Colombier 		print("sigalg=\n");
25161075affeSDavid du Colombier 		if(sigalg)
25171075affeSDavid du Colombier 			edump(*sigalg);
25181075affeSDavid du Colombier 	}
25191075affeSDavid du Colombier 	print("self-signed verify_signature returns: %s\n", e);
25201075affeSDavid du Colombier 
25211075affeSDavid du Colombier 	rsapubfree(pk);
25221075affeSDavid du Colombier 	freecert(c);
25231075affeSDavid du Colombier 	print("end X509dump\n");
25241075affeSDavid du Colombier }
2525