From bedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Sat, 15 Mar 2014 01:49:50 +0100 Subject: Lean and mean initial commit Not much functionality yet --- fmt_asn1generic.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 fmt_asn1generic.c (limited to 'fmt_asn1generic.c') diff --git a/fmt_asn1generic.c b/fmt_asn1generic.c new file mode 100644 index 0000000..c97ee96 --- /dev/null +++ b/fmt_asn1generic.c @@ -0,0 +1,139 @@ +#include +#include +#include "asn1.h" + +size_t fmt_asn1generic(char* dest,const char* fmt,...) { + size_t containerstack[100]; + size_t curinstack=0; + va_list args; + va_start(args,fmt); + unsigned long* application=0; + struct string* s; + struct oid* o; + struct string S; + size_t curlen=0; + size_t cursor=0; + size_t seqlen; + unsigned long desttag=0; + unsigned long appstore; + int stringtype; + while (*fmt) { + char* realdest=dest?dest+cursor:NULL; + switch (*fmt) { + case '*': // make next tag use APPLICATION with this tag + appstore=va_arg(args,unsigned long); + application=&appstore; + break; + case '0': // UNIVERSAL PRIMITIVE NULL length 0 + if (application) + curlen=fmt_asn1tag(realdest,APPLICATION,PRIMITIVE,_NULL); + else + curlen=fmt_asn1tag(realdest,UNIVERSAL,PRIMITIVE,_NULL); + application=NULL; + curlen+=fmt_asn1length(realdest?realdest+curlen:NULL,0); + break; + case 'i': // send integer + { + unsigned long i=va_arg(args,unsigned long); + if (application) + curlen=fmt_asn1int(realdest,APPLICATION,PRIMITIVE,*application,i); + else + curlen=fmt_asn1int(realdest,UNIVERSAL,PRIMITIVE,INTEGER,i); + application=NULL; + break; + } + case 'b': // send BIT_STRING, using struct string* as arg (expect l to be in bits, not bytes) + s=va_arg(args,struct string*); + if (application) + curlen=fmt_asn1bitstring(realdest,APPLICATION,PRIMITIVE,*application,s->s,s->l); + else + curlen=fmt_asn1bitstring(realdest,UNIVERSAL,PRIMITIVE,BIT_STRING,s->s,s->l); + application=NULL; + break; + case 'B': + stringtype=BIT_STRING; + goto stringcopy; + case 'A': + stringtype=IA5String; + goto stringcopy; + case 'P': + stringtype=PrintableString; + goto stringcopy; + case 'S': // send OCTET_STRING, using struct string* as arg + stringtype=OCTET_STRING; +stringcopy: + s=va_arg(args,struct string*); +copystring: + if (application) + curlen=fmt_asn1string(realdest,APPLICATION,PRIMITIVE,*application,s->s,s->l); + else + curlen=fmt_asn1string(realdest,UNIVERSAL,PRIMITIVE,stringtype,s->s,s->l); + application=NULL; + break; + case 't': + stringtype=UTCTIME; + goto stringcopy_alt; + case 'a': + stringtype=IA5String; + goto stringcopy_alt; + case 'p': + stringtype=PrintableString; + goto stringcopy_alt; + case 's': // send OCTET_STRING, using const char* with strlen() as arg + stringtype=OCTET_STRING; +stringcopy_alt: + S.s=va_arg(args,const char*); + S.l=strlen(S.s); + s=&S; + goto copystring; + case 'o': // send OBJECT_IDENTIFIER, using struct oid* as arg + o=va_arg(args,struct oid*); + if (application) + curlen=fmt_asn1OID(realdest,APPLICATION,PRIMITIVE,*application,o->a,o->l); + else + curlen=fmt_asn1OID(realdest,UNIVERSAL,PRIMITIVE,OBJECT_IDENTIFIER,o->a,o->l); + application=NULL; + break; + + case 'C': // copy raw ASN.1 DER data, take struct string* + s=va_arg(args,struct string*); + if (realdest) memcpy(realdest,s->s,s->l); + curlen=s->l; + break; + + case 'c': // start context specific section + desttag=va_arg(args,unsigned long); + // fall through + case '[': // start SET + case '{': // start SEQUENCE + if (application) + curlen=fmt_asn1tag(realdest,APPLICATION,CONSTRUCTED,*application); + else if (*fmt=='c') + curlen=fmt_asn1tag(realdest,PRIVATE,CONSTRUCTED,desttag); + else + curlen=fmt_asn1tag(realdest,UNIVERSAL,CONSTRUCTED,*fmt=='{'?SEQUENCE_OF:SET_OF); + containerstack[curinstack++]=cursor+curlen; + application=NULL; + break; + case ']': // end of SET + case '}': // end of SEQUENCE + /* we just wrote the tag and the sequence. Now that we wrote the + * sequence, we know the length it took, and we need to move the + * sequence data backwards to make room to write the ASN.1 length */ + { + char* anfang; + if (!curinstack) return 0; + anfang=dest+containerstack[--curinstack]; + seqlen=dest+cursor-anfang; + curlen=fmt_asn1length(NULL,seqlen); + if (!dest) break; + memmove(anfang+curlen,anfang,seqlen); + fmt_asn1length(anfang,seqlen); + break; + } + } + cursor+=curlen; + ++fmt; + } + return cursor; +} -- cgit v1.2.3-55-g7522