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
43de8abbc9SDavid du Colombier #define UTF8String 12
4480ee5cbfSDavid du Colombier #define SEQUENCE 16 /* also SEQUENCE OF */
459a747e4fSDavid du Colombier #define SETOF 17 /* also SETOF OF */
4680ee5cbfSDavid du Colombier #define NumericString 18
4780ee5cbfSDavid du Colombier #define PrintableString 19
4880ee5cbfSDavid du Colombier #define TeletexString 20
4980ee5cbfSDavid du Colombier #define VideotexString 21
5080ee5cbfSDavid du Colombier #define IA5String 22
5180ee5cbfSDavid du Colombier #define UTCTime 23
5280ee5cbfSDavid du Colombier #define GeneralizedTime 24
5380ee5cbfSDavid du Colombier #define GraphicString 25
5480ee5cbfSDavid du Colombier #define VisibleString 26
5580ee5cbfSDavid du Colombier #define GeneralString 27
5680ee5cbfSDavid du Colombier #define UniversalString 28
5780ee5cbfSDavid du Colombier #define BMPString 30
5880ee5cbfSDavid du Colombier
5980ee5cbfSDavid du Colombier struct Bytes {
6080ee5cbfSDavid du Colombier int len;
6180ee5cbfSDavid du Colombier uchar data[1];
6280ee5cbfSDavid du Colombier };
6380ee5cbfSDavid du Colombier
6480ee5cbfSDavid du Colombier struct Ints {
6580ee5cbfSDavid du Colombier int len;
6680ee5cbfSDavid du Colombier int data[1];
6780ee5cbfSDavid du Colombier };
6880ee5cbfSDavid du Colombier
6980ee5cbfSDavid du Colombier struct Bits {
7080ee5cbfSDavid du Colombier int len; /* number of bytes */
7180ee5cbfSDavid du Colombier int unusedbits; /* unused bits in last byte */
7280ee5cbfSDavid du Colombier uchar data[1]; /* most-significant bit first */
7380ee5cbfSDavid du Colombier };
7480ee5cbfSDavid du Colombier
7580ee5cbfSDavid du Colombier struct Tag {
7680ee5cbfSDavid du Colombier int class;
7780ee5cbfSDavid du Colombier int num;
7880ee5cbfSDavid du Colombier };
7980ee5cbfSDavid du Colombier
8080ee5cbfSDavid du Colombier enum { VBool, VInt, VOctets, VBigInt, VReal, VOther,
8180ee5cbfSDavid du Colombier VBitString, VNull, VEOC, VObjId, VString, VSeq, VSet };
8280ee5cbfSDavid du Colombier struct Value {
8380ee5cbfSDavid du Colombier int tag; /* VBool, etc. */
8480ee5cbfSDavid du Colombier union {
8580ee5cbfSDavid du Colombier int boolval;
8680ee5cbfSDavid du Colombier int intval;
8780ee5cbfSDavid du Colombier Bytes* octetsval;
8880ee5cbfSDavid du Colombier Bytes* bigintval;
8980ee5cbfSDavid du Colombier Bytes* realval; /* undecoded; hardly ever used */
9080ee5cbfSDavid du Colombier Bytes* otherval;
9180ee5cbfSDavid du Colombier Bits* bitstringval;
9280ee5cbfSDavid du Colombier Ints* objidval;
9380ee5cbfSDavid du Colombier char* stringval;
9480ee5cbfSDavid du Colombier Elist* seqval;
9580ee5cbfSDavid du Colombier Elist* setval;
9680ee5cbfSDavid du Colombier } u; /* (Don't use anonymous unions, for ease of porting) */
9780ee5cbfSDavid du Colombier };
9880ee5cbfSDavid du Colombier
9980ee5cbfSDavid du Colombier struct Elem {
10080ee5cbfSDavid du Colombier Tag tag;
10180ee5cbfSDavid du Colombier Value val;
10280ee5cbfSDavid du Colombier };
10380ee5cbfSDavid du Colombier
10480ee5cbfSDavid du Colombier struct Elist {
10580ee5cbfSDavid du Colombier Elist* tl;
10680ee5cbfSDavid du Colombier Elem hd;
10780ee5cbfSDavid du Colombier };
10880ee5cbfSDavid du Colombier
10980ee5cbfSDavid du Colombier /* decoding errors */
11080ee5cbfSDavid du Colombier enum { ASN_OK, ASN_ESHORT, ASN_ETOOBIG, ASN_EVALLEN,
11180ee5cbfSDavid du Colombier ASN_ECONSTR, ASN_EPRIM, ASN_EINVAL, ASN_EUNIMPL };
11280ee5cbfSDavid du Colombier
11380ee5cbfSDavid du Colombier
11480ee5cbfSDavid du Colombier /* here are the functions to consider making extern someday */
11580ee5cbfSDavid du Colombier static Bytes* newbytes(int len);
11680ee5cbfSDavid du Colombier static Bytes* makebytes(uchar* buf, int len);
11780ee5cbfSDavid du Colombier static void freebytes(Bytes* b);
11880ee5cbfSDavid du Colombier static Bytes* catbytes(Bytes* b1, Bytes* b2);
11980ee5cbfSDavid du Colombier static Ints* newints(int len);
12080ee5cbfSDavid du Colombier static Ints* makeints(int* buf, int len);
12180ee5cbfSDavid du Colombier static void freeints(Ints* b);
12280ee5cbfSDavid du Colombier static Bits* newbits(int len);
12380ee5cbfSDavid du Colombier static Bits* makebits(uchar* buf, int len, int unusedbits);
12480ee5cbfSDavid du Colombier static void freebits(Bits* b);
125d9306527SDavid du Colombier static Elist* mkel(Elem e, Elist* tail);
12680ee5cbfSDavid du Colombier static void freeelist(Elist* el);
12780ee5cbfSDavid du Colombier static int elistlen(Elist* el);
12880ee5cbfSDavid du Colombier static int is_seq(Elem* pe, Elist** pseq);
12980ee5cbfSDavid du Colombier static int is_set(Elem* pe, Elist** pset);
13080ee5cbfSDavid du Colombier static int is_int(Elem* pe, int* pint);
13180ee5cbfSDavid du Colombier static int is_bigint(Elem* pe, Bytes** pbigint);
13280ee5cbfSDavid du Colombier static int is_bitstring(Elem* pe, Bits** pbits);
13380ee5cbfSDavid du Colombier static int is_octetstring(Elem* pe, Bytes** poctets);
13480ee5cbfSDavid du Colombier static int is_oid(Elem* pe, Ints** poid);
13580ee5cbfSDavid du Colombier static int is_string(Elem* pe, char** pstring);
13680ee5cbfSDavid du Colombier static int is_time(Elem* pe, char** ptime);
13780ee5cbfSDavid du Colombier static int decode(uchar* a, int alen, Elem* pelem);
13880ee5cbfSDavid du Colombier static int decode_seq(uchar* a, int alen, Elist** pelist);
13980ee5cbfSDavid du Colombier static int decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval);
14080ee5cbfSDavid du Colombier static int encode(Elem e, Bytes** pbytes);
14180ee5cbfSDavid du Colombier static int oid_lookup(Ints* o, Ints** tab);
14280ee5cbfSDavid du Colombier static void freevalfields(Value* v);
1439a747e4fSDavid du Colombier static mpint *asn1mpint(Elem *e);
14480ee5cbfSDavid du Colombier
14580ee5cbfSDavid du Colombier
14680ee5cbfSDavid du Colombier
14780ee5cbfSDavid du Colombier #define TAG_MASK 0x1F
14880ee5cbfSDavid du Colombier #define CONSTR_MASK 0x20
14980ee5cbfSDavid du Colombier #define CLASS_MASK 0xC0
15080ee5cbfSDavid du Colombier #define MAXOBJIDLEN 20
15180ee5cbfSDavid du Colombier
15280ee5cbfSDavid du Colombier static int ber_decode(uchar** pp, uchar* pend, Elem* pelem);
15380ee5cbfSDavid du Colombier static int tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr);
15480ee5cbfSDavid du Colombier static int length_decode(uchar** pp, uchar* pend, int* plength);
15580ee5cbfSDavid du Colombier static int value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval);
15680ee5cbfSDavid du Colombier static int int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint);
15780ee5cbfSDavid du Colombier static int uint7_decode(uchar** pp, uchar* pend, int* pint);
15880ee5cbfSDavid du Colombier static int octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes);
15980ee5cbfSDavid du Colombier static int seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist);
16080ee5cbfSDavid du Colombier static int enc(uchar** pp, Elem e, int lenonly);
16180ee5cbfSDavid du Colombier static int val_enc(uchar** pp, Elem e, int *pconstr, int lenonly);
16280ee5cbfSDavid du Colombier static void uint7_enc(uchar** pp, int num, int lenonly);
16380ee5cbfSDavid du Colombier static void int_enc(uchar** pp, int num, int unsgned, int lenonly);
16480ee5cbfSDavid du Colombier
165d9306527SDavid du Colombier static void *
emalloc(int n)166d9306527SDavid du Colombier emalloc(int n)
167d9306527SDavid du Colombier {
168d9306527SDavid du Colombier void *p;
169d9306527SDavid du Colombier if(n==0)
170d9306527SDavid du Colombier n=1;
171d9306527SDavid du Colombier p = malloc(n);
172d9306527SDavid du Colombier if(p == nil){
173d9306527SDavid du Colombier exits("out of memory");
174d9306527SDavid du Colombier }
175d9306527SDavid du Colombier memset(p, 0, n);
1769027b8f7SDavid du Colombier setmalloctag(p, getcallerpc(&n));
177d9306527SDavid du Colombier return p;
178d9306527SDavid du Colombier }
179d9306527SDavid du Colombier
180d9306527SDavid du Colombier static char*
estrdup(char * s)181d9306527SDavid du Colombier estrdup(char *s)
182d9306527SDavid du Colombier {
183d9306527SDavid du Colombier char *d, *d0;
184d9306527SDavid du Colombier
185d9306527SDavid du Colombier if(!s)
186d9306527SDavid du Colombier return 0;
187d9306527SDavid du Colombier d = d0 = emalloc(strlen(s)+1);
188d9306527SDavid du Colombier while(*d++ = *s++)
189d9306527SDavid du Colombier ;
190d9306527SDavid du Colombier return d0;
191d9306527SDavid du Colombier }
192d9306527SDavid du Colombier
19380ee5cbfSDavid du Colombier
19480ee5cbfSDavid du Colombier /*
19580ee5cbfSDavid du Colombier * Decode a[0..len] as a BER encoding of an ASN1 type.
19680ee5cbfSDavid du Colombier * The return value is one of ASN_OK, etc.
19780ee5cbfSDavid du Colombier * Depending on the error, the returned elem may or may not
19880ee5cbfSDavid du Colombier * be nil.
19980ee5cbfSDavid du Colombier */
20080ee5cbfSDavid du Colombier static int
decode(uchar * a,int alen,Elem * pelem)20180ee5cbfSDavid du Colombier decode(uchar* a, int alen, Elem* pelem)
20280ee5cbfSDavid du Colombier {
20380ee5cbfSDavid du Colombier uchar* p = a;
20480ee5cbfSDavid du Colombier
20580ee5cbfSDavid du Colombier return ber_decode(&p, &a[alen], pelem);
20680ee5cbfSDavid du Colombier }
20780ee5cbfSDavid du Colombier
20880ee5cbfSDavid du Colombier /*
20980ee5cbfSDavid du Colombier * Like decode, but continue decoding after first element
21080ee5cbfSDavid du Colombier * of array ends.
21180ee5cbfSDavid du Colombier */
21280ee5cbfSDavid du Colombier static int
decode_seq(uchar * a,int alen,Elist ** pelist)21380ee5cbfSDavid du Colombier decode_seq(uchar* a, int alen, Elist** pelist)
21480ee5cbfSDavid du Colombier {
21580ee5cbfSDavid du Colombier uchar* p = a;
21680ee5cbfSDavid du Colombier
21780ee5cbfSDavid du Colombier return seq_decode(&p, &a[alen], -1, 1, pelist);
21880ee5cbfSDavid du Colombier }
21980ee5cbfSDavid du Colombier
22080ee5cbfSDavid du Colombier /*
22180ee5cbfSDavid du Colombier * Decode the whole array as a BER encoding of an ASN1 value,
22280ee5cbfSDavid du Colombier * (i.e., the part after the tag and length).
22380ee5cbfSDavid du Colombier * Assume the value is encoded as universal tag "kind".
22480ee5cbfSDavid du Colombier * The constr arg is 1 if the value is constructed, 0 if primitive.
22580ee5cbfSDavid du Colombier * If there's an error, the return string will contain the error.
22680ee5cbfSDavid du Colombier * Depending on the error, the returned value may or may not
22780ee5cbfSDavid du Colombier * be nil.
22880ee5cbfSDavid du Colombier */
22980ee5cbfSDavid du Colombier static int
decode_value(uchar * a,int alen,int kind,int isconstr,Value * pval)23080ee5cbfSDavid du Colombier decode_value(uchar* a, int alen, int kind, int isconstr, Value* pval)
23180ee5cbfSDavid du Colombier {
23280ee5cbfSDavid du Colombier uchar* p = a;
23380ee5cbfSDavid du Colombier
23480ee5cbfSDavid du Colombier return value_decode(&p, &a[alen], alen, kind, isconstr, pval);
23580ee5cbfSDavid du Colombier }
23680ee5cbfSDavid du Colombier
23780ee5cbfSDavid du Colombier /*
23880ee5cbfSDavid du Colombier * All of the following decoding routines take arguments:
23980ee5cbfSDavid du Colombier * uchar **pp;
24080ee5cbfSDavid du Colombier * uchar *pend;
24180ee5cbfSDavid du Colombier * Where parsing is supposed to start at **pp, and when parsing
24280ee5cbfSDavid du Colombier * is done, *pp is updated to point at next char to be parsed.
24380ee5cbfSDavid du Colombier * The pend pointer is just past end of string; an error should
24480ee5cbfSDavid du Colombier * be returned parsing hasn't finished by then.
24580ee5cbfSDavid du Colombier *
24680ee5cbfSDavid du Colombier * The returned int is ASN_OK if all went fine, else ASN_ESHORT, etc.
24780ee5cbfSDavid du Colombier * The remaining argument(s) are pointers to where parsed entity goes.
24880ee5cbfSDavid du Colombier */
24980ee5cbfSDavid du Colombier
25080ee5cbfSDavid du Colombier /* Decode an ASN1 'Elem' (tag, length, value) */
25180ee5cbfSDavid du Colombier static int
ber_decode(uchar ** pp,uchar * pend,Elem * pelem)25280ee5cbfSDavid du Colombier ber_decode(uchar** pp, uchar* pend, Elem* pelem)
25380ee5cbfSDavid du Colombier {
25480ee5cbfSDavid du Colombier int err;
25580ee5cbfSDavid du Colombier int isconstr;
25680ee5cbfSDavid du Colombier int length;
25780ee5cbfSDavid du Colombier Tag tag;
25880ee5cbfSDavid du Colombier Value val;
25980ee5cbfSDavid du Colombier
26080ee5cbfSDavid du Colombier err = tag_decode(pp, pend, &tag, &isconstr);
26180ee5cbfSDavid du Colombier if(err == ASN_OK) {
26280ee5cbfSDavid du Colombier err = length_decode(pp, pend, &length);
26380ee5cbfSDavid du Colombier if(err == ASN_OK) {
2649027b8f7SDavid du Colombier if(tag.class == Universal) {
26580ee5cbfSDavid du Colombier err = value_decode(pp, pend, length, tag.num, isconstr, &val);
2669027b8f7SDavid du Colombier if(val.tag == VSeq || val.tag == VSet)
2679027b8f7SDavid du Colombier setmalloctag(val.u.seqval, getcallerpc(&pp));
2689027b8f7SDavid du Colombier }else
26980ee5cbfSDavid du Colombier err = value_decode(pp, pend, length, OCTET_STRING, 0, &val);
27080ee5cbfSDavid du Colombier if(err == ASN_OK) {
27180ee5cbfSDavid du Colombier pelem->tag = tag;
27280ee5cbfSDavid du Colombier pelem->val = val;
27380ee5cbfSDavid du Colombier }
27480ee5cbfSDavid du Colombier }
27580ee5cbfSDavid du Colombier }
27680ee5cbfSDavid du Colombier return err;
27780ee5cbfSDavid du Colombier }
27880ee5cbfSDavid du Colombier
27980ee5cbfSDavid du Colombier /* Decode a tag field */
28080ee5cbfSDavid du Colombier static int
tag_decode(uchar ** pp,uchar * pend,Tag * ptag,int * pisconstr)28180ee5cbfSDavid du Colombier tag_decode(uchar** pp, uchar* pend, Tag* ptag, int* pisconstr)
28280ee5cbfSDavid du Colombier {
28380ee5cbfSDavid du Colombier int err;
28480ee5cbfSDavid du Colombier int v;
28580ee5cbfSDavid du Colombier uchar* p;
28680ee5cbfSDavid du Colombier
28780ee5cbfSDavid du Colombier err = ASN_OK;
28880ee5cbfSDavid du Colombier p = *pp;
28980ee5cbfSDavid du Colombier if(pend-p >= 2) {
29080ee5cbfSDavid du Colombier v = *p++;
29180ee5cbfSDavid du Colombier ptag->class = v&CLASS_MASK;
29280ee5cbfSDavid du Colombier if(v&CONSTR_MASK)
29380ee5cbfSDavid du Colombier *pisconstr = 1;
29480ee5cbfSDavid du Colombier else
29580ee5cbfSDavid du Colombier *pisconstr = 0;
29680ee5cbfSDavid du Colombier v &= TAG_MASK;
29780ee5cbfSDavid du Colombier if(v == TAG_MASK)
29880ee5cbfSDavid du Colombier err = uint7_decode(&p, pend, &v);
29980ee5cbfSDavid du Colombier ptag->num = v;
30080ee5cbfSDavid du Colombier }
30180ee5cbfSDavid du Colombier else
30280ee5cbfSDavid du Colombier err = ASN_ESHORT;
30380ee5cbfSDavid du Colombier *pp = p;
30480ee5cbfSDavid du Colombier return err;
30580ee5cbfSDavid du Colombier }
30680ee5cbfSDavid du Colombier
30780ee5cbfSDavid du Colombier /* Decode a length field */
30880ee5cbfSDavid du Colombier static int
length_decode(uchar ** pp,uchar * pend,int * plength)30980ee5cbfSDavid du Colombier length_decode(uchar** pp, uchar* pend, int* plength)
31080ee5cbfSDavid du Colombier {
31180ee5cbfSDavid du Colombier int err;
31280ee5cbfSDavid du Colombier int num;
31380ee5cbfSDavid du Colombier int v;
31480ee5cbfSDavid du Colombier uchar* p;
31580ee5cbfSDavid du Colombier
31680ee5cbfSDavid du Colombier err = ASN_OK;
31780ee5cbfSDavid du Colombier num = 0;
31880ee5cbfSDavid du Colombier p = *pp;
31980ee5cbfSDavid du Colombier if(p < pend) {
32080ee5cbfSDavid du Colombier v = *p++;
32180ee5cbfSDavid du Colombier if(v&0x80)
32280ee5cbfSDavid du Colombier err = int_decode(&p, pend, v&0x7F, 1, &num);
32380ee5cbfSDavid du Colombier else
32480ee5cbfSDavid du Colombier num = v;
32580ee5cbfSDavid du Colombier }
32680ee5cbfSDavid du Colombier else
32780ee5cbfSDavid du Colombier err = ASN_ESHORT;
32880ee5cbfSDavid du Colombier *pp = p;
32980ee5cbfSDavid du Colombier *plength = num;
33080ee5cbfSDavid du Colombier return err;
33180ee5cbfSDavid du Colombier }
33280ee5cbfSDavid du Colombier
33380ee5cbfSDavid du Colombier /* Decode a value field */
33480ee5cbfSDavid du Colombier static int
value_decode(uchar ** pp,uchar * pend,int length,int kind,int isconstr,Value * pval)33580ee5cbfSDavid du Colombier value_decode(uchar** pp, uchar* pend, int length, int kind, int isconstr, Value* pval)
33680ee5cbfSDavid du Colombier {
33780ee5cbfSDavid du Colombier int err;
33880ee5cbfSDavid du Colombier Bytes* va;
33980ee5cbfSDavid du Colombier int num;
34080ee5cbfSDavid du Colombier int bitsunused;
34180ee5cbfSDavid du Colombier int subids[MAXOBJIDLEN];
34280ee5cbfSDavid du Colombier int isubid;
34380ee5cbfSDavid du Colombier Elist* vl;
34480ee5cbfSDavid du Colombier uchar* p;
34580ee5cbfSDavid du Colombier uchar* pe;
34680ee5cbfSDavid du Colombier
34780ee5cbfSDavid du Colombier err = ASN_OK;
34880ee5cbfSDavid du Colombier p = *pp;
34980ee5cbfSDavid du Colombier if(length == -1) { /* "indefinite" length spec */
35080ee5cbfSDavid du Colombier if(!isconstr)
35180ee5cbfSDavid du Colombier err = ASN_EINVAL;
35280ee5cbfSDavid du Colombier }
35380ee5cbfSDavid du Colombier else if(p + length > pend)
35480ee5cbfSDavid du Colombier err = ASN_EVALLEN;
35580ee5cbfSDavid du Colombier if(err != ASN_OK)
35680ee5cbfSDavid du Colombier return err;
35780ee5cbfSDavid du Colombier
35880ee5cbfSDavid du Colombier switch(kind) {
35980ee5cbfSDavid du Colombier case 0:
36080ee5cbfSDavid du Colombier /* marker for end of indefinite constructions */
36180ee5cbfSDavid du Colombier if(length == 0)
36280ee5cbfSDavid du Colombier pval->tag = VNull;
36380ee5cbfSDavid du Colombier else
36480ee5cbfSDavid du Colombier err = ASN_EINVAL;
36580ee5cbfSDavid du Colombier break;
36680ee5cbfSDavid du Colombier
36780ee5cbfSDavid du Colombier case BOOLEAN:
36880ee5cbfSDavid du Colombier if(isconstr)
36980ee5cbfSDavid du Colombier err = ASN_ECONSTR;
37080ee5cbfSDavid du Colombier else if(length != 1)
37180ee5cbfSDavid du Colombier err = ASN_EVALLEN;
37280ee5cbfSDavid du Colombier else {
37380ee5cbfSDavid du Colombier pval->tag = VBool;
37480ee5cbfSDavid du Colombier pval->u.boolval = (*p++ != 0);
37580ee5cbfSDavid du Colombier }
37680ee5cbfSDavid du Colombier break;
37780ee5cbfSDavid du Colombier
37880ee5cbfSDavid du Colombier case INTEGER:
37980ee5cbfSDavid du Colombier case ENUMERATED:
38080ee5cbfSDavid du Colombier if(isconstr)
38180ee5cbfSDavid du Colombier err = ASN_ECONSTR;
38280ee5cbfSDavid du Colombier else if(length <= 4) {
38380ee5cbfSDavid du Colombier err = int_decode(&p, pend, length, 0, &num);
38480ee5cbfSDavid du Colombier if(err == ASN_OK) {
38580ee5cbfSDavid du Colombier pval->tag = VInt;
38680ee5cbfSDavid du Colombier pval->u.intval = num;
38780ee5cbfSDavid du Colombier }
38880ee5cbfSDavid du Colombier }
38980ee5cbfSDavid du Colombier else {
39080ee5cbfSDavid du Colombier pval->tag = VBigInt;
39180ee5cbfSDavid du Colombier pval->u.bigintval = makebytes(p, length);
39280ee5cbfSDavid du Colombier p += length;
39380ee5cbfSDavid du Colombier }
39480ee5cbfSDavid du Colombier break;
39580ee5cbfSDavid du Colombier
39680ee5cbfSDavid du Colombier case BIT_STRING:
39780ee5cbfSDavid du Colombier pval->tag = VBitString;
39880ee5cbfSDavid du Colombier if(isconstr) {
39980ee5cbfSDavid du Colombier if(length == -1 && p + 2 <= pend && *p == 0 && *(p+1) ==0) {
40080ee5cbfSDavid du Colombier pval->u.bitstringval = makebits(0, 0, 0);
40180ee5cbfSDavid du Colombier p += 2;
40280ee5cbfSDavid du Colombier }
40380ee5cbfSDavid du Colombier else
40480ee5cbfSDavid du Colombier /* TODO: recurse and concat results */
40580ee5cbfSDavid du Colombier err = ASN_EUNIMPL;
40680ee5cbfSDavid du Colombier }
40780ee5cbfSDavid du Colombier else {
40880ee5cbfSDavid du Colombier if(length < 2) {
40980ee5cbfSDavid du Colombier if(length == 1 && *p == 0) {
41080ee5cbfSDavid du Colombier pval->u.bitstringval = makebits(0, 0, 0);
41180ee5cbfSDavid du Colombier p++;
41280ee5cbfSDavid du Colombier }
41380ee5cbfSDavid du Colombier else
41480ee5cbfSDavid du Colombier err = ASN_EINVAL;
41580ee5cbfSDavid du Colombier }
41680ee5cbfSDavid du Colombier else {
41780ee5cbfSDavid du Colombier bitsunused = *p;
41880ee5cbfSDavid du Colombier if(bitsunused > 7)
41980ee5cbfSDavid du Colombier err = ASN_EINVAL;
42080ee5cbfSDavid du Colombier else if(length > 0x0FFFFFFF)
42180ee5cbfSDavid du Colombier err = ASN_ETOOBIG;
42280ee5cbfSDavid du Colombier else {
42380ee5cbfSDavid du Colombier pval->u.bitstringval = makebits(p+1, length-1, bitsunused);
42480ee5cbfSDavid du Colombier p += length;
42580ee5cbfSDavid du Colombier }
42680ee5cbfSDavid du Colombier }
42780ee5cbfSDavid du Colombier }
42880ee5cbfSDavid du Colombier break;
42980ee5cbfSDavid du Colombier
43080ee5cbfSDavid du Colombier case OCTET_STRING:
43180ee5cbfSDavid du Colombier case ObjectDescriptor:
43280ee5cbfSDavid du Colombier err = octet_decode(&p, pend, length, isconstr, &va);
43380ee5cbfSDavid du Colombier if(err == ASN_OK) {
43480ee5cbfSDavid du Colombier pval->tag = VOctets;
43580ee5cbfSDavid du Colombier pval->u.octetsval = va;
43680ee5cbfSDavid du Colombier }
43780ee5cbfSDavid du Colombier break;
43880ee5cbfSDavid du Colombier
43980ee5cbfSDavid du Colombier case NULLTAG:
44080ee5cbfSDavid du Colombier if(isconstr)
44180ee5cbfSDavid du Colombier err = ASN_ECONSTR;
44280ee5cbfSDavid du Colombier else if(length != 0)
44380ee5cbfSDavid du Colombier err = ASN_EVALLEN;
44480ee5cbfSDavid du Colombier else
44580ee5cbfSDavid du Colombier pval->tag = VNull;
44680ee5cbfSDavid du Colombier break;
44780ee5cbfSDavid du Colombier
44880ee5cbfSDavid du Colombier case OBJECT_ID:
44980ee5cbfSDavid du Colombier if(isconstr)
45080ee5cbfSDavid du Colombier err = ASN_ECONSTR;
45180ee5cbfSDavid du Colombier else if(length == 0)
45280ee5cbfSDavid du Colombier err = ASN_EVALLEN;
45380ee5cbfSDavid du Colombier else {
45480ee5cbfSDavid du Colombier isubid = 0;
45580ee5cbfSDavid du Colombier pe = p+length;
45680ee5cbfSDavid du Colombier while(p < pe && isubid < MAXOBJIDLEN) {
45780ee5cbfSDavid du Colombier err = uint7_decode(&p, pend, &num);
45880ee5cbfSDavid du Colombier if(err != ASN_OK)
45980ee5cbfSDavid du Colombier break;
46080ee5cbfSDavid du Colombier if(isubid == 0) {
46180ee5cbfSDavid du Colombier subids[isubid++] = num / 40;
46280ee5cbfSDavid du Colombier subids[isubid++] = num % 40;
46380ee5cbfSDavid du Colombier }
46480ee5cbfSDavid du Colombier else
46580ee5cbfSDavid du Colombier subids[isubid++] = num;
46680ee5cbfSDavid du Colombier }
46780ee5cbfSDavid du Colombier if(err == ASN_OK) {
46880ee5cbfSDavid du Colombier if(p != pe)
46980ee5cbfSDavid du Colombier err = ASN_EVALLEN;
47080ee5cbfSDavid du Colombier else {
47180ee5cbfSDavid du Colombier pval->tag = VObjId;
47280ee5cbfSDavid du Colombier pval->u.objidval = makeints(subids, isubid);
47380ee5cbfSDavid du Colombier }
47480ee5cbfSDavid du Colombier }
47580ee5cbfSDavid du Colombier }
47680ee5cbfSDavid du Colombier break;
47780ee5cbfSDavid du Colombier
47880ee5cbfSDavid du Colombier case EXTERNAL:
47980ee5cbfSDavid du Colombier case EMBEDDED_PDV:
48080ee5cbfSDavid du Colombier /* TODO: parse this internally */
48180ee5cbfSDavid du Colombier if(p+length > pend)
48280ee5cbfSDavid du Colombier err = ASN_EVALLEN;
48380ee5cbfSDavid du Colombier else {
48480ee5cbfSDavid du Colombier pval->tag = VOther;
48580ee5cbfSDavid du Colombier pval->u.otherval = makebytes(p, length);
48680ee5cbfSDavid du Colombier p += length;
48780ee5cbfSDavid du Colombier }
48880ee5cbfSDavid du Colombier break;
48980ee5cbfSDavid du Colombier
49080ee5cbfSDavid du Colombier case REAL:
49180ee5cbfSDavid du Colombier /* Let the application decode */
49280ee5cbfSDavid du Colombier if(isconstr)
49380ee5cbfSDavid du Colombier err = ASN_ECONSTR;
49480ee5cbfSDavid du Colombier else if(p+length > pend)
49580ee5cbfSDavid du Colombier err = ASN_EVALLEN;
49680ee5cbfSDavid du Colombier else {
49780ee5cbfSDavid du Colombier pval->tag = VReal;
49880ee5cbfSDavid du Colombier pval->u.realval = makebytes(p, length);
49980ee5cbfSDavid du Colombier p += length;
50080ee5cbfSDavid du Colombier }
50180ee5cbfSDavid du Colombier break;
50280ee5cbfSDavid du Colombier
50380ee5cbfSDavid du Colombier case SEQUENCE:
50480ee5cbfSDavid du Colombier err = seq_decode(&p, pend, length, isconstr, &vl);
5059027b8f7SDavid du Colombier setmalloctag(vl, getcallerpc(&pp));
50680ee5cbfSDavid du Colombier if(err == ASN_OK) {
50780ee5cbfSDavid du Colombier pval->tag = VSeq ;
50880ee5cbfSDavid du Colombier pval->u.seqval = vl;
50980ee5cbfSDavid du Colombier }
51080ee5cbfSDavid du Colombier break;
51180ee5cbfSDavid du Colombier
5129a747e4fSDavid du Colombier case SETOF:
51380ee5cbfSDavid du Colombier err = seq_decode(&p, pend, length, isconstr, &vl);
5149027b8f7SDavid du Colombier setmalloctag(vl, getcallerpc(&pp));
51580ee5cbfSDavid du Colombier if(err == ASN_OK) {
51680ee5cbfSDavid du Colombier pval->tag = VSet;
51780ee5cbfSDavid du Colombier pval->u.setval = vl;
51880ee5cbfSDavid du Colombier }
51980ee5cbfSDavid du Colombier break;
520de8abbc9SDavid du Colombier case UTF8String:
52180ee5cbfSDavid du Colombier case NumericString:
52280ee5cbfSDavid du Colombier case PrintableString:
52380ee5cbfSDavid du Colombier case TeletexString:
52480ee5cbfSDavid du Colombier case VideotexString:
52580ee5cbfSDavid du Colombier case IA5String:
52680ee5cbfSDavid du Colombier case UTCTime:
52780ee5cbfSDavid du Colombier case GeneralizedTime:
52880ee5cbfSDavid du Colombier case GraphicString:
52980ee5cbfSDavid du Colombier case VisibleString:
53080ee5cbfSDavid du Colombier case GeneralString:
53180ee5cbfSDavid du Colombier case UniversalString:
53280ee5cbfSDavid du Colombier case BMPString:
53380ee5cbfSDavid du Colombier /* TODO: figure out when character set conversion is necessary */
53480ee5cbfSDavid du Colombier err = octet_decode(&p, pend, length, isconstr, &va);
53580ee5cbfSDavid du Colombier if(err == ASN_OK) {
53680ee5cbfSDavid du Colombier pval->tag = VString;
537d9306527SDavid du Colombier pval->u.stringval = (char*)emalloc(va->len+1);
53880ee5cbfSDavid du Colombier memmove(pval->u.stringval, va->data, va->len);
53980ee5cbfSDavid du Colombier pval->u.stringval[va->len] = 0;
54080ee5cbfSDavid du Colombier free(va);
54180ee5cbfSDavid du Colombier }
54280ee5cbfSDavid du Colombier break;
54380ee5cbfSDavid du Colombier
54480ee5cbfSDavid du Colombier default:
54580ee5cbfSDavid du Colombier if(p+length > pend)
54680ee5cbfSDavid du Colombier err = ASN_EVALLEN;
54780ee5cbfSDavid du Colombier else {
54880ee5cbfSDavid du Colombier pval->tag = VOther;
54980ee5cbfSDavid du Colombier pval->u.otherval = makebytes(p, length);
55080ee5cbfSDavid du Colombier p += length;
55180ee5cbfSDavid du Colombier }
55280ee5cbfSDavid du Colombier break;
55380ee5cbfSDavid du Colombier }
55480ee5cbfSDavid du Colombier *pp = p;
55580ee5cbfSDavid du Colombier return err;
55680ee5cbfSDavid du Colombier }
55780ee5cbfSDavid du Colombier
55880ee5cbfSDavid du Colombier /*
55980ee5cbfSDavid du Colombier * Decode an int in format where count bytes are
56080ee5cbfSDavid du Colombier * concatenated to form value.
56180ee5cbfSDavid du Colombier * Although ASN1 allows any size integer, we return
56280ee5cbfSDavid du Colombier * an error if the result doesn't fit in a 32-bit int.
56380ee5cbfSDavid du Colombier * If unsgned is not set, make sure to propagate sign bit.
56480ee5cbfSDavid du Colombier */
56580ee5cbfSDavid du Colombier static int
int_decode(uchar ** pp,uchar * pend,int count,int unsgned,int * pint)56680ee5cbfSDavid du Colombier int_decode(uchar** pp, uchar* pend, int count, int unsgned, int* pint)
56780ee5cbfSDavid du Colombier {
56880ee5cbfSDavid du Colombier int err;
56980ee5cbfSDavid du Colombier int num;
57080ee5cbfSDavid du Colombier uchar* p;
57180ee5cbfSDavid du Colombier
57280ee5cbfSDavid du Colombier p = *pp;
57380ee5cbfSDavid du Colombier err = ASN_OK;
57480ee5cbfSDavid du Colombier num = 0;
57580ee5cbfSDavid du Colombier if(p+count <= pend) {
57680ee5cbfSDavid du Colombier if((count > 4) || (unsgned && count == 4 && (*p&0x80)))
57780ee5cbfSDavid du Colombier err = ASN_ETOOBIG;
57880ee5cbfSDavid du Colombier else {
57980ee5cbfSDavid du Colombier if(!unsgned && count > 0 && count < 4 && (*p&0x80))
5802d8b52e8SDavid du Colombier num = -1; /* set all bits, initially */
58180ee5cbfSDavid du Colombier while(count--)
58280ee5cbfSDavid du Colombier num = (num << 8)|(*p++);
58380ee5cbfSDavid du Colombier }
58480ee5cbfSDavid du Colombier }
58580ee5cbfSDavid du Colombier else
58680ee5cbfSDavid du Colombier err = ASN_ESHORT;
58780ee5cbfSDavid du Colombier *pint = num;
58880ee5cbfSDavid du Colombier *pp = p;
58980ee5cbfSDavid du Colombier return err;
59080ee5cbfSDavid du Colombier }
59180ee5cbfSDavid du Colombier
59280ee5cbfSDavid du Colombier /*
59380ee5cbfSDavid du Colombier * Decode an unsigned int in format where each
59480ee5cbfSDavid du Colombier * byte except last has high bit set, and remaining
59580ee5cbfSDavid du Colombier * seven bits of each byte are concatenated to form value.
59680ee5cbfSDavid du Colombier * Although ASN1 allows any size integer, we return
59780ee5cbfSDavid du Colombier * an error if the result doesn't fit in a 32 bit int.
59880ee5cbfSDavid du Colombier */
59980ee5cbfSDavid du Colombier static int
uint7_decode(uchar ** pp,uchar * pend,int * pint)60080ee5cbfSDavid du Colombier uint7_decode(uchar** pp, uchar* pend, int* pint)
60180ee5cbfSDavid du Colombier {
60280ee5cbfSDavid du Colombier int err;
60380ee5cbfSDavid du Colombier int num;
60480ee5cbfSDavid du Colombier int more;
60580ee5cbfSDavid du Colombier int v;
60680ee5cbfSDavid du Colombier uchar* p;
60780ee5cbfSDavid du Colombier
60880ee5cbfSDavid du Colombier p = *pp;
60980ee5cbfSDavid du Colombier err = ASN_OK;
61080ee5cbfSDavid du Colombier num = 0;
61180ee5cbfSDavid du Colombier more = 1;
61280ee5cbfSDavid du Colombier while(more && p < pend) {
61380ee5cbfSDavid du Colombier v = *p++;
61480ee5cbfSDavid du Colombier if(num&0x7F000000) {
61580ee5cbfSDavid du Colombier err = ASN_ETOOBIG;
61680ee5cbfSDavid du Colombier break;
61780ee5cbfSDavid du Colombier }
61880ee5cbfSDavid du Colombier num <<= 7;
61980ee5cbfSDavid du Colombier more = v&0x80;
62080ee5cbfSDavid du Colombier num |= (v&0x7F);
62180ee5cbfSDavid du Colombier }
62280ee5cbfSDavid du Colombier if(p == pend)
62380ee5cbfSDavid du Colombier err = ASN_ESHORT;
62480ee5cbfSDavid du Colombier *pint = num;
62580ee5cbfSDavid du Colombier *pp = p;
62680ee5cbfSDavid du Colombier return err;
62780ee5cbfSDavid du Colombier }
62880ee5cbfSDavid du Colombier
62980ee5cbfSDavid du Colombier /*
63080ee5cbfSDavid du Colombier * Decode an octet string, recursively if isconstr.
63180ee5cbfSDavid du Colombier * We've already checked that length==-1 implies isconstr==1,
63280ee5cbfSDavid du Colombier * and otherwise that specified length fits within (*pp..pend)
63380ee5cbfSDavid du Colombier */
63480ee5cbfSDavid du Colombier static int
octet_decode(uchar ** pp,uchar * pend,int length,int isconstr,Bytes ** pbytes)63580ee5cbfSDavid du Colombier octet_decode(uchar** pp, uchar* pend, int length, int isconstr, Bytes** pbytes)
63680ee5cbfSDavid du Colombier {
63780ee5cbfSDavid du Colombier int err;
63880ee5cbfSDavid du Colombier uchar* p;
63980ee5cbfSDavid du Colombier Bytes* ans;
64080ee5cbfSDavid du Colombier Bytes* newans;
64180ee5cbfSDavid du Colombier uchar* pstart;
64280ee5cbfSDavid du Colombier uchar* pold;
64380ee5cbfSDavid du Colombier Elem elem;
64480ee5cbfSDavid du Colombier
64580ee5cbfSDavid du Colombier err = ASN_OK;
64680ee5cbfSDavid du Colombier p = *pp;
64780ee5cbfSDavid du Colombier ans = nil;
64880ee5cbfSDavid du Colombier if(length >= 0 && !isconstr) {
64980ee5cbfSDavid du Colombier ans = makebytes(p, length);
65080ee5cbfSDavid du Colombier p += length;
65180ee5cbfSDavid du Colombier }
65280ee5cbfSDavid du Colombier else {
65380ee5cbfSDavid du Colombier /* constructed, either definite or indefinite length */
65480ee5cbfSDavid du Colombier pstart = p;
65580ee5cbfSDavid du Colombier for(;;) {
65680ee5cbfSDavid du Colombier if(length >= 0 && p >= pstart + length) {
65780ee5cbfSDavid du Colombier if(p != pstart + length)
65880ee5cbfSDavid du Colombier err = ASN_EVALLEN;
65980ee5cbfSDavid du Colombier break;
66080ee5cbfSDavid du Colombier }
66180ee5cbfSDavid du Colombier pold = p;
66280ee5cbfSDavid du Colombier err = ber_decode(&p, pend, &elem);
66380ee5cbfSDavid du Colombier if(err != ASN_OK)
66480ee5cbfSDavid du Colombier break;
66580ee5cbfSDavid du Colombier switch(elem.val.tag) {
66680ee5cbfSDavid du Colombier case VOctets:
66780ee5cbfSDavid du Colombier newans = catbytes(ans, elem.val.u.octetsval);
66880ee5cbfSDavid du Colombier freebytes(ans);
66980ee5cbfSDavid du Colombier ans = newans;
67080ee5cbfSDavid du Colombier break;
67180ee5cbfSDavid du Colombier
67280ee5cbfSDavid du Colombier case VEOC:
67380ee5cbfSDavid du Colombier if(length != -1) {
67480ee5cbfSDavid du Colombier p = pold;
67580ee5cbfSDavid du Colombier err = ASN_EINVAL;
67680ee5cbfSDavid du Colombier }
67780ee5cbfSDavid du Colombier goto cloop_done;
67880ee5cbfSDavid du Colombier
67980ee5cbfSDavid du Colombier default:
68080ee5cbfSDavid du Colombier p = pold;
68180ee5cbfSDavid du Colombier err = ASN_EINVAL;
68280ee5cbfSDavid du Colombier goto cloop_done;
68380ee5cbfSDavid du Colombier }
68480ee5cbfSDavid du Colombier }
68580ee5cbfSDavid du Colombier cloop_done:
68680ee5cbfSDavid du Colombier ;
68780ee5cbfSDavid du Colombier }
68880ee5cbfSDavid du Colombier *pp = p;
68980ee5cbfSDavid du Colombier *pbytes = ans;
69080ee5cbfSDavid du Colombier return err;
69180ee5cbfSDavid du Colombier }
69280ee5cbfSDavid du Colombier
69380ee5cbfSDavid du Colombier /*
69480ee5cbfSDavid du Colombier * Decode a sequence or set.
69580ee5cbfSDavid du Colombier * We've already checked that length==-1 implies isconstr==1,
69680ee5cbfSDavid du Colombier * and otherwise that specified length fits within (*p..pend)
69780ee5cbfSDavid du Colombier */
69880ee5cbfSDavid du Colombier static int
seq_decode(uchar ** pp,uchar * pend,int length,int isconstr,Elist ** pelist)69980ee5cbfSDavid du Colombier seq_decode(uchar** pp, uchar* pend, int length, int isconstr, Elist** pelist)
70080ee5cbfSDavid du Colombier {
70180ee5cbfSDavid du Colombier int err;
70280ee5cbfSDavid du Colombier uchar* p;
70380ee5cbfSDavid du Colombier uchar* pstart;
70480ee5cbfSDavid du Colombier uchar* pold;
70580ee5cbfSDavid du Colombier Elist* ans;
70680ee5cbfSDavid du Colombier Elem elem;
70780ee5cbfSDavid du Colombier Elist* lve;
70880ee5cbfSDavid du Colombier Elist* lveold;
70980ee5cbfSDavid du Colombier
71080ee5cbfSDavid du Colombier err = ASN_OK;
71180ee5cbfSDavid du Colombier ans = nil;
71280ee5cbfSDavid du Colombier p = *pp;
71380ee5cbfSDavid du Colombier if(!isconstr)
71480ee5cbfSDavid du Colombier err = ASN_EPRIM;
71580ee5cbfSDavid du Colombier else {
71680ee5cbfSDavid du Colombier /* constructed, either definite or indefinite length */
71780ee5cbfSDavid du Colombier lve = nil;
71880ee5cbfSDavid du Colombier pstart = p;
71980ee5cbfSDavid du Colombier for(;;) {
72080ee5cbfSDavid du Colombier if(length >= 0 && p >= pstart + length) {
72180ee5cbfSDavid du Colombier if(p != pstart + length)
72280ee5cbfSDavid du Colombier err = ASN_EVALLEN;
72380ee5cbfSDavid du Colombier break;
72480ee5cbfSDavid du Colombier }
72580ee5cbfSDavid du Colombier pold = p;
72680ee5cbfSDavid du Colombier err = ber_decode(&p, pend, &elem);
72780ee5cbfSDavid du Colombier if(err != ASN_OK)
72880ee5cbfSDavid du Colombier break;
72980ee5cbfSDavid du Colombier if(elem.val.tag == VEOC) {
73080ee5cbfSDavid du Colombier if(length != -1) {
73180ee5cbfSDavid du Colombier p = pold;
73280ee5cbfSDavid du Colombier err = ASN_EINVAL;
73380ee5cbfSDavid du Colombier }
73480ee5cbfSDavid du Colombier break;
73580ee5cbfSDavid du Colombier }
73680ee5cbfSDavid du Colombier else
737d9306527SDavid du Colombier lve = mkel(elem, lve);
73880ee5cbfSDavid du Colombier }
73980ee5cbfSDavid du Colombier if(err == ASN_OK) {
74080ee5cbfSDavid du Colombier /* reverse back to original order */
74180ee5cbfSDavid du Colombier while(lve != nil) {
74280ee5cbfSDavid du Colombier lveold = lve;
74380ee5cbfSDavid du Colombier lve = lve->tl;
74480ee5cbfSDavid du Colombier lveold->tl = ans;
74580ee5cbfSDavid du Colombier ans = lveold;
74680ee5cbfSDavid du Colombier }
74780ee5cbfSDavid du Colombier }
74880ee5cbfSDavid du Colombier }
74980ee5cbfSDavid du Colombier *pp = p;
75080ee5cbfSDavid du Colombier *pelist = ans;
7519027b8f7SDavid du Colombier setmalloctag(ans, getcallerpc(&pp));
75280ee5cbfSDavid du Colombier return err;
75380ee5cbfSDavid du Colombier }
75480ee5cbfSDavid du Colombier
75580ee5cbfSDavid du Colombier /*
75680ee5cbfSDavid du Colombier * Encode e by BER rules, putting answer in *pbytes.
75780ee5cbfSDavid du Colombier * This is done by first calling enc with lenonly==1
75880ee5cbfSDavid du Colombier * to get the length of the needed buffer,
75980ee5cbfSDavid du Colombier * then allocating the buffer and using enc again to fill it up.
76080ee5cbfSDavid du Colombier */
76180ee5cbfSDavid du Colombier static int
encode(Elem e,Bytes ** pbytes)76280ee5cbfSDavid du Colombier encode(Elem e, Bytes** pbytes)
76380ee5cbfSDavid du Colombier {
76480ee5cbfSDavid du Colombier uchar* p;
76580ee5cbfSDavid du Colombier Bytes* ans;
76680ee5cbfSDavid du Colombier int err;
76780ee5cbfSDavid du Colombier uchar uc;
76880ee5cbfSDavid du Colombier
76980ee5cbfSDavid du Colombier p = &uc;
77080ee5cbfSDavid du Colombier err = enc(&p, e, 1);
77180ee5cbfSDavid du Colombier if(err == ASN_OK) {
77280ee5cbfSDavid du Colombier ans = newbytes(p-&uc);
77380ee5cbfSDavid du Colombier p = ans->data;
77480ee5cbfSDavid du Colombier err = enc(&p, e, 0);
77580ee5cbfSDavid du Colombier *pbytes = ans;
77680ee5cbfSDavid du Colombier }
77780ee5cbfSDavid du Colombier return err;
77880ee5cbfSDavid du Colombier }
77980ee5cbfSDavid du Colombier
78080ee5cbfSDavid du Colombier /*
78180ee5cbfSDavid du Colombier * The various enc functions take a pointer to a pointer
78280ee5cbfSDavid du Colombier * into a buffer, and encode their entity starting there,
78380ee5cbfSDavid du Colombier * updating the pointer afterwards.
78480ee5cbfSDavid du Colombier * If lenonly is 1, only the pointer update is done,
78580ee5cbfSDavid du Colombier * allowing enc to be called first to calculate the needed
78680ee5cbfSDavid du Colombier * buffer length.
78780ee5cbfSDavid du Colombier * If lenonly is 0, it is assumed that the answer will fit.
78880ee5cbfSDavid du Colombier */
78980ee5cbfSDavid du Colombier
79080ee5cbfSDavid du Colombier static int
enc(uchar ** pp,Elem e,int lenonly)79180ee5cbfSDavid du Colombier enc(uchar** pp, Elem e, int lenonly)
79280ee5cbfSDavid du Colombier {
79380ee5cbfSDavid du Colombier int err;
79480ee5cbfSDavid du Colombier int vlen;
79580ee5cbfSDavid du Colombier int constr;
79680ee5cbfSDavid du Colombier Tag tag;
79780ee5cbfSDavid du Colombier int v;
79880ee5cbfSDavid du Colombier int ilen;
79980ee5cbfSDavid du Colombier uchar* p;
80080ee5cbfSDavid du Colombier uchar* psave;
80180ee5cbfSDavid du Colombier
80280ee5cbfSDavid du Colombier p = *pp;
80380ee5cbfSDavid du Colombier err = val_enc(&p, e, &constr, 1);
80480ee5cbfSDavid du Colombier if(err != ASN_OK)
80580ee5cbfSDavid du Colombier return err;
80680ee5cbfSDavid du Colombier vlen = p - *pp;
80780ee5cbfSDavid du Colombier p = *pp;
80880ee5cbfSDavid du Colombier tag = e.tag;
80980ee5cbfSDavid du Colombier v = tag.class|constr;
81080ee5cbfSDavid du Colombier if(tag.num < 31) {
81180ee5cbfSDavid du Colombier if(!lenonly)
81280ee5cbfSDavid du Colombier *p = (v|tag.num);
81380ee5cbfSDavid du Colombier p++;
81480ee5cbfSDavid du Colombier }
81580ee5cbfSDavid du Colombier else {
81680ee5cbfSDavid du Colombier if(!lenonly)
81780ee5cbfSDavid du Colombier *p = (v|31);
81880ee5cbfSDavid du Colombier p++;
81980ee5cbfSDavid du Colombier if(tag.num < 0)
82080ee5cbfSDavid du Colombier return ASN_EINVAL;
82180ee5cbfSDavid du Colombier uint7_enc(&p, tag.num, lenonly);
82280ee5cbfSDavid du Colombier }
82380ee5cbfSDavid du Colombier if(vlen < 0x80) {
82480ee5cbfSDavid du Colombier if(!lenonly)
82580ee5cbfSDavid du Colombier *p = vlen;
82680ee5cbfSDavid du Colombier p++;
82780ee5cbfSDavid du Colombier }
82880ee5cbfSDavid du Colombier else {
82980ee5cbfSDavid du Colombier psave = p;
83080ee5cbfSDavid du Colombier int_enc(&p, vlen, 1, 1);
83180ee5cbfSDavid du Colombier ilen = p-psave;
83280ee5cbfSDavid du Colombier p = psave;
83380ee5cbfSDavid du Colombier if(!lenonly) {
83480ee5cbfSDavid du Colombier *p++ = (0x80 | ilen);
83580ee5cbfSDavid du Colombier int_enc(&p, vlen, 1, 0);
83680ee5cbfSDavid du Colombier }
83780ee5cbfSDavid du Colombier else
83880ee5cbfSDavid du Colombier p += 1 + ilen;
83980ee5cbfSDavid du Colombier }
84080ee5cbfSDavid du Colombier if(!lenonly)
84180ee5cbfSDavid du Colombier val_enc(&p, e, &constr, 0);
84280ee5cbfSDavid du Colombier else
84380ee5cbfSDavid du Colombier p += vlen;
84480ee5cbfSDavid du Colombier *pp = p;
84580ee5cbfSDavid du Colombier return err;
84680ee5cbfSDavid du Colombier }
84780ee5cbfSDavid du Colombier
84880ee5cbfSDavid du Colombier static int
val_enc(uchar ** pp,Elem e,int * pconstr,int lenonly)84980ee5cbfSDavid du Colombier val_enc(uchar** pp, Elem e, int *pconstr, int lenonly)
85080ee5cbfSDavid du Colombier {
85180ee5cbfSDavid du Colombier int err;
85280ee5cbfSDavid du Colombier uchar* p;
85380ee5cbfSDavid du Colombier int kind;
85480ee5cbfSDavid du Colombier int cl;
85580ee5cbfSDavid du Colombier int v;
85680ee5cbfSDavid du Colombier Bytes* bb = nil;
85780ee5cbfSDavid du Colombier Bits* bits;
85880ee5cbfSDavid du Colombier Ints* oid;
85980ee5cbfSDavid du Colombier int k;
86080ee5cbfSDavid du Colombier Elist* el;
86180ee5cbfSDavid du Colombier char* s;
86280ee5cbfSDavid du Colombier
86380ee5cbfSDavid du Colombier p = *pp;
86480ee5cbfSDavid du Colombier err = ASN_OK;
86580ee5cbfSDavid du Colombier kind = e.tag.num;
86680ee5cbfSDavid du Colombier cl = e.tag.class;
86780ee5cbfSDavid du Colombier *pconstr = 0;
86880ee5cbfSDavid du Colombier if(cl != Universal) {
86980ee5cbfSDavid du Colombier switch(e.val.tag) {
87080ee5cbfSDavid du Colombier case VBool:
87180ee5cbfSDavid du Colombier kind = BOOLEAN;
87280ee5cbfSDavid du Colombier break;
87380ee5cbfSDavid du Colombier case VInt:
87480ee5cbfSDavid du Colombier kind = INTEGER;
87580ee5cbfSDavid du Colombier break;
87680ee5cbfSDavid du Colombier case VBigInt:
87780ee5cbfSDavid du Colombier kind = INTEGER;
87880ee5cbfSDavid du Colombier break;
87980ee5cbfSDavid du Colombier case VOctets:
88080ee5cbfSDavid du Colombier kind = OCTET_STRING;
88180ee5cbfSDavid du Colombier break;
88280ee5cbfSDavid du Colombier case VReal:
88380ee5cbfSDavid du Colombier kind = REAL;
88480ee5cbfSDavid du Colombier break;
88580ee5cbfSDavid du Colombier case VOther:
88680ee5cbfSDavid du Colombier kind = OCTET_STRING;
88780ee5cbfSDavid du Colombier break;
88880ee5cbfSDavid du Colombier case VBitString:
88980ee5cbfSDavid du Colombier kind = BIT_STRING;
89080ee5cbfSDavid du Colombier break;
89180ee5cbfSDavid du Colombier case VNull:
89280ee5cbfSDavid du Colombier kind = NULLTAG;
89380ee5cbfSDavid du Colombier break;
89480ee5cbfSDavid du Colombier case VObjId:
89580ee5cbfSDavid du Colombier kind = OBJECT_ID;
89680ee5cbfSDavid du Colombier break;
89780ee5cbfSDavid du Colombier case VString:
89880ee5cbfSDavid du Colombier kind = UniversalString;
89980ee5cbfSDavid du Colombier break;
90080ee5cbfSDavid du Colombier case VSeq:
90180ee5cbfSDavid du Colombier kind = SEQUENCE;
90280ee5cbfSDavid du Colombier break;
90380ee5cbfSDavid du Colombier case VSet:
9049a747e4fSDavid du Colombier kind = SETOF;
90580ee5cbfSDavid du Colombier break;
90680ee5cbfSDavid du Colombier }
90780ee5cbfSDavid du Colombier }
90880ee5cbfSDavid du Colombier switch(kind) {
90980ee5cbfSDavid du Colombier case BOOLEAN:
91080ee5cbfSDavid du Colombier if(is_int(&e, &v)) {
91180ee5cbfSDavid du Colombier if(v != 0)
91280ee5cbfSDavid du Colombier v = 255;
91380ee5cbfSDavid du Colombier int_enc(&p, v, 1, lenonly);
91480ee5cbfSDavid du Colombier }
91580ee5cbfSDavid du Colombier else
91680ee5cbfSDavid du Colombier err = ASN_EINVAL;
91780ee5cbfSDavid du Colombier break;
91880ee5cbfSDavid du Colombier
91980ee5cbfSDavid du Colombier case INTEGER:
92080ee5cbfSDavid du Colombier case ENUMERATED:
92180ee5cbfSDavid du Colombier if(is_int(&e, &v))
92280ee5cbfSDavid du Colombier int_enc(&p, v, 0, lenonly);
92380ee5cbfSDavid du Colombier else {
92480ee5cbfSDavid du Colombier if(is_bigint(&e, &bb)) {
92580ee5cbfSDavid du Colombier if(!lenonly)
92680ee5cbfSDavid du Colombier memmove(p, bb->data, bb->len);
92780ee5cbfSDavid du Colombier p += bb->len;
92880ee5cbfSDavid du Colombier }
92980ee5cbfSDavid du Colombier else
93080ee5cbfSDavid du Colombier err = ASN_EINVAL;
93180ee5cbfSDavid du Colombier }
93280ee5cbfSDavid du Colombier break;
93380ee5cbfSDavid du Colombier
93480ee5cbfSDavid du Colombier case BIT_STRING:
93580ee5cbfSDavid du Colombier if(is_bitstring(&e, &bits)) {
93680ee5cbfSDavid du Colombier if(bits->len == 0) {
93780ee5cbfSDavid du Colombier if(!lenonly)
93880ee5cbfSDavid du Colombier *p = 0;
93980ee5cbfSDavid du Colombier p++;
94080ee5cbfSDavid du Colombier }
94180ee5cbfSDavid du Colombier else {
94280ee5cbfSDavid du Colombier v = bits->unusedbits;
94380ee5cbfSDavid du Colombier if(v < 0 || v > 7)
94480ee5cbfSDavid du Colombier err = ASN_EINVAL;
94580ee5cbfSDavid du Colombier else {
94680ee5cbfSDavid du Colombier if(!lenonly) {
94780ee5cbfSDavid du Colombier *p = v;
94880ee5cbfSDavid du Colombier memmove(p+1, bits->data, bits->len);
94980ee5cbfSDavid du Colombier }
95080ee5cbfSDavid du Colombier p += 1 + bits->len;
95180ee5cbfSDavid du Colombier }
95280ee5cbfSDavid du Colombier }
95380ee5cbfSDavid du Colombier }
95480ee5cbfSDavid du Colombier else
95580ee5cbfSDavid du Colombier err = ASN_EINVAL;
95680ee5cbfSDavid du Colombier break;
95780ee5cbfSDavid du Colombier
95880ee5cbfSDavid du Colombier case OCTET_STRING:
95980ee5cbfSDavid du Colombier case ObjectDescriptor:
96080ee5cbfSDavid du Colombier case EXTERNAL:
96180ee5cbfSDavid du Colombier case REAL:
96280ee5cbfSDavid du Colombier case EMBEDDED_PDV:
96380ee5cbfSDavid du Colombier bb = nil;
96480ee5cbfSDavid du Colombier switch(e.val.tag) {
96580ee5cbfSDavid du Colombier case VOctets:
96680ee5cbfSDavid du Colombier bb = e.val.u.octetsval;
96780ee5cbfSDavid du Colombier break;
96880ee5cbfSDavid du Colombier case VReal:
96980ee5cbfSDavid du Colombier bb = e.val.u.realval;
97080ee5cbfSDavid du Colombier break;
97180ee5cbfSDavid du Colombier case VOther:
97280ee5cbfSDavid du Colombier bb = e.val.u.otherval;
97380ee5cbfSDavid du Colombier break;
97480ee5cbfSDavid du Colombier }
97580ee5cbfSDavid du Colombier if(bb != nil) {
97680ee5cbfSDavid du Colombier if(!lenonly)
97780ee5cbfSDavid du Colombier memmove(p, bb->data, bb->len);
97880ee5cbfSDavid du Colombier p += bb->len;
97980ee5cbfSDavid du Colombier }
98080ee5cbfSDavid du Colombier else
98180ee5cbfSDavid du Colombier err = ASN_EINVAL;
98280ee5cbfSDavid du Colombier break;
98380ee5cbfSDavid du Colombier
98480ee5cbfSDavid du Colombier case NULLTAG:
98580ee5cbfSDavid du Colombier break;
98680ee5cbfSDavid du Colombier
98780ee5cbfSDavid du Colombier case OBJECT_ID:
98880ee5cbfSDavid du Colombier if(is_oid(&e, &oid)) {
98980ee5cbfSDavid du Colombier for(k = 0; k < oid->len; k++) {
99080ee5cbfSDavid du Colombier v = oid->data[k];
99180ee5cbfSDavid du Colombier if(k == 0) {
99280ee5cbfSDavid du Colombier v *= 40;
99380ee5cbfSDavid du Colombier if(oid->len > 1)
99480ee5cbfSDavid du Colombier v += oid->data[++k];
99580ee5cbfSDavid du Colombier }
99680ee5cbfSDavid du Colombier uint7_enc(&p, v, lenonly);
99780ee5cbfSDavid du Colombier }
99880ee5cbfSDavid du Colombier }
99980ee5cbfSDavid du Colombier else
100080ee5cbfSDavid du Colombier err = ASN_EINVAL;
100180ee5cbfSDavid du Colombier break;
100280ee5cbfSDavid du Colombier
100380ee5cbfSDavid du Colombier case SEQUENCE:
10049a747e4fSDavid du Colombier case SETOF:
100580ee5cbfSDavid du Colombier el = nil;
100680ee5cbfSDavid du Colombier if(e.val.tag == VSeq)
100780ee5cbfSDavid du Colombier el = e.val.u.seqval;
100880ee5cbfSDavid du Colombier else if(e.val.tag == VSet)
100980ee5cbfSDavid du Colombier el = e.val.u.setval;
101080ee5cbfSDavid du Colombier else
101180ee5cbfSDavid du Colombier err = ASN_EINVAL;
101280ee5cbfSDavid du Colombier if(el != nil) {
101380ee5cbfSDavid du Colombier *pconstr = CONSTR_MASK;
101480ee5cbfSDavid du Colombier for(; el != nil; el = el->tl) {
101580ee5cbfSDavid du Colombier err = enc(&p, el->hd, lenonly);
101680ee5cbfSDavid du Colombier if(err != ASN_OK)
101780ee5cbfSDavid du Colombier break;
101880ee5cbfSDavid du Colombier }
101980ee5cbfSDavid du Colombier }
102080ee5cbfSDavid du Colombier break;
102180ee5cbfSDavid du Colombier
1022de8abbc9SDavid du Colombier case UTF8String:
102380ee5cbfSDavid du Colombier case NumericString:
102480ee5cbfSDavid du Colombier case PrintableString:
102580ee5cbfSDavid du Colombier case TeletexString:
102680ee5cbfSDavid du Colombier case VideotexString:
102780ee5cbfSDavid du Colombier case IA5String:
102880ee5cbfSDavid du Colombier case UTCTime:
102980ee5cbfSDavid du Colombier case GeneralizedTime:
103080ee5cbfSDavid du Colombier case GraphicString:
103180ee5cbfSDavid du Colombier case VisibleString:
103280ee5cbfSDavid du Colombier case GeneralString:
103380ee5cbfSDavid du Colombier case UniversalString:
103480ee5cbfSDavid du Colombier case BMPString:
103580ee5cbfSDavid du Colombier if(e.val.tag == VString) {
103680ee5cbfSDavid du Colombier s = e.val.u.stringval;
103780ee5cbfSDavid du Colombier if(s != nil) {
103880ee5cbfSDavid du Colombier v = strlen(s);
1039d9306527SDavid du Colombier if(!lenonly)
104080ee5cbfSDavid du Colombier memmove(p, s, v);
104180ee5cbfSDavid du Colombier p += v;
104280ee5cbfSDavid du Colombier }
104380ee5cbfSDavid du Colombier }
104480ee5cbfSDavid du Colombier else
104580ee5cbfSDavid du Colombier err = ASN_EINVAL;
104680ee5cbfSDavid du Colombier break;
104780ee5cbfSDavid du Colombier
104880ee5cbfSDavid du Colombier default:
104980ee5cbfSDavid du Colombier err = ASN_EINVAL;
105080ee5cbfSDavid du Colombier }
105180ee5cbfSDavid du Colombier *pp = p;
105280ee5cbfSDavid du Colombier return err;
105380ee5cbfSDavid du Colombier }
105480ee5cbfSDavid du Colombier
105580ee5cbfSDavid du Colombier /*
105680ee5cbfSDavid du Colombier * Encode num as unsigned 7 bit values with top bit 1 on all bytes
105780ee5cbfSDavid du Colombier * except last, only putting in bytes if !lenonly.
105880ee5cbfSDavid du Colombier */
105980ee5cbfSDavid du Colombier static void
uint7_enc(uchar ** pp,int num,int lenonly)106080ee5cbfSDavid du Colombier uint7_enc(uchar** pp, int num, int lenonly)
106180ee5cbfSDavid du Colombier {
106280ee5cbfSDavid du Colombier int n;
106380ee5cbfSDavid du Colombier int v;
106480ee5cbfSDavid du Colombier int k;
106580ee5cbfSDavid du Colombier uchar* p;
106680ee5cbfSDavid du Colombier
106780ee5cbfSDavid du Colombier p = *pp;
106880ee5cbfSDavid du Colombier n = 1;
106980ee5cbfSDavid du Colombier v = num >> 7;
107080ee5cbfSDavid du Colombier while(v > 0) {
107180ee5cbfSDavid du Colombier v >>= 7;
107280ee5cbfSDavid du Colombier n++;
107380ee5cbfSDavid du Colombier }
107480ee5cbfSDavid du Colombier if(lenonly)
107580ee5cbfSDavid du Colombier p += n;
107680ee5cbfSDavid du Colombier else {
107780ee5cbfSDavid du Colombier for(k = (n - 1)*7; k > 0; k -= 7)
107880ee5cbfSDavid du Colombier *p++= ((num >> k)|0x80);
107980ee5cbfSDavid du Colombier *p++ = (num&0x7F);
108080ee5cbfSDavid du Colombier }
108180ee5cbfSDavid du Colombier *pp = p;
108280ee5cbfSDavid du Colombier }
108380ee5cbfSDavid du Colombier
108480ee5cbfSDavid du Colombier /*
108580ee5cbfSDavid du Colombier * Encode num as unsigned or signed integer,
108680ee5cbfSDavid du Colombier * only putting in bytes if !lenonly.
108780ee5cbfSDavid du Colombier * Encoding is length followed by bytes to concatenate.
108880ee5cbfSDavid du Colombier */
108980ee5cbfSDavid du Colombier static void
int_enc(uchar ** pp,int num,int unsgned,int lenonly)109080ee5cbfSDavid du Colombier int_enc(uchar** pp, int num, int unsgned, int lenonly)
109180ee5cbfSDavid du Colombier {
109280ee5cbfSDavid du Colombier int v;
109380ee5cbfSDavid du Colombier int n;
109480ee5cbfSDavid du Colombier int prevv;
109580ee5cbfSDavid du Colombier int k;
109680ee5cbfSDavid du Colombier uchar* p;
109780ee5cbfSDavid du Colombier
109880ee5cbfSDavid du Colombier p = *pp;
109980ee5cbfSDavid du Colombier v = num;
110080ee5cbfSDavid du Colombier if(v < 0)
110180ee5cbfSDavid du Colombier v = -(v + 1);
110280ee5cbfSDavid du Colombier n = 1;
110380ee5cbfSDavid du Colombier prevv = v;
110480ee5cbfSDavid du Colombier v >>= 8;
110580ee5cbfSDavid du Colombier while(v > 0) {
110680ee5cbfSDavid du Colombier prevv = v;
110780ee5cbfSDavid du Colombier v >>= 8;
110880ee5cbfSDavid du Colombier n++;
110980ee5cbfSDavid du Colombier }
111080ee5cbfSDavid du Colombier if(!unsgned && (prevv&0x80))
111180ee5cbfSDavid du Colombier n++;
111280ee5cbfSDavid du Colombier if(lenonly)
111380ee5cbfSDavid du Colombier p += n;
111480ee5cbfSDavid du Colombier else {
111580ee5cbfSDavid du Colombier for(k = (n - 1)*8; k >= 0; k -= 8)
111680ee5cbfSDavid du Colombier *p++ = (num >> k);
111780ee5cbfSDavid du Colombier }
111880ee5cbfSDavid du Colombier *pp = p;
111980ee5cbfSDavid du Colombier }
112080ee5cbfSDavid du Colombier
112180ee5cbfSDavid du Colombier static int
ints_eq(Ints * a,Ints * b)112280ee5cbfSDavid du Colombier ints_eq(Ints* a, Ints* b)
112380ee5cbfSDavid du Colombier {
112480ee5cbfSDavid du Colombier int alen;
112580ee5cbfSDavid du Colombier int i;
112680ee5cbfSDavid du Colombier
112780ee5cbfSDavid du Colombier alen = a->len;
112880ee5cbfSDavid du Colombier if(alen != b->len)
112980ee5cbfSDavid du Colombier return 0;
113080ee5cbfSDavid du Colombier for(i = 0; i < alen; i++)
113180ee5cbfSDavid du Colombier if(a->data[i] != b->data[i])
113280ee5cbfSDavid du Colombier return 0;
113380ee5cbfSDavid du Colombier return 1;
113480ee5cbfSDavid du Colombier }
113580ee5cbfSDavid du Colombier
113680ee5cbfSDavid du Colombier /*
113780ee5cbfSDavid du Colombier * Look up o in tab (which must have nil entry to terminate).
113880ee5cbfSDavid du Colombier * Return index of matching entry, or -1 if none.
113980ee5cbfSDavid du Colombier */
114080ee5cbfSDavid du Colombier static int
oid_lookup(Ints * o,Ints ** tab)114180ee5cbfSDavid du Colombier oid_lookup(Ints* o, Ints** tab)
114280ee5cbfSDavid du Colombier {
114380ee5cbfSDavid du Colombier int i;
114480ee5cbfSDavid du Colombier
114580ee5cbfSDavid du Colombier for(i = 0; tab[i] != nil; i++)
114680ee5cbfSDavid du Colombier if(ints_eq(o, tab[i]))
114780ee5cbfSDavid du Colombier return i;
114880ee5cbfSDavid du Colombier return -1;
114980ee5cbfSDavid du Colombier }
115080ee5cbfSDavid du Colombier
115180ee5cbfSDavid du Colombier /*
115280ee5cbfSDavid du Colombier * Return true if *pe is a SEQUENCE, and set *pseq to
115380ee5cbfSDavid du Colombier * the value of the sequence if so.
115480ee5cbfSDavid du Colombier */
115580ee5cbfSDavid du Colombier static int
is_seq(Elem * pe,Elist ** pseq)115680ee5cbfSDavid du Colombier is_seq(Elem* pe, Elist** pseq)
115780ee5cbfSDavid du Colombier {
115880ee5cbfSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == SEQUENCE && pe->val.tag == VSeq) {
115980ee5cbfSDavid du Colombier *pseq = pe->val.u.seqval;
116080ee5cbfSDavid du Colombier return 1;
116180ee5cbfSDavid du Colombier }
116280ee5cbfSDavid du Colombier return 0;
116380ee5cbfSDavid du Colombier }
116480ee5cbfSDavid du Colombier
116580ee5cbfSDavid du Colombier static int
is_set(Elem * pe,Elist ** pset)116680ee5cbfSDavid du Colombier is_set(Elem* pe, Elist** pset)
116780ee5cbfSDavid du Colombier {
11689a747e4fSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == SETOF && pe->val.tag == VSet) {
116980ee5cbfSDavid du Colombier *pset = pe->val.u.setval;
117080ee5cbfSDavid du Colombier return 1;
117180ee5cbfSDavid du Colombier }
117280ee5cbfSDavid du Colombier return 0;
117380ee5cbfSDavid du Colombier }
117480ee5cbfSDavid du Colombier
117580ee5cbfSDavid du Colombier static int
is_int(Elem * pe,int * pint)117680ee5cbfSDavid du Colombier is_int(Elem* pe, int* pint)
117780ee5cbfSDavid du Colombier {
117880ee5cbfSDavid du Colombier if(pe->tag.class == Universal) {
117980ee5cbfSDavid du Colombier if(pe->tag.num == INTEGER && pe->val.tag == VInt) {
118080ee5cbfSDavid du Colombier *pint = pe->val.u.intval;
118180ee5cbfSDavid du Colombier return 1;
118280ee5cbfSDavid du Colombier }
118380ee5cbfSDavid du Colombier else if(pe->tag.num == BOOLEAN && pe->val.tag == VBool) {
118480ee5cbfSDavid du Colombier *pint = pe->val.u.boolval;
118580ee5cbfSDavid du Colombier return 1;
118680ee5cbfSDavid du Colombier }
118780ee5cbfSDavid du Colombier }
118880ee5cbfSDavid du Colombier return 0;
118980ee5cbfSDavid du Colombier }
119080ee5cbfSDavid du Colombier
11919a747e4fSDavid du Colombier /*
11929a747e4fSDavid du Colombier * for convience, all VInt's are readable via this routine,
11939a747e4fSDavid du Colombier * as well as all VBigInt's
11949a747e4fSDavid du Colombier */
119580ee5cbfSDavid du Colombier static int
is_bigint(Elem * pe,Bytes ** pbigint)119680ee5cbfSDavid du Colombier is_bigint(Elem* pe, Bytes** pbigint)
119780ee5cbfSDavid du Colombier {
11989a747e4fSDavid du Colombier int v, n, i;
11999a747e4fSDavid du Colombier
12009a747e4fSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == INTEGER) {
12019a747e4fSDavid du Colombier if(pe->val.tag == VBigInt)
120280ee5cbfSDavid du Colombier *pbigint = pe->val.u.bigintval;
12039a747e4fSDavid du Colombier else if(pe->val.tag == VInt){
12049a747e4fSDavid du Colombier v = pe->val.u.intval;
12059a747e4fSDavid du Colombier for(n = 1; n < 4; n++)
12069a747e4fSDavid du Colombier if((1 << (8 * n)) > v)
12079a747e4fSDavid du Colombier break;
12089a747e4fSDavid du Colombier *pbigint = newbytes(n);
12099a747e4fSDavid du Colombier for(i = 0; i < n; i++)
12109a747e4fSDavid du Colombier (*pbigint)->data[i] = (v >> ((n - 1 - i) * 8));
12119a747e4fSDavid du Colombier }else
12129a747e4fSDavid du Colombier return 0;
121380ee5cbfSDavid du Colombier return 1;
121480ee5cbfSDavid du Colombier }
121580ee5cbfSDavid du Colombier return 0;
121680ee5cbfSDavid du Colombier }
121780ee5cbfSDavid du Colombier
121880ee5cbfSDavid du Colombier static int
is_bitstring(Elem * pe,Bits ** pbits)121980ee5cbfSDavid du Colombier is_bitstring(Elem* pe, Bits** pbits)
122080ee5cbfSDavid du Colombier {
122180ee5cbfSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == BIT_STRING && pe->val.tag == VBitString) {
122280ee5cbfSDavid du Colombier *pbits = pe->val.u.bitstringval;
122380ee5cbfSDavid du Colombier return 1;
122480ee5cbfSDavid du Colombier }
122580ee5cbfSDavid du Colombier return 0;
122680ee5cbfSDavid du Colombier }
122780ee5cbfSDavid du Colombier
122880ee5cbfSDavid du Colombier static int
is_octetstring(Elem * pe,Bytes ** poctets)122980ee5cbfSDavid du Colombier is_octetstring(Elem* pe, Bytes** poctets)
123080ee5cbfSDavid du Colombier {
123180ee5cbfSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == OCTET_STRING && pe->val.tag == VOctets) {
123280ee5cbfSDavid du Colombier *poctets = pe->val.u.octetsval;
123380ee5cbfSDavid du Colombier return 1;
123480ee5cbfSDavid du Colombier }
123580ee5cbfSDavid du Colombier return 0;
123680ee5cbfSDavid du Colombier }
123780ee5cbfSDavid du Colombier
123880ee5cbfSDavid du Colombier static int
is_oid(Elem * pe,Ints ** poid)123980ee5cbfSDavid du Colombier is_oid(Elem* pe, Ints** poid)
124080ee5cbfSDavid du Colombier {
124180ee5cbfSDavid du Colombier if(pe->tag.class == Universal && pe->tag.num == OBJECT_ID && pe->val.tag == VObjId) {
124280ee5cbfSDavid du Colombier *poid = pe->val.u.objidval;
124380ee5cbfSDavid du Colombier return 1;
124480ee5cbfSDavid du Colombier }
124580ee5cbfSDavid du Colombier return 0;
124680ee5cbfSDavid du Colombier }
124780ee5cbfSDavid du Colombier
124880ee5cbfSDavid du Colombier static int
is_string(Elem * pe,char ** pstring)124980ee5cbfSDavid du Colombier is_string(Elem* pe, char** pstring)
125080ee5cbfSDavid du Colombier {
125180ee5cbfSDavid du Colombier if(pe->tag.class == Universal) {
125280ee5cbfSDavid du Colombier switch(pe->tag.num) {
1253de8abbc9SDavid du Colombier case UTF8String:
125480ee5cbfSDavid du Colombier case NumericString:
125580ee5cbfSDavid du Colombier case PrintableString:
125680ee5cbfSDavid du Colombier case TeletexString:
125780ee5cbfSDavid du Colombier case VideotexString:
125880ee5cbfSDavid du Colombier case IA5String:
125980ee5cbfSDavid du Colombier case GraphicString:
126080ee5cbfSDavid du Colombier case VisibleString:
126180ee5cbfSDavid du Colombier case GeneralString:
126280ee5cbfSDavid du Colombier case UniversalString:
126380ee5cbfSDavid du Colombier case BMPString:
126480ee5cbfSDavid du Colombier if(pe->val.tag == VString) {
126580ee5cbfSDavid du Colombier *pstring = pe->val.u.stringval;
126680ee5cbfSDavid du Colombier return 1;
126780ee5cbfSDavid du Colombier }
126880ee5cbfSDavid du Colombier }
126980ee5cbfSDavid du Colombier }
127080ee5cbfSDavid du Colombier return 0;
127180ee5cbfSDavid du Colombier }
127280ee5cbfSDavid du Colombier
127380ee5cbfSDavid du Colombier static int
is_time(Elem * pe,char ** ptime)127480ee5cbfSDavid du Colombier is_time(Elem* pe, char** ptime)
127580ee5cbfSDavid du Colombier {
127680ee5cbfSDavid du Colombier if(pe->tag.class == Universal
127780ee5cbfSDavid du Colombier && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
127880ee5cbfSDavid du Colombier && pe->val.tag == VString) {
127980ee5cbfSDavid du Colombier *ptime = pe->val.u.stringval;
128080ee5cbfSDavid du Colombier return 1;
128180ee5cbfSDavid du Colombier }
128280ee5cbfSDavid du Colombier return 0;
128380ee5cbfSDavid du Colombier }
128480ee5cbfSDavid du Colombier
128580ee5cbfSDavid du Colombier
128680ee5cbfSDavid du Colombier /*
128780ee5cbfSDavid du Colombier * malloc and return a new Bytes structure capable of
128880ee5cbfSDavid du Colombier * holding len bytes. (len >= 0)
128980ee5cbfSDavid du Colombier */
129080ee5cbfSDavid du Colombier static Bytes*
newbytes(int len)129180ee5cbfSDavid du Colombier newbytes(int len)
129280ee5cbfSDavid du Colombier {
129380ee5cbfSDavid du Colombier Bytes* ans;
129480ee5cbfSDavid du Colombier
1295d9306527SDavid du Colombier ans = (Bytes*)emalloc(OFFSETOF(data[0], Bytes) + len);
129680ee5cbfSDavid du Colombier ans->len = len;
129780ee5cbfSDavid du Colombier return ans;
129880ee5cbfSDavid du Colombier }
129980ee5cbfSDavid du Colombier
130080ee5cbfSDavid du Colombier /*
130180ee5cbfSDavid du Colombier * newbytes(len), with data initialized from buf
130280ee5cbfSDavid du Colombier */
130380ee5cbfSDavid du Colombier static Bytes*
makebytes(uchar * buf,int len)130480ee5cbfSDavid du Colombier makebytes(uchar* buf, int len)
130580ee5cbfSDavid du Colombier {
130680ee5cbfSDavid du Colombier Bytes* ans;
130780ee5cbfSDavid du Colombier
130880ee5cbfSDavid du Colombier ans = newbytes(len);
130980ee5cbfSDavid du Colombier memmove(ans->data, buf, len);
131080ee5cbfSDavid du Colombier return ans;
131180ee5cbfSDavid du Colombier }
131280ee5cbfSDavid du Colombier
131380ee5cbfSDavid du Colombier static void
freebytes(Bytes * b)131480ee5cbfSDavid du Colombier freebytes(Bytes* b)
131580ee5cbfSDavid du Colombier {
131680ee5cbfSDavid du Colombier if(b != nil)
131780ee5cbfSDavid du Colombier free(b);
131880ee5cbfSDavid du Colombier }
131980ee5cbfSDavid du Colombier
132080ee5cbfSDavid du Colombier /*
132180ee5cbfSDavid du Colombier * Make a new Bytes, containing bytes of b1 followed by those of b2.
132280ee5cbfSDavid du Colombier * Either b1 or b2 or both can be nil.
132380ee5cbfSDavid du Colombier */
132480ee5cbfSDavid du Colombier static Bytes*
catbytes(Bytes * b1,Bytes * b2)132580ee5cbfSDavid du Colombier catbytes(Bytes* b1, Bytes* b2)
132680ee5cbfSDavid du Colombier {
132780ee5cbfSDavid du Colombier Bytes* ans;
132880ee5cbfSDavid du Colombier int n;
132980ee5cbfSDavid du Colombier
133080ee5cbfSDavid du Colombier if(b1 == nil) {
133180ee5cbfSDavid du Colombier if(b2 == nil)
133280ee5cbfSDavid du Colombier ans = newbytes(0);
133380ee5cbfSDavid du Colombier else
133480ee5cbfSDavid du Colombier ans = makebytes(b2->data, b2->len);
133580ee5cbfSDavid du Colombier }
133680ee5cbfSDavid du Colombier else if(b2 == nil) {
133780ee5cbfSDavid du Colombier ans = makebytes(b1->data, b1->len);
133880ee5cbfSDavid du Colombier }
133980ee5cbfSDavid du Colombier else {
134080ee5cbfSDavid du Colombier n = b1->len + b2->len;
134180ee5cbfSDavid du Colombier ans = newbytes(n);
134280ee5cbfSDavid du Colombier ans->len = n;
134380ee5cbfSDavid du Colombier memmove(ans->data, b1->data, b1->len);
134480ee5cbfSDavid du Colombier memmove(ans->data+b1->len, b2->data, b2->len);
134580ee5cbfSDavid du Colombier }
134680ee5cbfSDavid du Colombier return ans;
134780ee5cbfSDavid du Colombier }
134880ee5cbfSDavid du Colombier
134980ee5cbfSDavid du Colombier /* len is number of ints */
135080ee5cbfSDavid du Colombier static Ints*
newints(int len)135180ee5cbfSDavid du Colombier newints(int len)
135280ee5cbfSDavid du Colombier {
135380ee5cbfSDavid du Colombier Ints* ans;
135480ee5cbfSDavid du Colombier
1355d9306527SDavid du Colombier ans = (Ints*)emalloc(OFFSETOF(data[0], Ints) + len*sizeof(int));
135680ee5cbfSDavid du Colombier ans->len = len;
135780ee5cbfSDavid du Colombier return ans;
135880ee5cbfSDavid du Colombier }
135980ee5cbfSDavid du Colombier
136080ee5cbfSDavid du Colombier static Ints*
makeints(int * buf,int len)136180ee5cbfSDavid du Colombier makeints(int* buf, int len)
136280ee5cbfSDavid du Colombier {
136380ee5cbfSDavid du Colombier Ints* ans;
136480ee5cbfSDavid du Colombier
136580ee5cbfSDavid du Colombier ans = newints(len);
136680ee5cbfSDavid du Colombier if(len > 0)
136780ee5cbfSDavid du Colombier memmove(ans->data, buf, len*sizeof(int));
136880ee5cbfSDavid du Colombier return ans;
136980ee5cbfSDavid du Colombier }
137080ee5cbfSDavid du Colombier
137180ee5cbfSDavid du Colombier static void
freeints(Ints * b)137280ee5cbfSDavid du Colombier freeints(Ints* b)
137380ee5cbfSDavid du Colombier {
137480ee5cbfSDavid du Colombier if(b != nil)
137580ee5cbfSDavid du Colombier free(b);
137680ee5cbfSDavid du Colombier }
137780ee5cbfSDavid du Colombier
137880ee5cbfSDavid du Colombier /* len is number of bytes */
137980ee5cbfSDavid du Colombier static Bits*
newbits(int len)138080ee5cbfSDavid du Colombier newbits(int len)
138180ee5cbfSDavid du Colombier {
138280ee5cbfSDavid du Colombier Bits* ans;
138380ee5cbfSDavid du Colombier
1384d9306527SDavid du Colombier ans = (Bits*)emalloc(OFFSETOF(data[0], Bits) + len);
138580ee5cbfSDavid du Colombier ans->len = len;
138680ee5cbfSDavid du Colombier ans->unusedbits = 0;
138780ee5cbfSDavid du Colombier return ans;
138880ee5cbfSDavid du Colombier }
138980ee5cbfSDavid du Colombier
139080ee5cbfSDavid du Colombier static Bits*
makebits(uchar * buf,int len,int unusedbits)139180ee5cbfSDavid du Colombier makebits(uchar* buf, int len, int unusedbits)
139280ee5cbfSDavid du Colombier {
139380ee5cbfSDavid du Colombier Bits* ans;
139480ee5cbfSDavid du Colombier
139580ee5cbfSDavid du Colombier ans = newbits(len);
139680ee5cbfSDavid du Colombier memmove(ans->data, buf, len);
139780ee5cbfSDavid du Colombier ans->unusedbits = unusedbits;
139880ee5cbfSDavid du Colombier return ans;
139980ee5cbfSDavid du Colombier }
140080ee5cbfSDavid du Colombier
140180ee5cbfSDavid du Colombier static void
freebits(Bits * b)140280ee5cbfSDavid du Colombier freebits(Bits* b)
140380ee5cbfSDavid du Colombier {
140480ee5cbfSDavid du Colombier if(b != nil)
140580ee5cbfSDavid du Colombier free(b);
140680ee5cbfSDavid du Colombier }
140780ee5cbfSDavid du Colombier
140880ee5cbfSDavid du Colombier static Elist*
mkel(Elem e,Elist * tail)1409d9306527SDavid du Colombier mkel(Elem e, Elist* tail)
141080ee5cbfSDavid du Colombier {
141180ee5cbfSDavid du Colombier Elist* el;
141280ee5cbfSDavid du Colombier
1413d9306527SDavid du Colombier el = (Elist*)emalloc(sizeof(Elist));
14149027b8f7SDavid du Colombier setmalloctag(el, getcallerpc(&e));
141580ee5cbfSDavid du Colombier el->hd = e;
141680ee5cbfSDavid du Colombier el->tl = tail;
141780ee5cbfSDavid du Colombier return el;
141880ee5cbfSDavid du Colombier }
141980ee5cbfSDavid du Colombier
142080ee5cbfSDavid du Colombier static int
elistlen(Elist * el)142180ee5cbfSDavid du Colombier elistlen(Elist* el)
142280ee5cbfSDavid du Colombier {
142380ee5cbfSDavid du Colombier int ans = 0;
142480ee5cbfSDavid du Colombier while(el != nil) {
142580ee5cbfSDavid du Colombier ans++;
142680ee5cbfSDavid du Colombier el = el->tl;
142780ee5cbfSDavid du Colombier }
142880ee5cbfSDavid du Colombier return ans;
142980ee5cbfSDavid du Colombier }
143080ee5cbfSDavid du Colombier
143180ee5cbfSDavid du Colombier /* Frees elist, but not fields inside values of constituent elems */
143280ee5cbfSDavid du Colombier static void
freeelist(Elist * el)143380ee5cbfSDavid du Colombier freeelist(Elist* el)
143480ee5cbfSDavid du Colombier {
143580ee5cbfSDavid du Colombier Elist* next;
143680ee5cbfSDavid du Colombier
143780ee5cbfSDavid du Colombier while(el != nil) {
143880ee5cbfSDavid du Colombier next = el->tl;
143980ee5cbfSDavid du Colombier free(el);
144080ee5cbfSDavid du Colombier el = next;
144180ee5cbfSDavid du Colombier }
144280ee5cbfSDavid du Colombier }
144380ee5cbfSDavid du Colombier
144480ee5cbfSDavid du Colombier /* free any allocated structures inside v (recursively freeing Elists) */
144580ee5cbfSDavid du Colombier static void
freevalfields(Value * v)144680ee5cbfSDavid du Colombier freevalfields(Value* v)
144780ee5cbfSDavid du Colombier {
144880ee5cbfSDavid du Colombier Elist* el;
144980ee5cbfSDavid du Colombier Elist* l;
145080ee5cbfSDavid du Colombier if(v == nil)
145180ee5cbfSDavid du Colombier return;
145280ee5cbfSDavid du Colombier switch(v->tag) {
145380ee5cbfSDavid du Colombier case VOctets:
145480ee5cbfSDavid du Colombier freebytes(v->u.octetsval);
145580ee5cbfSDavid du Colombier break;
145680ee5cbfSDavid du Colombier case VBigInt:
145780ee5cbfSDavid du Colombier freebytes(v->u.bigintval);
145880ee5cbfSDavid du Colombier break;
145980ee5cbfSDavid du Colombier case VReal:
146080ee5cbfSDavid du Colombier freebytes(v->u.realval);
146180ee5cbfSDavid du Colombier break;
146280ee5cbfSDavid du Colombier case VOther:
146380ee5cbfSDavid du Colombier freebytes(v->u.otherval);
146480ee5cbfSDavid du Colombier break;
146580ee5cbfSDavid du Colombier case VBitString:
146680ee5cbfSDavid du Colombier freebits(v->u.bitstringval);
146780ee5cbfSDavid du Colombier break;
146880ee5cbfSDavid du Colombier case VObjId:
146980ee5cbfSDavid du Colombier freeints(v->u.objidval);
147080ee5cbfSDavid du Colombier break;
147180ee5cbfSDavid du Colombier case VString:
147280ee5cbfSDavid du Colombier if(v->u.stringval)
147380ee5cbfSDavid du Colombier free(v->u.stringval);
147480ee5cbfSDavid du Colombier break;
147580ee5cbfSDavid du Colombier case VSeq:
147680ee5cbfSDavid du Colombier el = v->u.seqval;
147780ee5cbfSDavid du Colombier for(l = el; l != nil; l = l->tl)
147880ee5cbfSDavid du Colombier freevalfields(&l->hd.val);
147980ee5cbfSDavid du Colombier if(el)
148080ee5cbfSDavid du Colombier freeelist(el);
148180ee5cbfSDavid du Colombier break;
148280ee5cbfSDavid du Colombier case VSet:
148380ee5cbfSDavid du Colombier el = v->u.setval;
148480ee5cbfSDavid du Colombier for(l = el; l != nil; l = l->tl)
148580ee5cbfSDavid du Colombier freevalfields(&l->hd.val);
148680ee5cbfSDavid du Colombier if(el)
148780ee5cbfSDavid du Colombier freeelist(el);
148880ee5cbfSDavid du Colombier break;
148980ee5cbfSDavid du Colombier }
149080ee5cbfSDavid du Colombier }
149180ee5cbfSDavid du Colombier
149280ee5cbfSDavid du Colombier /* end of general ASN1 functions */
149380ee5cbfSDavid du Colombier
149480ee5cbfSDavid du Colombier
149580ee5cbfSDavid du Colombier
149680ee5cbfSDavid du Colombier
149780ee5cbfSDavid du Colombier
149880ee5cbfSDavid du Colombier /*=============================================================*/
149980ee5cbfSDavid du Colombier /*
150080ee5cbfSDavid du Colombier * Decode and parse an X.509 Certificate, defined by this ASN1:
150180ee5cbfSDavid du Colombier * Certificate ::= SEQUENCE {
150280ee5cbfSDavid du Colombier * certificateInfo CertificateInfo,
150380ee5cbfSDavid du Colombier * signatureAlgorithm AlgorithmIdentifier,
150480ee5cbfSDavid du Colombier * signature BIT STRING }
150580ee5cbfSDavid du Colombier *
150680ee5cbfSDavid du Colombier * CertificateInfo ::= SEQUENCE {
150780ee5cbfSDavid du Colombier * version [0] INTEGER DEFAULT v1 (0),
150880ee5cbfSDavid du Colombier * serialNumber INTEGER,
150980ee5cbfSDavid du Colombier * signature AlgorithmIdentifier,
151080ee5cbfSDavid du Colombier * issuer Name,
151180ee5cbfSDavid du Colombier * validity Validity,
151280ee5cbfSDavid du Colombier * subject Name,
151380ee5cbfSDavid du Colombier * subjectPublicKeyInfo SubjectPublicKeyInfo }
15143ff48bf5SDavid du Colombier * (version v2 has two more fields, optional unique identifiers for
15153ff48bf5SDavid du Colombier * issuer and subject; since we ignore these anyway, we won't parse them)
151680ee5cbfSDavid du Colombier *
151780ee5cbfSDavid du Colombier * Validity ::= SEQUENCE {
151880ee5cbfSDavid du Colombier * notBefore UTCTime,
151980ee5cbfSDavid du Colombier * notAfter UTCTime }
152080ee5cbfSDavid du Colombier *
152180ee5cbfSDavid du Colombier * SubjectPublicKeyInfo ::= SEQUENCE {
152280ee5cbfSDavid du Colombier * algorithm AlgorithmIdentifier,
152380ee5cbfSDavid du Colombier * subjectPublicKey BIT STRING }
152480ee5cbfSDavid du Colombier *
152580ee5cbfSDavid du Colombier * AlgorithmIdentifier ::= SEQUENCE {
152680ee5cbfSDavid du Colombier * algorithm OBJECT IDENTIFER,
152780ee5cbfSDavid du Colombier * parameters ANY DEFINED BY ALGORITHM OPTIONAL }
152880ee5cbfSDavid du Colombier *
152980ee5cbfSDavid du Colombier * Name ::= SEQUENCE OF RelativeDistinguishedName
153080ee5cbfSDavid du Colombier *
15319a747e4fSDavid du Colombier * RelativeDistinguishedName ::= SETOF SIZE(1..MAX) OF AttributeTypeAndValue
153280ee5cbfSDavid du Colombier *
153380ee5cbfSDavid du Colombier * AttributeTypeAndValue ::= SEQUENCE {
153480ee5cbfSDavid du Colombier * type OBJECT IDENTIFER,
153580ee5cbfSDavid du Colombier * value DirectoryString }
153680ee5cbfSDavid du Colombier * (selected attributes have these Object Ids:
153780ee5cbfSDavid du Colombier * commonName {2 5 4 3}
153880ee5cbfSDavid du Colombier * countryName {2 5 4 6}
153980ee5cbfSDavid du Colombier * localityName {2 5 4 7}
154080ee5cbfSDavid du Colombier * stateOrProvinceName {2 5 4 8}
154180ee5cbfSDavid du Colombier * organizationName {2 5 4 10}
154280ee5cbfSDavid du Colombier * organizationalUnitName {2 5 4 11}
154380ee5cbfSDavid du Colombier * )
154480ee5cbfSDavid du Colombier *
154580ee5cbfSDavid du Colombier * DirectoryString ::= CHOICE {
154680ee5cbfSDavid du Colombier * teletexString TeletexString,
154780ee5cbfSDavid du Colombier * printableString PrintableString,
154880ee5cbfSDavid du Colombier * universalString UniversalString }
154980ee5cbfSDavid du Colombier *
15503ff48bf5SDavid du Colombier * See rfc1423, rfc2437 for AlgorithmIdentifier, subjectPublicKeyInfo, signature.
15513ff48bf5SDavid du Colombier *
15523ff48bf5SDavid du Colombier * Not yet implemented:
15533ff48bf5SDavid du Colombier * CertificateRevocationList ::= SIGNED SEQUENCE{
15543ff48bf5SDavid du Colombier * signature AlgorithmIdentifier,
15553ff48bf5SDavid du Colombier * issuer Name,
15563ff48bf5SDavid du Colombier * lastUpdate UTCTime,
15573ff48bf5SDavid du Colombier * nextUpdate UTCTime,
15583ff48bf5SDavid du Colombier * revokedCertificates
15593ff48bf5SDavid du Colombier * SEQUENCE OF CRLEntry OPTIONAL}
15603ff48bf5SDavid du Colombier * CRLEntry ::= SEQUENCE{
15613ff48bf5SDavid du Colombier * userCertificate SerialNumber,
15623ff48bf5SDavid du Colombier * revocationDate UTCTime}
156380ee5cbfSDavid du Colombier */
156480ee5cbfSDavid du Colombier
156580ee5cbfSDavid du Colombier typedef struct CertX509 {
156680ee5cbfSDavid du Colombier int serial;
156780ee5cbfSDavid du Colombier char* issuer;
156880ee5cbfSDavid du Colombier char* validity_start;
156980ee5cbfSDavid du Colombier char* validity_end;
157080ee5cbfSDavid du Colombier char* subject;
157180ee5cbfSDavid du Colombier int publickey_alg;
157280ee5cbfSDavid du Colombier Bytes* publickey;
157380ee5cbfSDavid du Colombier int signature_alg;
157480ee5cbfSDavid du Colombier Bytes* signature;
157580ee5cbfSDavid du Colombier } CertX509;
157680ee5cbfSDavid du Colombier
157780ee5cbfSDavid du Colombier /* Algorithm object-ids */
157880ee5cbfSDavid du Colombier enum {
157980ee5cbfSDavid du Colombier ALG_rsaEncryption,
158080ee5cbfSDavid du Colombier ALG_md2WithRSAEncryption,
158180ee5cbfSDavid du Colombier ALG_md4WithRSAEncryption,
158280ee5cbfSDavid du Colombier ALG_md5WithRSAEncryption,
15839a747e4fSDavid du Colombier ALG_sha1WithRSAEncryption,
158454c86280SDavid du Colombier ALG_sha1WithRSAEncryptionOiw,
15851075affeSDavid du Colombier ALG_md5,
158680ee5cbfSDavid du Colombier NUMALGS
158780ee5cbfSDavid du Colombier };
158880ee5cbfSDavid du Colombier typedef struct Ints7 {
158980ee5cbfSDavid du Colombier int len;
159080ee5cbfSDavid du Colombier int data[7];
159180ee5cbfSDavid du Colombier } Ints7;
159280ee5cbfSDavid du Colombier static Ints7 oid_rsaEncryption = {7, 1, 2, 840, 113549, 1, 1, 1 };
159380ee5cbfSDavid du Colombier static Ints7 oid_md2WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 2 };
159480ee5cbfSDavid du Colombier static Ints7 oid_md4WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 3 };
159580ee5cbfSDavid du Colombier static Ints7 oid_md5WithRSAEncryption = {7, 1, 2, 840, 113549, 1, 1, 4 };
15969a747e4fSDavid du Colombier static Ints7 oid_sha1WithRSAEncryption ={7, 1, 2, 840, 113549, 1, 1, 5 };
159754c86280SDavid du Colombier static Ints7 oid_sha1WithRSAEncryptionOiw ={6, 1, 3, 14, 3, 2, 29 };
15981075affeSDavid du Colombier static Ints7 oid_md5 ={6, 1, 2, 840, 113549, 2, 5, 0 };
159980ee5cbfSDavid du Colombier static Ints *alg_oid_tab[NUMALGS+1] = {
160080ee5cbfSDavid du Colombier (Ints*)&oid_rsaEncryption,
160180ee5cbfSDavid du Colombier (Ints*)&oid_md2WithRSAEncryption,
160280ee5cbfSDavid du Colombier (Ints*)&oid_md4WithRSAEncryption,
160380ee5cbfSDavid du Colombier (Ints*)&oid_md5WithRSAEncryption,
16049a747e4fSDavid du Colombier (Ints*)&oid_sha1WithRSAEncryption,
160554c86280SDavid du Colombier (Ints*)&oid_sha1WithRSAEncryptionOiw,
16061075affeSDavid du Colombier (Ints*)&oid_md5,
160780ee5cbfSDavid du Colombier nil
160880ee5cbfSDavid du Colombier };
160954c86280SDavid du Colombier static DigestFun digestalg[NUMALGS+1] = { md5, md5, md5, md5, sha1, sha1, md5, nil };
161080ee5cbfSDavid du Colombier
161180ee5cbfSDavid du Colombier static void
freecert(CertX509 * c)161280ee5cbfSDavid du Colombier freecert(CertX509* c)
161380ee5cbfSDavid du Colombier {
161480ee5cbfSDavid du Colombier if(!c) return;
161580ee5cbfSDavid du Colombier if(c->issuer != nil)
161680ee5cbfSDavid du Colombier free(c->issuer);
161780ee5cbfSDavid du Colombier if(c->validity_start != nil)
161880ee5cbfSDavid du Colombier free(c->validity_start);
161980ee5cbfSDavid du Colombier if(c->validity_end != nil)
162080ee5cbfSDavid du Colombier free(c->validity_end);
162180ee5cbfSDavid du Colombier if(c->subject != nil)
162280ee5cbfSDavid du Colombier free(c->subject);
162380ee5cbfSDavid du Colombier freebytes(c->publickey);
162480ee5cbfSDavid du Colombier freebytes(c->signature);
162592fd5f07SDavid du Colombier free(c);
162680ee5cbfSDavid du Colombier }
162780ee5cbfSDavid du Colombier
162880ee5cbfSDavid du Colombier /*
162980ee5cbfSDavid du Colombier * Parse the Name ASN1 type.
163080ee5cbfSDavid du Colombier * The sequence of RelativeDistinguishedName's gives a sort of pathname,
163180ee5cbfSDavid du Colombier * from most general to most specific. Each element of the path can be
163280ee5cbfSDavid du Colombier * one or more (but usually just one) attribute-value pair, such as
163380ee5cbfSDavid du Colombier * countryName="US".
163480ee5cbfSDavid du Colombier * We'll just form a "postal-style" address string by concatenating the elements
163580ee5cbfSDavid du Colombier * from most specific to least specific, separated by commas.
163680ee5cbfSDavid du Colombier * Return name-as-string (which must be freed by caller).
163780ee5cbfSDavid du Colombier */
163880ee5cbfSDavid du Colombier static char*
parse_name(Elem * e)163980ee5cbfSDavid du Colombier parse_name(Elem* e)
164080ee5cbfSDavid du Colombier {
164180ee5cbfSDavid du Colombier Elist* el;
164280ee5cbfSDavid du Colombier Elem* es;
164380ee5cbfSDavid du Colombier Elist* esetl;
164480ee5cbfSDavid du Colombier Elem* eat;
164580ee5cbfSDavid du Colombier Elist* eatl;
164680ee5cbfSDavid du Colombier char* s;
164780ee5cbfSDavid du Colombier enum { MAXPARTS = 100 };
164880ee5cbfSDavid du Colombier char* parts[MAXPARTS];
164980ee5cbfSDavid du Colombier int i;
165080ee5cbfSDavid du Colombier int plen;
165180ee5cbfSDavid du Colombier char* ans = nil;
165280ee5cbfSDavid du Colombier
165380ee5cbfSDavid du Colombier if(!is_seq(e, &el))
165480ee5cbfSDavid du Colombier goto errret;
165580ee5cbfSDavid du Colombier i = 0;
165680ee5cbfSDavid du Colombier plen = 0;
165780ee5cbfSDavid du Colombier while(el != nil) {
165880ee5cbfSDavid du Colombier es = &el->hd;
165980ee5cbfSDavid du Colombier if(!is_set(es, &esetl))
166080ee5cbfSDavid du Colombier goto errret;
166180ee5cbfSDavid du Colombier while(esetl != nil) {
166280ee5cbfSDavid du Colombier eat = &esetl->hd;
166380ee5cbfSDavid du Colombier if(!is_seq(eat, &eatl) || elistlen(eatl) != 2)
166480ee5cbfSDavid du Colombier goto errret;
16653ff48bf5SDavid du Colombier if(!is_string(&eatl->tl->hd, &s) || i>=MAXPARTS)
166680ee5cbfSDavid du Colombier goto errret;
166780ee5cbfSDavid du Colombier parts[i++] = s;
166880ee5cbfSDavid du Colombier plen += strlen(s) + 2; /* room for ", " after */
166980ee5cbfSDavid du Colombier esetl = esetl->tl;
167080ee5cbfSDavid du Colombier }
167180ee5cbfSDavid du Colombier el = el->tl;
167280ee5cbfSDavid du Colombier }
167380ee5cbfSDavid du Colombier if(i > 0) {
1674d9306527SDavid du Colombier ans = (char*)emalloc(plen);
167580ee5cbfSDavid du Colombier *ans = '\0';
167680ee5cbfSDavid du Colombier while(--i >= 0) {
167780ee5cbfSDavid du Colombier s = parts[i];
167880ee5cbfSDavid du Colombier strcat(ans, s);
167980ee5cbfSDavid du Colombier if(i > 0)
168080ee5cbfSDavid du Colombier strcat(ans, ", ");
168180ee5cbfSDavid du Colombier }
168280ee5cbfSDavid du Colombier }
168380ee5cbfSDavid du Colombier
168480ee5cbfSDavid du Colombier errret:
168580ee5cbfSDavid du Colombier return ans;
168680ee5cbfSDavid du Colombier }
168780ee5cbfSDavid du Colombier
168880ee5cbfSDavid du Colombier /*
168980ee5cbfSDavid du Colombier * Parse an AlgorithmIdentifer ASN1 type.
169080ee5cbfSDavid du Colombier * Look up the oid in oid_tab and return one of OID_rsaEncryption, etc..,
169180ee5cbfSDavid du Colombier * or -1 if not found.
169280ee5cbfSDavid du Colombier * For now, ignore parameters, since none of our algorithms need them.
169380ee5cbfSDavid du Colombier */
169480ee5cbfSDavid du Colombier static int
parse_alg(Elem * e)169580ee5cbfSDavid du Colombier parse_alg(Elem* e)
169680ee5cbfSDavid du Colombier {
169780ee5cbfSDavid du Colombier Elist* el;
169880ee5cbfSDavid du Colombier Ints* oid;
169980ee5cbfSDavid du Colombier
170080ee5cbfSDavid du Colombier if(!is_seq(e, &el) || el == nil || !is_oid(&el->hd, &oid))
170180ee5cbfSDavid du Colombier return -1;
170280ee5cbfSDavid du Colombier return oid_lookup(oid, alg_oid_tab);
170380ee5cbfSDavid du Colombier }
170480ee5cbfSDavid du Colombier
170580ee5cbfSDavid du Colombier static CertX509*
decode_cert(Bytes * a)170680ee5cbfSDavid du Colombier decode_cert(Bytes* a)
170780ee5cbfSDavid du Colombier {
170880ee5cbfSDavid du Colombier int ok = 0;
170980ee5cbfSDavid du Colombier int n;
171080ee5cbfSDavid du Colombier CertX509* c = nil;
171180ee5cbfSDavid du Colombier Elem ecert;
171280ee5cbfSDavid du Colombier Elem* ecertinfo;
171380ee5cbfSDavid du Colombier Elem* esigalg;
171480ee5cbfSDavid du Colombier Elem* esig;
171580ee5cbfSDavid du Colombier Elem* eserial;
171680ee5cbfSDavid du Colombier Elem* eissuer;
171780ee5cbfSDavid du Colombier Elem* evalidity;
171880ee5cbfSDavid du Colombier Elem* esubj;
171980ee5cbfSDavid du Colombier Elem* epubkey;
172080ee5cbfSDavid du Colombier Elist* el;
172180ee5cbfSDavid du Colombier Elist* elcert = nil;
172280ee5cbfSDavid du Colombier Elist* elcertinfo = nil;
172380ee5cbfSDavid du Colombier Elist* elvalidity = nil;
172480ee5cbfSDavid du Colombier Elist* elpubkey = nil;
172580ee5cbfSDavid du Colombier Bits* bits = nil;
172680ee5cbfSDavid du Colombier Bytes* b;
172780ee5cbfSDavid du Colombier Elem* e;
172880ee5cbfSDavid du Colombier
172980ee5cbfSDavid du Colombier if(decode(a->data, a->len, &ecert) != ASN_OK)
173080ee5cbfSDavid du Colombier goto errret;
173180ee5cbfSDavid du Colombier
1732d9306527SDavid du Colombier c = (CertX509*)emalloc(sizeof(CertX509));
173380ee5cbfSDavid du Colombier c->serial = -1;
173480ee5cbfSDavid du Colombier c->issuer = nil;
173580ee5cbfSDavid du Colombier c->validity_start = nil;
173680ee5cbfSDavid du Colombier c->validity_end = nil;
173780ee5cbfSDavid du Colombier c->subject = nil;
173880ee5cbfSDavid du Colombier c->publickey_alg = -1;
173980ee5cbfSDavid du Colombier c->publickey = nil;
174080ee5cbfSDavid du Colombier c->signature_alg = -1;
174180ee5cbfSDavid du Colombier c->signature = nil;
174280ee5cbfSDavid du Colombier
174380ee5cbfSDavid du Colombier /* Certificate */
174480ee5cbfSDavid du Colombier if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
174580ee5cbfSDavid du Colombier goto errret;
174680ee5cbfSDavid du Colombier ecertinfo = &elcert->hd;
174780ee5cbfSDavid du Colombier el = elcert->tl;
174880ee5cbfSDavid du Colombier esigalg = &el->hd;
17493ff48bf5SDavid du Colombier c->signature_alg = parse_alg(esigalg);
175080ee5cbfSDavid du Colombier el = el->tl;
175180ee5cbfSDavid du Colombier esig = &el->hd;
175280ee5cbfSDavid du Colombier
175380ee5cbfSDavid du Colombier /* Certificate Info */
175480ee5cbfSDavid du Colombier if(!is_seq(ecertinfo, &elcertinfo))
175580ee5cbfSDavid du Colombier goto errret;
175680ee5cbfSDavid du Colombier n = elistlen(elcertinfo);
175780ee5cbfSDavid du Colombier if(n < 6)
175880ee5cbfSDavid du Colombier goto errret;
175980ee5cbfSDavid du Colombier eserial =&elcertinfo->hd;
176080ee5cbfSDavid du Colombier el = elcertinfo->tl;
176180ee5cbfSDavid du Colombier /* check for optional version, marked by explicit context tag 0 */
176280ee5cbfSDavid du Colombier if(eserial->tag.class == Context && eserial->tag.num == 0) {
176380ee5cbfSDavid du Colombier eserial = &el->hd;
176480ee5cbfSDavid du Colombier if(n < 7)
176580ee5cbfSDavid du Colombier goto errret;
176680ee5cbfSDavid du Colombier el = el->tl;
176780ee5cbfSDavid du Colombier }
176880ee5cbfSDavid du Colombier
17693ff48bf5SDavid du Colombier if(parse_alg(&el->hd) != c->signature_alg)
17703ff48bf5SDavid du Colombier goto errret;
177180ee5cbfSDavid du Colombier el = el->tl;
177280ee5cbfSDavid du Colombier eissuer = &el->hd;
177380ee5cbfSDavid du Colombier el = el->tl;
177480ee5cbfSDavid du Colombier evalidity = &el->hd;
177580ee5cbfSDavid du Colombier el = el->tl;
177680ee5cbfSDavid du Colombier esubj = &el->hd;
177780ee5cbfSDavid du Colombier el = el->tl;
177880ee5cbfSDavid du Colombier epubkey = &el->hd;
177980ee5cbfSDavid du Colombier if(!is_int(eserial, &c->serial)) {
178080ee5cbfSDavid du Colombier if(!is_bigint(eserial, &b))
178180ee5cbfSDavid du Colombier goto errret;
178280ee5cbfSDavid du Colombier c->serial = -1; /* else we have to change cert struct */
178380ee5cbfSDavid du Colombier }
178480ee5cbfSDavid du Colombier c->issuer = parse_name(eissuer);
178580ee5cbfSDavid du Colombier if(c->issuer == nil)
178680ee5cbfSDavid du Colombier goto errret;
178780ee5cbfSDavid du Colombier /* Validity */
178880ee5cbfSDavid du Colombier if(!is_seq(evalidity, &elvalidity))
178980ee5cbfSDavid du Colombier goto errret;
179080ee5cbfSDavid du Colombier if(elistlen(elvalidity) != 2)
179180ee5cbfSDavid du Colombier goto errret;
179280ee5cbfSDavid du Colombier e = &elvalidity->hd;
179380ee5cbfSDavid du Colombier if(!is_time(e, &c->validity_start))
179480ee5cbfSDavid du Colombier goto errret;
179580ee5cbfSDavid du Colombier e->val.u.stringval = nil; /* string ownership transfer */
179680ee5cbfSDavid du Colombier e = &elvalidity->tl->hd;
179780ee5cbfSDavid du Colombier if(!is_time(e, &c->validity_end))
179880ee5cbfSDavid du Colombier goto errret;
179980ee5cbfSDavid du Colombier e->val.u.stringval = nil; /* string ownership transfer */
180080ee5cbfSDavid du Colombier
180180ee5cbfSDavid du Colombier /* resume CertificateInfo */
180280ee5cbfSDavid du Colombier c->subject = parse_name(esubj);
180380ee5cbfSDavid du Colombier if(c->subject == nil)
180480ee5cbfSDavid du Colombier goto errret;
180580ee5cbfSDavid du Colombier
180680ee5cbfSDavid du Colombier /* SubjectPublicKeyInfo */
180780ee5cbfSDavid du Colombier if(!is_seq(epubkey, &elpubkey))
180880ee5cbfSDavid du Colombier goto errret;
180980ee5cbfSDavid du Colombier if(elistlen(elpubkey) != 2)
181080ee5cbfSDavid du Colombier goto errret;
181180ee5cbfSDavid du Colombier
181280ee5cbfSDavid du Colombier c->publickey_alg = parse_alg(&elpubkey->hd);
181380ee5cbfSDavid du Colombier if(c->publickey_alg < 0)
181480ee5cbfSDavid du Colombier goto errret;
181580ee5cbfSDavid du Colombier if(!is_bitstring(&elpubkey->tl->hd, &bits))
181680ee5cbfSDavid du Colombier goto errret;
181780ee5cbfSDavid du Colombier if(bits->unusedbits != 0)
181880ee5cbfSDavid du Colombier goto errret;
181980ee5cbfSDavid du Colombier c->publickey = makebytes(bits->data, bits->len);
182080ee5cbfSDavid du Colombier
182180ee5cbfSDavid du Colombier /*resume Certificate */
182280ee5cbfSDavid du Colombier if(c->signature_alg < 0)
182380ee5cbfSDavid du Colombier goto errret;
182480ee5cbfSDavid du Colombier if(!is_bitstring(esig, &bits))
182580ee5cbfSDavid du Colombier goto errret;
182680ee5cbfSDavid du Colombier c->signature = makebytes(bits->data, bits->len);
182780ee5cbfSDavid du Colombier ok = 1;
182880ee5cbfSDavid du Colombier
182980ee5cbfSDavid du Colombier errret:
183080ee5cbfSDavid du Colombier freevalfields(&ecert.val); /* recurses through lists, too */
183180ee5cbfSDavid du Colombier if(!ok){
183280ee5cbfSDavid du Colombier freecert(c);
183380ee5cbfSDavid du Colombier c = nil;
183480ee5cbfSDavid du Colombier }
183580ee5cbfSDavid du Colombier return c;
183680ee5cbfSDavid du Colombier }
183780ee5cbfSDavid du Colombier
18389a747e4fSDavid du Colombier /*
18399a747e4fSDavid du Colombier * RSAPublickKey :: SEQUENCE {
18409a747e4fSDavid du Colombier * modulus INTEGER,
18419a747e4fSDavid du Colombier * publicExponent INTEGER
18429a747e4fSDavid du Colombier * }
18439a747e4fSDavid du Colombier */
184480ee5cbfSDavid du Colombier static RSApub*
decode_rsapubkey(Bytes * a)184580ee5cbfSDavid du Colombier decode_rsapubkey(Bytes* a)
184680ee5cbfSDavid du Colombier {
184780ee5cbfSDavid du Colombier Elem e;
184892fd5f07SDavid du Colombier Elist *el, *l;
18499a747e4fSDavid du Colombier mpint *mp;
18509a747e4fSDavid du Colombier RSApub* key;
185180ee5cbfSDavid du Colombier
185292fd5f07SDavid du Colombier l = nil;
18539a747e4fSDavid du Colombier key = rsapuballoc();
185480ee5cbfSDavid du Colombier if(decode(a->data, a->len, &e) != ASN_OK)
185580ee5cbfSDavid du Colombier goto errret;
185680ee5cbfSDavid du Colombier if(!is_seq(&e, &el) || elistlen(el) != 2)
185780ee5cbfSDavid du Colombier goto errret;
18589a747e4fSDavid du Colombier
185992fd5f07SDavid du Colombier l = el;
186092fd5f07SDavid du Colombier
18619a747e4fSDavid du Colombier key->n = mp = asn1mpint(&el->hd);
18629a747e4fSDavid du Colombier if(mp == nil)
186380ee5cbfSDavid du Colombier goto errret;
18649a747e4fSDavid du Colombier
18659a747e4fSDavid du Colombier el = el->tl;
18669a747e4fSDavid du Colombier key->ek = mp = asn1mpint(&el->hd);
18679a747e4fSDavid du Colombier if(mp == nil)
186880ee5cbfSDavid du Colombier goto errret;
186992fd5f07SDavid du Colombier
187092fd5f07SDavid du Colombier if(l != nil)
187192fd5f07SDavid du Colombier freeelist(l);
18729a747e4fSDavid du Colombier return key;
187380ee5cbfSDavid du Colombier errret:
187492fd5f07SDavid du Colombier if(l != nil)
187592fd5f07SDavid du Colombier freeelist(l);
18769a747e4fSDavid du Colombier rsapubfree(key);
187780ee5cbfSDavid du Colombier return nil;
187880ee5cbfSDavid du Colombier }
187980ee5cbfSDavid du Colombier
18809a747e4fSDavid du Colombier /*
18819a747e4fSDavid du Colombier * RSAPrivateKey ::= SEQUENCE {
18829a747e4fSDavid du Colombier * version Version,
18839a747e4fSDavid du Colombier * modulus INTEGER, -- n
18849a747e4fSDavid du Colombier * publicExponent INTEGER, -- e
18859a747e4fSDavid du Colombier * privateExponent INTEGER, -- d
18869a747e4fSDavid du Colombier * prime1 INTEGER, -- p
18879a747e4fSDavid du Colombier * prime2 INTEGER, -- q
18889a747e4fSDavid du Colombier * exponent1 INTEGER, -- d mod (p-1)
18899a747e4fSDavid du Colombier * exponent2 INTEGER, -- d mod (q-1)
18909a747e4fSDavid du Colombier * coefficient INTEGER -- (inverse of q) mod p }
18919a747e4fSDavid du Colombier */
18929a747e4fSDavid du Colombier static RSApriv*
decode_rsaprivkey(Bytes * a)18939a747e4fSDavid du Colombier decode_rsaprivkey(Bytes* a)
18949a747e4fSDavid du Colombier {
18959a747e4fSDavid du Colombier int version;
18969a747e4fSDavid du Colombier Elem e;
18979a747e4fSDavid du Colombier Elist *el;
18989a747e4fSDavid du Colombier mpint *mp;
18999a747e4fSDavid du Colombier RSApriv* key;
19009a747e4fSDavid du Colombier
19019a747e4fSDavid du Colombier key = rsaprivalloc();
19029a747e4fSDavid du Colombier if(decode(a->data, a->len, &e) != ASN_OK)
19039a747e4fSDavid du Colombier goto errret;
19049a747e4fSDavid du Colombier if(!is_seq(&e, &el) || elistlen(el) != 9)
19059a747e4fSDavid du Colombier goto errret;
19069a747e4fSDavid du Colombier if(!is_int(&el->hd, &version) || version != 0)
19079a747e4fSDavid du Colombier goto errret;
19089a747e4fSDavid du Colombier
19099a747e4fSDavid du Colombier el = el->tl;
19109a747e4fSDavid du Colombier key->pub.n = mp = asn1mpint(&el->hd);
19119a747e4fSDavid du Colombier if(mp == nil)
19129a747e4fSDavid du Colombier goto errret;
19139a747e4fSDavid du Colombier
19149a747e4fSDavid du Colombier el = el->tl;
19159a747e4fSDavid du Colombier key->pub.ek = mp = asn1mpint(&el->hd);
19169a747e4fSDavid du Colombier if(mp == nil)
19179a747e4fSDavid du Colombier goto errret;
19189a747e4fSDavid du Colombier
19199a747e4fSDavid du Colombier el = el->tl;
19209a747e4fSDavid du Colombier key->dk = mp = asn1mpint(&el->hd);
19219a747e4fSDavid du Colombier if(mp == nil)
19229a747e4fSDavid du Colombier goto errret;
19239a747e4fSDavid du Colombier
19249a747e4fSDavid du Colombier el = el->tl;
19259a747e4fSDavid du Colombier key->q = mp = asn1mpint(&el->hd);
19269a747e4fSDavid du Colombier if(mp == nil)
19279a747e4fSDavid du Colombier goto errret;
19289a747e4fSDavid du Colombier
19299a747e4fSDavid du Colombier el = el->tl;
19309a747e4fSDavid du Colombier key->p = mp = asn1mpint(&el->hd);
19319a747e4fSDavid du Colombier if(mp == nil)
19329a747e4fSDavid du Colombier goto errret;
19339a747e4fSDavid du Colombier
19349a747e4fSDavid du Colombier el = el->tl;
19359a747e4fSDavid du Colombier key->kq = mp = asn1mpint(&el->hd);
19369a747e4fSDavid du Colombier if(mp == nil)
19379a747e4fSDavid du Colombier goto errret;
19389a747e4fSDavid du Colombier
19399a747e4fSDavid du Colombier el = el->tl;
19409a747e4fSDavid du Colombier key->kp = mp = asn1mpint(&el->hd);
19419a747e4fSDavid du Colombier if(mp == nil)
19429a747e4fSDavid du Colombier goto errret;
19439a747e4fSDavid du Colombier
19449a747e4fSDavid du Colombier el = el->tl;
19459a747e4fSDavid du Colombier key->c2 = mp = asn1mpint(&el->hd);
19469a747e4fSDavid du Colombier if(mp == nil)
19479a747e4fSDavid du Colombier goto errret;
19489a747e4fSDavid du Colombier
19499a747e4fSDavid du Colombier return key;
19509a747e4fSDavid du Colombier errret:
19519a747e4fSDavid du Colombier rsaprivfree(key);
19529a747e4fSDavid du Colombier return nil;
19539a747e4fSDavid du Colombier }
19549a747e4fSDavid du Colombier
19552d8b52e8SDavid du Colombier /*
19562d8b52e8SDavid du Colombier * DSAPrivateKey ::= SEQUENCE{
19572d8b52e8SDavid du Colombier * version Version,
19582d8b52e8SDavid du Colombier * p INTEGER,
19592d8b52e8SDavid du Colombier * q INTEGER,
19602d8b52e8SDavid du Colombier * g INTEGER, -- alpha
19612d8b52e8SDavid du Colombier * pub_key INTEGER, -- key
19622d8b52e8SDavid du Colombier * priv_key INTEGER, -- secret
19632d8b52e8SDavid du Colombier * }
19642d8b52e8SDavid du Colombier */
19652d8b52e8SDavid du Colombier static DSApriv*
decode_dsaprivkey(Bytes * a)19662d8b52e8SDavid du Colombier decode_dsaprivkey(Bytes* a)
19672d8b52e8SDavid du Colombier {
19682d8b52e8SDavid du Colombier int version;
19692d8b52e8SDavid du Colombier Elem e;
19702d8b52e8SDavid du Colombier Elist *el;
19712d8b52e8SDavid du Colombier mpint *mp;
19722d8b52e8SDavid du Colombier DSApriv* key;
19732d8b52e8SDavid du Colombier
19742d8b52e8SDavid du Colombier key = dsaprivalloc();
19752d8b52e8SDavid du Colombier if(decode(a->data, a->len, &e) != ASN_OK)
19762d8b52e8SDavid du Colombier goto errret;
19772d8b52e8SDavid du Colombier if(!is_seq(&e, &el) || elistlen(el) != 6)
19782d8b52e8SDavid du Colombier goto errret;
19792d8b52e8SDavid du Colombier version = -1;
19802d8b52e8SDavid du Colombier if(!is_int(&el->hd, &version) || version != 0)
19812d8b52e8SDavid du Colombier {
19822d8b52e8SDavid du Colombier fprint(2, "version %d\n", version);
19832d8b52e8SDavid du Colombier goto errret;
19842d8b52e8SDavid du Colombier }
19852d8b52e8SDavid du Colombier
19862d8b52e8SDavid du Colombier el = el->tl;
19872d8b52e8SDavid du Colombier key->pub.p = mp = asn1mpint(&el->hd);
19882d8b52e8SDavid du Colombier if(mp == nil)
19892d8b52e8SDavid du Colombier goto errret;
19902d8b52e8SDavid du Colombier
19912d8b52e8SDavid du Colombier el = el->tl;
19922d8b52e8SDavid du Colombier key->pub.q = mp = asn1mpint(&el->hd);
19932d8b52e8SDavid du Colombier if(mp == nil)
19942d8b52e8SDavid du Colombier goto errret;
19952d8b52e8SDavid du Colombier
19962d8b52e8SDavid du Colombier el = el->tl;
19972d8b52e8SDavid du Colombier key->pub.alpha = mp = asn1mpint(&el->hd);
19982d8b52e8SDavid du Colombier if(mp == nil)
19992d8b52e8SDavid du Colombier goto errret;
20002d8b52e8SDavid du Colombier
20012d8b52e8SDavid du Colombier el = el->tl;
20022d8b52e8SDavid du Colombier key->pub.key = mp = asn1mpint(&el->hd);
20032d8b52e8SDavid du Colombier if(mp == nil)
20042d8b52e8SDavid du Colombier goto errret;
20052d8b52e8SDavid du Colombier
20062d8b52e8SDavid du Colombier el = el->tl;
20072d8b52e8SDavid du Colombier key->secret = mp = asn1mpint(&el->hd);
20082d8b52e8SDavid du Colombier if(mp == nil)
20092d8b52e8SDavid du Colombier goto errret;
20102d8b52e8SDavid du Colombier
20112d8b52e8SDavid du Colombier return key;
20122d8b52e8SDavid du Colombier errret:
20132d8b52e8SDavid du Colombier dsaprivfree(key);
20142d8b52e8SDavid du Colombier return nil;
20152d8b52e8SDavid du Colombier }
20162d8b52e8SDavid du Colombier
20179a747e4fSDavid du Colombier static mpint*
asn1mpint(Elem * e)20189a747e4fSDavid du Colombier asn1mpint(Elem *e)
20199a747e4fSDavid du Colombier {
20209a747e4fSDavid du Colombier Bytes *b;
20219a747e4fSDavid du Colombier mpint *mp;
20229a747e4fSDavid du Colombier int v;
20239a747e4fSDavid du Colombier
20249a747e4fSDavid du Colombier if(is_int(e, &v))
20259a747e4fSDavid du Colombier return itomp(v, nil);
20269a747e4fSDavid du Colombier if(is_bigint(e, &b)) {
20279a747e4fSDavid du Colombier mp = betomp(b->data, b->len, nil);
20289a747e4fSDavid du Colombier freebytes(b);
20299a747e4fSDavid du Colombier return mp;
20309a747e4fSDavid du Colombier }
20319a747e4fSDavid du Colombier return nil;
20329a747e4fSDavid du Colombier }
20339a747e4fSDavid du Colombier
2034d9306527SDavid du Colombier static mpint*
pkcs1pad(Bytes * b,mpint * modulus)2035d9306527SDavid du Colombier pkcs1pad(Bytes *b, mpint *modulus)
2036d9306527SDavid du Colombier {
2037d9306527SDavid du Colombier int n = (mpsignif(modulus)+7)/8;
2038d9306527SDavid du Colombier int pm1, i;
2039d9306527SDavid du Colombier uchar *p;
2040d9306527SDavid du Colombier mpint *mp;
2041d9306527SDavid du Colombier
2042d9306527SDavid du Colombier pm1 = n - 1 - b->len;
2043d9306527SDavid du Colombier p = (uchar*)emalloc(n);
2044d9306527SDavid du Colombier p[0] = 0;
2045d9306527SDavid du Colombier p[1] = 1;
2046d9306527SDavid du Colombier for(i = 2; i < pm1; i++)
2047d9306527SDavid du Colombier p[i] = 0xFF;
2048d9306527SDavid du Colombier p[pm1] = 0;
2049d9306527SDavid du Colombier memcpy(&p[pm1+1], b->data, b->len);
2050d9306527SDavid du Colombier mp = betomp(p, n, nil);
2051d9306527SDavid du Colombier free(p);
2052d9306527SDavid du Colombier return mp;
2053d9306527SDavid du Colombier }
2054d9306527SDavid du Colombier
20559a747e4fSDavid du Colombier RSApriv*
asn1toRSApriv(uchar * kd,int kn)20569a747e4fSDavid du Colombier asn1toRSApriv(uchar *kd, int kn)
20579a747e4fSDavid du Colombier {
20589a747e4fSDavid du Colombier Bytes *b;
20599a747e4fSDavid du Colombier RSApriv *key;
20609a747e4fSDavid du Colombier
20619a747e4fSDavid du Colombier b = makebytes(kd, kn);
20629a747e4fSDavid du Colombier key = decode_rsaprivkey(b);
20639a747e4fSDavid du Colombier freebytes(b);
20649a747e4fSDavid du Colombier return key;
20659a747e4fSDavid du Colombier }
206680ee5cbfSDavid du Colombier
20672d8b52e8SDavid du Colombier DSApriv*
asn1toDSApriv(uchar * kd,int kn)20682d8b52e8SDavid du Colombier asn1toDSApriv(uchar *kd, int kn)
20692d8b52e8SDavid du Colombier {
20702d8b52e8SDavid du Colombier Bytes *b;
20712d8b52e8SDavid du Colombier DSApriv *key;
20722d8b52e8SDavid du Colombier
20732d8b52e8SDavid du Colombier b = makebytes(kd, kn);
20742d8b52e8SDavid du Colombier key = decode_dsaprivkey(b);
20752d8b52e8SDavid du Colombier freebytes(b);
20762d8b52e8SDavid du Colombier return key;
20772d8b52e8SDavid du Colombier }
20782d8b52e8SDavid du Colombier
20793ff48bf5SDavid du Colombier /*
20803ff48bf5SDavid du Colombier * digest(CertificateInfo)
20813ff48bf5SDavid du Colombier * Our ASN.1 library doesn't return pointers into the original
20823ff48bf5SDavid du Colombier * data array, so we need to do a little hand decoding.
20833ff48bf5SDavid du Colombier */
20843ff48bf5SDavid du Colombier static void
digest_certinfo(Bytes * cert,DigestFun digestfun,uchar * digest)20853ff48bf5SDavid du Colombier digest_certinfo(Bytes *cert, DigestFun digestfun, uchar *digest)
20863ff48bf5SDavid du Colombier {
20873ff48bf5SDavid du Colombier uchar *info, *p, *pend;
20883ff48bf5SDavid du Colombier ulong infolen;
20893ff48bf5SDavid du Colombier int isconstr, length;
20903ff48bf5SDavid du Colombier Tag tag;
20913ff48bf5SDavid du Colombier Elem elem;
20923ff48bf5SDavid du Colombier
20933ff48bf5SDavid du Colombier p = cert->data;
20943ff48bf5SDavid du Colombier pend = cert->data + cert->len;
20953ff48bf5SDavid du Colombier if(tag_decode(&p, pend, &tag, &isconstr) != ASN_OK ||
20963ff48bf5SDavid du Colombier tag.class != Universal || tag.num != SEQUENCE ||
20973ff48bf5SDavid du Colombier length_decode(&p, pend, &length) != ASN_OK ||
209839734e7eSDavid du Colombier p+length > pend ||
209939734e7eSDavid du Colombier p+length < p)
21003ff48bf5SDavid du Colombier return;
21013ff48bf5SDavid du Colombier info = p;
210292fd5f07SDavid du Colombier if(ber_decode(&p, pend, &elem) != ASN_OK)
210392fd5f07SDavid du Colombier return;
210492fd5f07SDavid du Colombier freevalfields(&elem.val);
210592fd5f07SDavid du Colombier if(elem.tag.num != SEQUENCE)
21063ff48bf5SDavid du Colombier return;
21073ff48bf5SDavid du Colombier infolen = p - info;
21083ff48bf5SDavid du Colombier (*digestfun)(info, infolen, digest, nil);
21093ff48bf5SDavid du Colombier }
21103ff48bf5SDavid du Colombier
21113ff48bf5SDavid du Colombier static char*
verify_signature(Bytes * signature,RSApub * pk,uchar * edigest,Elem ** psigalg)21121075affeSDavid du Colombier verify_signature(Bytes* signature, RSApub *pk, uchar *edigest, Elem **psigalg)
21133ff48bf5SDavid du Colombier {
21143ff48bf5SDavid du Colombier Elem e;
21153ff48bf5SDavid du Colombier Elist *el;
21163ff48bf5SDavid du Colombier Bytes *digest;
21173ff48bf5SDavid du Colombier uchar *pkcs1buf, *buf;
21183ff48bf5SDavid du Colombier int buflen;
21193ff48bf5SDavid du Colombier mpint *pkcs1;
212039734e7eSDavid du Colombier int nlen;
212192fd5f07SDavid du Colombier char *err;
212292fd5f07SDavid du Colombier
212392fd5f07SDavid du Colombier err = nil;
212492fd5f07SDavid du Colombier pkcs1buf = nil;
212539734e7eSDavid du Colombier
212639734e7eSDavid du Colombier /* one less than the byte length of the modulus */
212739734e7eSDavid du Colombier nlen = (mpsignif(pk->n)-1)/8;
21283ff48bf5SDavid du Colombier
21293ff48bf5SDavid du Colombier /* see 9.2.1 of rfc2437 */
21303ff48bf5SDavid du Colombier pkcs1 = betomp(signature->data, signature->len, nil);
21313ff48bf5SDavid du Colombier mpexp(pkcs1, pk->ek, pk->n, pkcs1);
21323ff48bf5SDavid du Colombier buflen = mptobe(pkcs1, nil, 0, &pkcs1buf);
21333ff48bf5SDavid du Colombier buf = pkcs1buf;
213492fd5f07SDavid du Colombier if(buflen != nlen || buf[0] != 1) {
213592fd5f07SDavid du Colombier err = "expected 1";
213692fd5f07SDavid du Colombier goto end;
213792fd5f07SDavid du Colombier }
21383ff48bf5SDavid du Colombier buf++;
21393ff48bf5SDavid du Colombier while(buf[0] == 0xff)
21403ff48bf5SDavid du Colombier buf++;
214192fd5f07SDavid du Colombier if(buf[0] != 0) {
214292fd5f07SDavid du Colombier err = "expected 0";
214392fd5f07SDavid du Colombier goto end;
214492fd5f07SDavid du Colombier }
21453ff48bf5SDavid du Colombier buf++;
21463ff48bf5SDavid du Colombier buflen -= buf-pkcs1buf;
21473ff48bf5SDavid du Colombier if(decode(buf, buflen, &e) != ASN_OK || !is_seq(&e, &el) || elistlen(el) != 2 ||
214892fd5f07SDavid du Colombier !is_octetstring(&el->tl->hd, &digest)) {
214992fd5f07SDavid du Colombier err = "signature parse error";
215092fd5f07SDavid du Colombier goto end;
215192fd5f07SDavid du Colombier }
21521075affeSDavid du Colombier *psigalg = &el->hd;
21533ff48bf5SDavid du Colombier if(memcmp(digest->data, edigest, digest->len) == 0)
215492fd5f07SDavid du Colombier goto end;
215592fd5f07SDavid du Colombier err = "digests did not match";
215692fd5f07SDavid du Colombier
215792fd5f07SDavid du Colombier end:
215892fd5f07SDavid du Colombier if(pkcs1 != nil)
215992fd5f07SDavid du Colombier mpfree(pkcs1);
216092fd5f07SDavid du Colombier if(pkcs1buf != nil)
216192fd5f07SDavid du Colombier free(pkcs1buf);
216292fd5f07SDavid du Colombier return err;
21633ff48bf5SDavid du Colombier }
21643ff48bf5SDavid du Colombier
216580ee5cbfSDavid du Colombier RSApub*
X509toRSApub(uchar * cert,int ncert,char * name,int nname)216680ee5cbfSDavid du Colombier X509toRSApub(uchar *cert, int ncert, char *name, int nname)
216780ee5cbfSDavid du Colombier {
216880ee5cbfSDavid du Colombier char *e;
216980ee5cbfSDavid du Colombier Bytes *b;
217080ee5cbfSDavid du Colombier CertX509 *c;
217180ee5cbfSDavid du Colombier RSApub *pk;
217280ee5cbfSDavid du Colombier
217380ee5cbfSDavid du Colombier b = makebytes(cert, ncert);
217480ee5cbfSDavid du Colombier c = decode_cert(b);
217580ee5cbfSDavid du Colombier freebytes(b);
217680ee5cbfSDavid du Colombier if(c == nil)
217780ee5cbfSDavid du Colombier return nil;
217880ee5cbfSDavid du Colombier if(name != nil && c->subject != nil){
217980ee5cbfSDavid du Colombier e = strchr(c->subject, ',');
218080ee5cbfSDavid du Colombier if(e != nil)
21812d8b52e8SDavid du Colombier *e = 0; /* take just CN part of Distinguished Name */
218280ee5cbfSDavid du Colombier strncpy(name, c->subject, nname);
218380ee5cbfSDavid du Colombier }
218480ee5cbfSDavid du Colombier pk = decode_rsapubkey(c->publickey);
218580ee5cbfSDavid du Colombier freecert(c);
218680ee5cbfSDavid du Colombier return pk;
218780ee5cbfSDavid du Colombier }
21883ff48bf5SDavid du Colombier
2189*6ca6a3e7SDavid du Colombier int
getalgo(Elem * e)2190*6ca6a3e7SDavid du Colombier getalgo(Elem *e)
2191*6ca6a3e7SDavid du Colombier {
2192*6ca6a3e7SDavid du Colombier Value *v;
2193*6ca6a3e7SDavid du Colombier Elist *el;
2194*6ca6a3e7SDavid du Colombier int a;
2195*6ca6a3e7SDavid du Colombier
2196*6ca6a3e7SDavid du Colombier if((a = parse_alg(e)) >= 0)
2197*6ca6a3e7SDavid du Colombier return a;
2198*6ca6a3e7SDavid du Colombier v = &e->val;
2199*6ca6a3e7SDavid du Colombier if(v->tag == VSeq){
2200*6ca6a3e7SDavid du Colombier print("Seq\n");
2201*6ca6a3e7SDavid du Colombier for(el = v->u.seqval; el!=nil; el = el->tl){
2202*6ca6a3e7SDavid du Colombier if((a = getalgo(&el->hd)) >= 0)
2203*6ca6a3e7SDavid du Colombier return a;
2204*6ca6a3e7SDavid du Colombier }
2205*6ca6a3e7SDavid du Colombier }
2206*6ca6a3e7SDavid du Colombier return -1;
2207*6ca6a3e7SDavid du Colombier }
2208*6ca6a3e7SDavid du Colombier
2209*6ca6a3e7SDavid du Colombier static void edump(Elem e);
2210*6ca6a3e7SDavid du Colombier
2211*6ca6a3e7SDavid du Colombier RSApub*
asn1toRSApub(uchar * der,int nder)2212*6ca6a3e7SDavid du Colombier asn1toRSApub(uchar *der, int nder)
2213*6ca6a3e7SDavid du Colombier {
2214*6ca6a3e7SDavid du Colombier Elem e;
2215*6ca6a3e7SDavid du Colombier Elist *el, *l;
2216*6ca6a3e7SDavid du Colombier int n;
2217*6ca6a3e7SDavid du Colombier Bits *b;
2218*6ca6a3e7SDavid du Colombier RSApub *key;
2219*6ca6a3e7SDavid du Colombier mpint *mp;
2220*6ca6a3e7SDavid du Colombier
2221*6ca6a3e7SDavid du Colombier if(decode(der, nder, &e) != ASN_OK){
2222*6ca6a3e7SDavid du Colombier print("didn't parse\n");
2223*6ca6a3e7SDavid du Colombier return nil;
2224*6ca6a3e7SDavid du Colombier }
2225*6ca6a3e7SDavid du Colombier if(!is_seq(&e, &el)){
2226*6ca6a3e7SDavid du Colombier print("no seq");
2227*6ca6a3e7SDavid du Colombier return nil;
2228*6ca6a3e7SDavid du Colombier }
2229*6ca6a3e7SDavid du Colombier if((n = elistlen(el)) != 2){
2230*6ca6a3e7SDavid du Colombier print("bad length %d\n", n);
2231*6ca6a3e7SDavid du Colombier return nil;
2232*6ca6a3e7SDavid du Colombier }
2233*6ca6a3e7SDavid du Colombier if((n = getalgo(&el->hd)) < 0){
2234*6ca6a3e7SDavid du Colombier print("no algo\n");
2235*6ca6a3e7SDavid du Colombier return nil;
2236*6ca6a3e7SDavid du Colombier }
2237*6ca6a3e7SDavid du Colombier if(n != 0){
2238*6ca6a3e7SDavid du Colombier print("cant do algorithm %d\n", n);
2239*6ca6a3e7SDavid du Colombier return nil;
2240*6ca6a3e7SDavid du Colombier }
2241*6ca6a3e7SDavid du Colombier if(!is_bitstring(&el->tl->hd, &b)){
2242*6ca6a3e7SDavid du Colombier print("no bits\n");
2243*6ca6a3e7SDavid du Colombier return nil;
2244*6ca6a3e7SDavid du Colombier }
2245*6ca6a3e7SDavid du Colombier if(decode(b->data, b->len, &e) != ASN_OK){
2246*6ca6a3e7SDavid du Colombier print("no second decode\n");
2247*6ca6a3e7SDavid du Colombier return nil;
2248*6ca6a3e7SDavid du Colombier }
2249*6ca6a3e7SDavid du Colombier if(!is_seq(&e, &el)){
2250*6ca6a3e7SDavid du Colombier print("no second seq\n");
2251*6ca6a3e7SDavid du Colombier return nil;
2252*6ca6a3e7SDavid du Colombier }
2253*6ca6a3e7SDavid du Colombier if(elistlen(el) != 2){
2254*6ca6a3e7SDavid du Colombier print("no second length\n");
2255*6ca6a3e7SDavid du Colombier return nil;
2256*6ca6a3e7SDavid du Colombier }
2257*6ca6a3e7SDavid du Colombier key = rsapuballoc();
2258*6ca6a3e7SDavid du Colombier
2259*6ca6a3e7SDavid du Colombier l = el;
2260*6ca6a3e7SDavid du Colombier
2261*6ca6a3e7SDavid du Colombier key->n = mp = asn1mpint(&el->hd);
2262*6ca6a3e7SDavid du Colombier if(mp == nil)
2263*6ca6a3e7SDavid du Colombier goto errret;
2264*6ca6a3e7SDavid du Colombier
2265*6ca6a3e7SDavid du Colombier el = el->tl;
2266*6ca6a3e7SDavid du Colombier key->ek = mp = asn1mpint(&el->hd);
2267*6ca6a3e7SDavid du Colombier if(mp == nil)
2268*6ca6a3e7SDavid du Colombier goto errret;
2269*6ca6a3e7SDavid du Colombier
2270*6ca6a3e7SDavid du Colombier if(l != nil)
2271*6ca6a3e7SDavid du Colombier freeelist(l);
2272*6ca6a3e7SDavid du Colombier return key;
2273*6ca6a3e7SDavid du Colombier errret:
2274*6ca6a3e7SDavid du Colombier if(l != nil)
2275*6ca6a3e7SDavid du Colombier freeelist(l);
2276*6ca6a3e7SDavid du Colombier rsapubfree(key);
2277*6ca6a3e7SDavid du Colombier return nil;
2278*6ca6a3e7SDavid du Colombier }
2279*6ca6a3e7SDavid du Colombier
22803ff48bf5SDavid du Colombier char*
X509verify(uchar * cert,int ncert,RSApub * pk)22813ff48bf5SDavid du Colombier X509verify(uchar *cert, int ncert, RSApub *pk)
22823ff48bf5SDavid du Colombier {
22833ff48bf5SDavid du Colombier char *e;
22843ff48bf5SDavid du Colombier Bytes *b;
22853ff48bf5SDavid du Colombier CertX509 *c;
22863ff48bf5SDavid du Colombier uchar digest[SHA1dlen];
22871075affeSDavid du Colombier Elem *sigalg;
22883ff48bf5SDavid du Colombier
22893ff48bf5SDavid du Colombier b = makebytes(cert, ncert);
22903ff48bf5SDavid du Colombier c = decode_cert(b);
22913ff48bf5SDavid du Colombier if(c != nil)
22923ff48bf5SDavid du Colombier digest_certinfo(b, digestalg[c->signature_alg], digest);
22933ff48bf5SDavid du Colombier freebytes(b);
22943ff48bf5SDavid du Colombier if(c == nil)
22951075affeSDavid du Colombier return "cannot decode cert";
22961075affeSDavid du Colombier e = verify_signature(c->signature, pk, digest, &sigalg);
22973ff48bf5SDavid du Colombier freecert(c);
22983ff48bf5SDavid du Colombier return e;
22993ff48bf5SDavid du Colombier }
2300d9306527SDavid du Colombier
2301d9306527SDavid du Colombier /* ------- Elem constructors ---------- */
2302d9306527SDavid du Colombier static Elem
Null(void)2303d9306527SDavid du Colombier Null(void)
2304d9306527SDavid du Colombier {
2305d9306527SDavid du Colombier Elem e;
2306d9306527SDavid du Colombier
2307d9306527SDavid du Colombier e.tag.class = Universal;
2308d9306527SDavid du Colombier e.tag.num = NULLTAG;
2309d9306527SDavid du Colombier e.val.tag = VNull;
2310d9306527SDavid du Colombier return e;
2311d9306527SDavid du Colombier }
2312d9306527SDavid du Colombier
2313d9306527SDavid du Colombier static Elem
mkint(int j)2314d9306527SDavid du Colombier mkint(int j)
2315d9306527SDavid du Colombier {
2316d9306527SDavid du Colombier Elem e;
2317d9306527SDavid du Colombier
2318d9306527SDavid du Colombier e.tag.class = Universal;
2319d9306527SDavid du Colombier e.tag.num = INTEGER;
2320d9306527SDavid du Colombier e.val.tag = VInt;
2321d9306527SDavid du Colombier e.val.u.intval = j;
2322d9306527SDavid du Colombier return e;
2323d9306527SDavid du Colombier }
2324d9306527SDavid du Colombier
2325d9306527SDavid du Colombier static Elem
mkbigint(mpint * p)2326d9306527SDavid du Colombier mkbigint(mpint *p)
2327d9306527SDavid du Colombier {
2328d9306527SDavid du Colombier Elem e;
2329d9306527SDavid du Colombier uchar *buf;
2330d9306527SDavid du Colombier int buflen;
2331d9306527SDavid du Colombier
2332d9306527SDavid du Colombier e.tag.class = Universal;
2333d9306527SDavid du Colombier e.tag.num = INTEGER;
2334d9306527SDavid du Colombier e.val.tag = VBigInt;
2335d9306527SDavid du Colombier buflen = mptobe(p, nil, 0, &buf);
2336d9306527SDavid du Colombier e.val.u.bigintval = makebytes(buf, buflen);
2337d9306527SDavid du Colombier free(buf);
2338d9306527SDavid du Colombier return e;
2339d9306527SDavid du Colombier }
2340d9306527SDavid du Colombier
2341d9306527SDavid du Colombier static Elem
mkstring(char * s)2342d9306527SDavid du Colombier mkstring(char *s)
2343d9306527SDavid du Colombier {
2344d9306527SDavid du Colombier Elem e;
2345d9306527SDavid du Colombier
2346d9306527SDavid du Colombier e.tag.class = Universal;
2347d9306527SDavid du Colombier e.tag.num = IA5String;
2348d9306527SDavid du Colombier e.val.tag = VString;
2349d9306527SDavid du Colombier e.val.u.stringval = estrdup(s);
2350d9306527SDavid du Colombier return e;
2351d9306527SDavid du Colombier }
2352d9306527SDavid du Colombier
2353d9306527SDavid du Colombier static Elem
mkoctet(uchar * buf,int buflen)2354d9306527SDavid du Colombier mkoctet(uchar *buf, int buflen)
2355d9306527SDavid du Colombier {
2356d9306527SDavid du Colombier Elem e;
2357d9306527SDavid du Colombier
2358d9306527SDavid du Colombier e.tag.class = Universal;
2359d9306527SDavid du Colombier e.tag.num = OCTET_STRING;
2360d9306527SDavid du Colombier e.val.tag = VOctets;
2361d9306527SDavid du Colombier e.val.u.octetsval = makebytes(buf, buflen);
2362d9306527SDavid du Colombier return e;
2363d9306527SDavid du Colombier }
2364d9306527SDavid du Colombier
2365d9306527SDavid du Colombier static Elem
mkbits(uchar * buf,int buflen)2366d9306527SDavid du Colombier mkbits(uchar *buf, int buflen)
2367d9306527SDavid du Colombier {
2368d9306527SDavid du Colombier Elem e;
2369d9306527SDavid du Colombier
2370d9306527SDavid du Colombier e.tag.class = Universal;
2371d9306527SDavid du Colombier e.tag.num = BIT_STRING;
2372d9306527SDavid du Colombier e.val.tag = VBitString;
2373d9306527SDavid du Colombier e.val.u.bitstringval = makebits(buf, buflen, 0);
2374d9306527SDavid du Colombier return e;
2375d9306527SDavid du Colombier }
2376d9306527SDavid du Colombier
2377d9306527SDavid du Colombier static Elem
mkutc(long t)2378d9306527SDavid du Colombier mkutc(long t)
2379d9306527SDavid du Colombier {
2380d9306527SDavid du Colombier Elem e;
2381d9306527SDavid du Colombier char utc[50];
2382d9306527SDavid du Colombier Tm *tm = gmtime(t);
2383d9306527SDavid du Colombier
2384d9306527SDavid du Colombier e.tag.class = Universal;
2385d9306527SDavid du Colombier e.tag.num = UTCTime;
2386d9306527SDavid du Colombier e.val.tag = VString;
2387d9306527SDavid du Colombier snprint(utc, 50, "%.2d%.2d%.2d%.2d%.2d%.2dZ",
2388d9306527SDavid du Colombier tm->year % 100, tm->mon+1, tm->mday, tm->hour, tm->min, tm->sec);
2389d9306527SDavid du Colombier e.val.u.stringval = estrdup(utc);
2390d9306527SDavid du Colombier return e;
2391d9306527SDavid du Colombier }
2392d9306527SDavid du Colombier
2393d9306527SDavid du Colombier static Elem
mkoid(Ints * oid)2394d9306527SDavid du Colombier mkoid(Ints *oid)
2395d9306527SDavid du Colombier {
2396d9306527SDavid du Colombier Elem e;
2397d9306527SDavid du Colombier
2398d9306527SDavid du Colombier e.tag.class = Universal;
2399d9306527SDavid du Colombier e.tag.num = OBJECT_ID;
2400d9306527SDavid du Colombier e.val.tag = VObjId;
2401d9306527SDavid du Colombier e.val.u.objidval = makeints(oid->data, oid->len);
2402d9306527SDavid du Colombier return e;
2403d9306527SDavid du Colombier }
2404d9306527SDavid du Colombier
2405d9306527SDavid du Colombier static Elem
mkseq(Elist * el)2406d9306527SDavid du Colombier mkseq(Elist *el)
2407d9306527SDavid du Colombier {
2408d9306527SDavid du Colombier Elem e;
2409d9306527SDavid du Colombier
2410d9306527SDavid du Colombier e.tag.class = Universal;
2411d9306527SDavid du Colombier e.tag.num = SEQUENCE;
2412d9306527SDavid du Colombier e.val.tag = VSeq;
2413d9306527SDavid du Colombier e.val.u.seqval = el;
2414d9306527SDavid du Colombier return e;
2415d9306527SDavid du Colombier }
2416d9306527SDavid du Colombier
2417d9306527SDavid du Colombier static Elem
mkset(Elist * el)2418d9306527SDavid du Colombier mkset(Elist *el)
2419d9306527SDavid du Colombier {
2420d9306527SDavid du Colombier Elem e;
2421d9306527SDavid du Colombier
2422d9306527SDavid du Colombier e.tag.class = Universal;
2423d9306527SDavid du Colombier e.tag.num = SETOF;
2424d9306527SDavid du Colombier e.val.tag = VSet;
2425d9306527SDavid du Colombier e.val.u.setval = el;
2426d9306527SDavid du Colombier return e;
2427d9306527SDavid du Colombier }
2428d9306527SDavid du Colombier
2429d9306527SDavid du Colombier static Elem
mkalg(int alg)2430d9306527SDavid du Colombier mkalg(int alg)
2431d9306527SDavid du Colombier {
2432d9306527SDavid du Colombier return mkseq(mkel(mkoid(alg_oid_tab[alg]), mkel(Null(), nil)));
2433d9306527SDavid du Colombier }
2434d9306527SDavid du Colombier
24351075affeSDavid du Colombier typedef struct Ints7pref {
2436d9306527SDavid du Colombier int len;
24371075affeSDavid du Colombier int data[7];
2438d9306527SDavid du Colombier char prefix[4];
24391075affeSDavid du Colombier } Ints7pref;
24401075affeSDavid du Colombier Ints7pref DN_oid[] = {
24411075affeSDavid du Colombier {4, 2, 5, 4, 6, 0, 0, 0, "C="},
24421075affeSDavid du Colombier {4, 2, 5, 4, 8, 0, 0, 0, "ST="},
24431075affeSDavid du Colombier {4, 2, 5, 4, 7, 0, 0, 0, "L="},
24441075affeSDavid du Colombier {4, 2, 5, 4, 10, 0, 0, 0, "O="},
24451075affeSDavid du Colombier {4, 2, 5, 4, 11, 0, 0, 0, "OU="},
24461075affeSDavid du Colombier {4, 2, 5, 4, 3, 0, 0, 0, "CN="},
24471075affeSDavid du Colombier {7, 1,2,840,113549,1,9,1, "E="},
2448d9306527SDavid du Colombier };
2449d9306527SDavid du Colombier
2450d9306527SDavid du Colombier static Elem
mkname(Ints7pref * oid,char * subj)24511075affeSDavid du Colombier mkname(Ints7pref *oid, char *subj)
2452d9306527SDavid du Colombier {
2453d9306527SDavid du Colombier return mkset(mkel(mkseq(mkel(mkoid((Ints*)oid), mkel(mkstring(subj), nil))), nil));
2454d9306527SDavid du Colombier }
2455d9306527SDavid du Colombier
2456d9306527SDavid du Colombier static Elem
mkDN(char * dn)2457d9306527SDavid du Colombier mkDN(char *dn)
2458d9306527SDavid du Colombier {
2459d9306527SDavid du Colombier int i, j, nf;
2460d9306527SDavid du Colombier char *f[20], *prefix, *d2 = estrdup(dn);
2461d9306527SDavid du Colombier Elist* el = nil;
2462d9306527SDavid du Colombier
2463d9306527SDavid du Colombier nf = tokenize(d2, f, nelem(f));
2464d9306527SDavid du Colombier for(i=nf-1; i>=0; i--){
2465d9306527SDavid du Colombier for(j=0; j<nelem(DN_oid); j++){
2466d9306527SDavid du Colombier prefix = DN_oid[j].prefix;
2467d9306527SDavid du Colombier if(strncmp(f[i],prefix,strlen(prefix))==0){
2468d9306527SDavid du Colombier el = mkel(mkname(&DN_oid[j],f[i]+strlen(prefix)), el);
2469d9306527SDavid du Colombier break;
2470d9306527SDavid du Colombier }
2471d9306527SDavid du Colombier }
2472d9306527SDavid du Colombier }
2473d9306527SDavid du Colombier free(d2);
2474d9306527SDavid du Colombier return mkseq(el);
2475d9306527SDavid du Colombier }
2476d9306527SDavid du Colombier
2477*6ca6a3e7SDavid du Colombier uchar*
RSApubtoasn1(RSApub * pub,int * keylen)2478*6ca6a3e7SDavid du Colombier RSApubtoasn1(RSApub *pub, int *keylen)
2479*6ca6a3e7SDavid du Colombier {
2480*6ca6a3e7SDavid du Colombier Elem pubkey;
2481*6ca6a3e7SDavid du Colombier Bytes *pkbytes;
2482*6ca6a3e7SDavid du Colombier uchar *key;
2483*6ca6a3e7SDavid du Colombier
2484*6ca6a3e7SDavid du Colombier key = nil;
2485*6ca6a3e7SDavid du Colombier pubkey = mkseq(mkel(mkbigint(pub->n),mkel(mkint(mptoi(pub->ek)),nil)));
2486*6ca6a3e7SDavid du Colombier if(encode(pubkey, &pkbytes) != ASN_OK)
2487*6ca6a3e7SDavid du Colombier goto errret;
2488*6ca6a3e7SDavid du Colombier freevalfields(&pubkey.val);
2489*6ca6a3e7SDavid du Colombier pubkey = mkseq(
2490*6ca6a3e7SDavid du Colombier mkel(mkalg(ALG_rsaEncryption),
2491*6ca6a3e7SDavid du Colombier mkel(mkbits(pkbytes->data, pkbytes->len),
2492*6ca6a3e7SDavid du Colombier nil)));
2493*6ca6a3e7SDavid du Colombier freebytes(pkbytes);
2494*6ca6a3e7SDavid du Colombier if(encode(pubkey, &pkbytes) != ASN_OK)
2495*6ca6a3e7SDavid du Colombier goto errret;
2496*6ca6a3e7SDavid du Colombier if(keylen)
2497*6ca6a3e7SDavid du Colombier *keylen = pkbytes->len;
2498*6ca6a3e7SDavid du Colombier key = malloc(pkbytes->len);
2499*6ca6a3e7SDavid du Colombier memmove(key, pkbytes->data, pkbytes->len);
2500*6ca6a3e7SDavid du Colombier free(pkbytes);
2501*6ca6a3e7SDavid du Colombier errret:
2502*6ca6a3e7SDavid du Colombier freevalfields(&pubkey.val);
2503*6ca6a3e7SDavid du Colombier return key;
2504*6ca6a3e7SDavid du Colombier }
2505d9306527SDavid du Colombier
2506d9306527SDavid du Colombier uchar*
X509gen(RSApriv * priv,char * subj,ulong valid[2],int * certlen)2507d9306527SDavid du Colombier X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen)
2508d9306527SDavid du Colombier {
2509d9306527SDavid du Colombier int serial = 0;
2510d9306527SDavid du Colombier uchar *cert = nil;
2511d9306527SDavid du Colombier RSApub *pk = rsaprivtopub(priv);
2512d9306527SDavid du Colombier Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
2513d9306527SDavid du Colombier Elem e, certinfo, issuer, subject, pubkey, validity, sig;
2514d9306527SDavid du Colombier uchar digest[MD5dlen], *buf;
2515d9306527SDavid du Colombier int buflen;
2516d9306527SDavid du Colombier mpint *pkcs1;
2517d9306527SDavid du Colombier
2518d9306527SDavid du Colombier e.val.tag = VInt; /* so freevalfields at errret is no-op */
2519d9306527SDavid du Colombier issuer = mkDN(subj);
2520d9306527SDavid du Colombier subject = mkDN(subj);
2521d9306527SDavid du Colombier pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
2522d9306527SDavid du Colombier if(encode(pubkey, &pkbytes) != ASN_OK)
2523d9306527SDavid du Colombier goto errret;
2524d9306527SDavid du Colombier freevalfields(&pubkey.val);
2525d9306527SDavid du Colombier pubkey = mkseq(
2526d9306527SDavid du Colombier mkel(mkalg(ALG_rsaEncryption),
2527d9306527SDavid du Colombier mkel(mkbits(pkbytes->data, pkbytes->len),
2528d9306527SDavid du Colombier nil)));
2529d9306527SDavid du Colombier freebytes(pkbytes);
2530d9306527SDavid du Colombier validity = mkseq(
2531d9306527SDavid du Colombier mkel(mkutc(valid[0]),
2532d9306527SDavid du Colombier mkel(mkutc(valid[1]),
2533d9306527SDavid du Colombier nil)));
2534d9306527SDavid du Colombier certinfo = mkseq(
2535d9306527SDavid du Colombier mkel(mkint(serial),
2536d9306527SDavid du Colombier mkel(mkalg(ALG_md5WithRSAEncryption),
2537d9306527SDavid du Colombier mkel(issuer,
2538d9306527SDavid du Colombier mkel(validity,
2539d9306527SDavid du Colombier mkel(subject,
2540d9306527SDavid du Colombier mkel(pubkey,
2541d9306527SDavid du Colombier nil)))))));
2542d9306527SDavid du Colombier if(encode(certinfo, &certinfobytes) != ASN_OK)
2543d9306527SDavid du Colombier goto errret;
2544d9306527SDavid du Colombier md5(certinfobytes->data, certinfobytes->len, digest, 0);
2545d9306527SDavid du Colombier freebytes(certinfobytes);
2546d9306527SDavid du Colombier sig = mkseq(
25471075affeSDavid du Colombier mkel(mkalg(ALG_md5),
2548d9306527SDavid du Colombier mkel(mkoctet(digest, MD5dlen),
2549d9306527SDavid du Colombier nil)));
2550d9306527SDavid du Colombier if(encode(sig, &sigbytes) != ASN_OK)
2551d9306527SDavid du Colombier goto errret;
2552d9306527SDavid du Colombier pkcs1 = pkcs1pad(sigbytes, pk->n);
2553d9306527SDavid du Colombier freebytes(sigbytes);
2554d9306527SDavid du Colombier rsadecrypt(priv, pkcs1, pkcs1);
2555d9306527SDavid du Colombier buflen = mptobe(pkcs1, nil, 0, &buf);
2556d9306527SDavid du Colombier mpfree(pkcs1);
2557d9306527SDavid du Colombier e = mkseq(
2558d9306527SDavid du Colombier mkel(certinfo,
2559d9306527SDavid du Colombier mkel(mkalg(ALG_md5WithRSAEncryption),
2560d9306527SDavid du Colombier mkel(mkbits(buf, buflen),
2561d9306527SDavid du Colombier nil))));
2562d9306527SDavid du Colombier free(buf);
2563d9306527SDavid du Colombier if(encode(e, &certbytes) != ASN_OK)
2564d9306527SDavid du Colombier goto errret;
2565d9306527SDavid du Colombier if(certlen)
2566d9306527SDavid du Colombier *certlen = certbytes->len;
2567d9306527SDavid du Colombier cert = certbytes->data;
2568d9306527SDavid du Colombier errret:
2569d9306527SDavid du Colombier freevalfields(&e.val);
2570d9306527SDavid du Colombier return cert;
2571d9306527SDavid du Colombier }
2572d9306527SDavid du Colombier
25731075affeSDavid du Colombier uchar*
X509req(RSApriv * priv,char * subj,int * certlen)25741075affeSDavid du Colombier X509req(RSApriv *priv, char *subj, int *certlen)
25751075affeSDavid du Colombier {
25761075affeSDavid du Colombier /* RFC 2314, PKCS #10 Certification Request Syntax */
25771075affeSDavid du Colombier int version = 0;
25781075affeSDavid du Colombier uchar *cert = nil;
25791075affeSDavid du Colombier RSApub *pk = rsaprivtopub(priv);
25801075affeSDavid du Colombier Bytes *certbytes, *pkbytes, *certinfobytes, *sigbytes;
25811075affeSDavid du Colombier Elem e, certinfo, subject, pubkey, sig;
25821075affeSDavid du Colombier uchar digest[MD5dlen], *buf;
25831075affeSDavid du Colombier int buflen;
25841075affeSDavid du Colombier mpint *pkcs1;
25851075affeSDavid du Colombier
25861075affeSDavid du Colombier e.val.tag = VInt; /* so freevalfields at errret is no-op */
25871075affeSDavid du Colombier subject = mkDN(subj);
25881075affeSDavid du Colombier pubkey = mkseq(mkel(mkbigint(pk->n),mkel(mkint(mptoi(pk->ek)),nil)));
25891075affeSDavid du Colombier if(encode(pubkey, &pkbytes) != ASN_OK)
25901075affeSDavid du Colombier goto errret;
25911075affeSDavid du Colombier freevalfields(&pubkey.val);
25921075affeSDavid du Colombier pubkey = mkseq(
25931075affeSDavid du Colombier mkel(mkalg(ALG_rsaEncryption),
25941075affeSDavid du Colombier mkel(mkbits(pkbytes->data, pkbytes->len),
25951075affeSDavid du Colombier nil)));
25961075affeSDavid du Colombier freebytes(pkbytes);
25971075affeSDavid du Colombier certinfo = mkseq(
25981075affeSDavid du Colombier mkel(mkint(version),
25991075affeSDavid du Colombier mkel(subject,
26001075affeSDavid du Colombier mkel(pubkey,
26011075affeSDavid du Colombier nil))));
26021075affeSDavid du Colombier if(encode(certinfo, &certinfobytes) != ASN_OK)
26031075affeSDavid du Colombier goto errret;
26041075affeSDavid du Colombier md5(certinfobytes->data, certinfobytes->len, digest, 0);
26051075affeSDavid du Colombier freebytes(certinfobytes);
26061075affeSDavid du Colombier sig = mkseq(
26071075affeSDavid du Colombier mkel(mkalg(ALG_md5),
26081075affeSDavid du Colombier mkel(mkoctet(digest, MD5dlen),
26091075affeSDavid du Colombier nil)));
26101075affeSDavid du Colombier if(encode(sig, &sigbytes) != ASN_OK)
26111075affeSDavid du Colombier goto errret;
26121075affeSDavid du Colombier pkcs1 = pkcs1pad(sigbytes, pk->n);
26131075affeSDavid du Colombier freebytes(sigbytes);
26141075affeSDavid du Colombier rsadecrypt(priv, pkcs1, pkcs1);
26151075affeSDavid du Colombier buflen = mptobe(pkcs1, nil, 0, &buf);
26161075affeSDavid du Colombier mpfree(pkcs1);
26171075affeSDavid du Colombier e = mkseq(
26181075affeSDavid du Colombier mkel(certinfo,
26191075affeSDavid du Colombier mkel(mkalg(ALG_md5),
26201075affeSDavid du Colombier mkel(mkbits(buf, buflen),
26211075affeSDavid du Colombier nil))));
26221075affeSDavid du Colombier free(buf);
26231075affeSDavid du Colombier if(encode(e, &certbytes) != ASN_OK)
26241075affeSDavid du Colombier goto errret;
26251075affeSDavid du Colombier if(certlen)
26261075affeSDavid du Colombier *certlen = certbytes->len;
26271075affeSDavid du Colombier cert = certbytes->data;
26281075affeSDavid du Colombier errret:
26291075affeSDavid du Colombier freevalfields(&e.val);
26301075affeSDavid du Colombier return cert;
26311075affeSDavid du Colombier }
26321075affeSDavid du Colombier
2633d9306527SDavid du Colombier static char*
tagdump(Tag tag)2634d9306527SDavid du Colombier tagdump(Tag tag)
2635d9306527SDavid du Colombier {
2636d9306527SDavid du Colombier if(tag.class != Universal)
2637d9306527SDavid du Colombier return smprint("class%d,num%d", tag.class, tag.num);
2638d9306527SDavid du Colombier switch(tag.num){
2639ec46fab0SDavid du Colombier case BOOLEAN: return "BOOLEAN";
2640ec46fab0SDavid du Colombier case INTEGER: return "INTEGER";
2641ec46fab0SDavid du Colombier case BIT_STRING: return "BIT STRING";
2642ec46fab0SDavid du Colombier case OCTET_STRING: return "OCTET STRING";
2643ec46fab0SDavid du Colombier case NULLTAG: return "NULLTAG";
2644ec46fab0SDavid du Colombier case OBJECT_ID: return "OID";
2645ec46fab0SDavid du Colombier case ObjectDescriptor: return "OBJECT_DES";
2646ec46fab0SDavid du Colombier case EXTERNAL: return "EXTERNAL";
2647ec46fab0SDavid du Colombier case REAL: return "REAL";
2648ec46fab0SDavid du Colombier case ENUMERATED: return "ENUMERATED";
2649ec46fab0SDavid du Colombier case EMBEDDED_PDV: return "EMBEDDED PDV";
2650ec46fab0SDavid du Colombier case SEQUENCE: return "SEQUENCE";
2651ec46fab0SDavid du Colombier case SETOF: return "SETOF";
2652de8abbc9SDavid du Colombier case UTF8String: return "UTF8String";
2653ec46fab0SDavid du Colombier case NumericString: return "NumericString";
2654ec46fab0SDavid du Colombier case PrintableString: return "PrintableString";
2655ec46fab0SDavid du Colombier case TeletexString: return "TeletexString";
2656ec46fab0SDavid du Colombier case VideotexString: return "VideotexString";
2657ec46fab0SDavid du Colombier case IA5String: return "IA5String";
2658ec46fab0SDavid du Colombier case UTCTime: return "UTCTime";
2659ec46fab0SDavid du Colombier case GeneralizedTime: return "GeneralizedTime";
2660ec46fab0SDavid du Colombier case GraphicString: return "GraphicString";
2661ec46fab0SDavid du Colombier case VisibleString: return "VisibleString";
2662ec46fab0SDavid du Colombier case GeneralString: return "GeneralString";
2663ec46fab0SDavid du Colombier case UniversalString: return "UniversalString";
2664ec46fab0SDavid du Colombier case BMPString: return "BMPString";
2665d9306527SDavid du Colombier default:
2666d9306527SDavid du Colombier return smprint("Universal,num%d", tag.num);
2667d9306527SDavid du Colombier }
2668d9306527SDavid du Colombier }
2669d9306527SDavid du Colombier
2670d9306527SDavid du Colombier static void
edump(Elem e)2671d9306527SDavid du Colombier edump(Elem e)
2672d9306527SDavid du Colombier {
2673d9306527SDavid du Colombier Value v;
2674d9306527SDavid du Colombier Elist *el;
2675d9306527SDavid du Colombier int i;
2676d9306527SDavid du Colombier
2677d9306527SDavid du Colombier print("%s{", tagdump(e.tag));
2678d9306527SDavid du Colombier v = e.val;
2679d9306527SDavid du Colombier switch(v.tag){
2680d9306527SDavid du Colombier case VBool: print("Bool %d",v.u.boolval); break;
2681d9306527SDavid du Colombier case VInt: print("Int %d",v.u.intval); break;
2682d9306527SDavid du Colombier case VOctets: print("Octets[%d] %.2x%.2x...",v.u.octetsval->len,v.u.octetsval->data[0],v.u.octetsval->data[1]); break;
2683d9306527SDavid du Colombier case VBigInt: print("BigInt[%d] %.2x%.2x...",v.u.bigintval->len,v.u.bigintval->data[0],v.u.bigintval->data[1]); break;
2684d9306527SDavid du Colombier case VReal: print("Real..."); break;
2685d9306527SDavid du Colombier case VOther: print("Other..."); break;
2686*6ca6a3e7SDavid du Colombier case VBitString: print("BitString");
2687*6ca6a3e7SDavid du Colombier for(i = 0; i<v.u.bitstringval->len; i++)
2688*6ca6a3e7SDavid du Colombier print(" %02x", v.u.bitstringval->data[i]);
2689*6ca6a3e7SDavid du Colombier break;
2690d9306527SDavid du Colombier case VNull: print("Null"); break;
2691d9306527SDavid du Colombier case VEOC: print("EOC..."); break;
2692d9306527SDavid du Colombier case VObjId: print("ObjId");
2693d9306527SDavid du Colombier for(i = 0; i<v.u.objidval->len; i++)
2694d9306527SDavid du Colombier print(" %d", v.u.objidval->data[i]);
2695d9306527SDavid du Colombier break;
2696d9306527SDavid du Colombier case VString: print("String \"%s\"",v.u.stringval); break;
2697d9306527SDavid du Colombier case VSeq: print("Seq\n");
2698d9306527SDavid du Colombier for(el = v.u.seqval; el!=nil; el = el->tl)
2699d9306527SDavid du Colombier edump(el->hd);
2700d9306527SDavid du Colombier break;
2701d9306527SDavid du Colombier case VSet: print("Set\n");
2702d9306527SDavid du Colombier for(el = v.u.setval; el!=nil; el = el->tl)
2703d9306527SDavid du Colombier edump(el->hd);
2704d9306527SDavid du Colombier break;
2705d9306527SDavid du Colombier }
2706d9306527SDavid du Colombier print("}\n");
2707d9306527SDavid du Colombier }
2708d9306527SDavid du Colombier
2709d9306527SDavid du Colombier void
asn1dump(uchar * der,int len)2710d9306527SDavid du Colombier asn1dump(uchar *der, int len)
2711d9306527SDavid du Colombier {
2712d9306527SDavid du Colombier Elem e;
2713d9306527SDavid du Colombier
2714d9306527SDavid du Colombier if(decode(der, len, &e) != ASN_OK){
27151075affeSDavid du Colombier print("didn't parse\n");
2716d9306527SDavid du Colombier exits("didn't parse");
2717d9306527SDavid du Colombier }
2718d9306527SDavid du Colombier edump(e);
2719d9306527SDavid du Colombier }
27201075affeSDavid du Colombier
27211075affeSDavid du Colombier void
X509dump(uchar * cert,int ncert)27221075affeSDavid du Colombier X509dump(uchar *cert, int ncert)
27231075affeSDavid du Colombier {
27241075affeSDavid du Colombier char *e;
27251075affeSDavid du Colombier Bytes *b;
27261075affeSDavid du Colombier CertX509 *c;
27271075affeSDavid du Colombier RSApub *pk;
27281075affeSDavid du Colombier uchar digest[SHA1dlen];
27291075affeSDavid du Colombier Elem *sigalg;
27301075affeSDavid du Colombier
27311075affeSDavid du Colombier print("begin X509dump\n");
27321075affeSDavid du Colombier b = makebytes(cert, ncert);
27331075affeSDavid du Colombier c = decode_cert(b);
27341075affeSDavid du Colombier if(c != nil)
27351075affeSDavid du Colombier digest_certinfo(b, digestalg[c->signature_alg], digest);
27361075affeSDavid du Colombier freebytes(b);
27371075affeSDavid du Colombier if(c == nil){
27381075affeSDavid du Colombier print("cannot decode cert");
27391075affeSDavid du Colombier return;
27401075affeSDavid du Colombier }
27411075affeSDavid du Colombier
27421075affeSDavid du Colombier print("serial %d\n", c->serial);
27431075affeSDavid du Colombier print("issuer %s\n", c->issuer);
27441075affeSDavid du Colombier print("validity %s %s\n", c->validity_start, c->validity_end);
27451075affeSDavid du Colombier print("subject %s\n", c->subject);
27461075affeSDavid du Colombier pk = decode_rsapubkey(c->publickey);
27471075affeSDavid du Colombier print("pubkey e=%B n(%d)=%B\n", pk->ek, mpsignif(pk->n), pk->n);
27481075affeSDavid du Colombier
27491075affeSDavid du Colombier print("sigalg=%d digest=%.*H\n", c->signature_alg, MD5dlen, digest);
27501075affeSDavid du Colombier e = verify_signature(c->signature, pk, digest, &sigalg);
27511075affeSDavid du Colombier if(e==nil){
27521075affeSDavid du Colombier e = "nil (meaning ok)";
27531075affeSDavid du Colombier print("sigalg=\n");
27541075affeSDavid du Colombier if(sigalg)
27551075affeSDavid du Colombier edump(*sigalg);
27561075affeSDavid du Colombier }
27571075affeSDavid du Colombier print("self-signed verify_signature returns: %s\n", e);
27581075affeSDavid du Colombier
27591075affeSDavid du Colombier rsapubfree(pk);
27601075affeSDavid du Colombier freecert(c);
27611075affeSDavid du Colombier print("end X509dump\n");
27621075affeSDavid du Colombier }
2763