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