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