summaryrefslogtreecommitdiffstats
path: root/fmt_asn1generic.c
diff options
context:
space:
mode:
authorSimon Rettberg2014-03-15 01:49:50 +0100
committerSimon Rettberg2014-03-15 01:49:50 +0100
commitbedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad (patch)
treec7d1995a09f6ed0c4e6873252e957d72f5d07d07 /fmt_asn1generic.c
downloadldadp-bedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad.tar.gz
ldadp-bedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad.tar.xz
ldadp-bedd2e7ccb1595c23e159eaa952ae1b0b5a3d2ad.zip
Lean and mean initial commit
Not much functionality yet
Diffstat (limited to 'fmt_asn1generic.c')
-rw-r--r--fmt_asn1generic.c139
1 files changed, 139 insertions, 0 deletions
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 <stdarg.h>
+#include <string.h>
+#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;
+}