first shot at x.509 certificate parsing
This commit is contained in:
4
Makefile
4
Makefile
@@ -12,7 +12,7 @@ scan_asn1STRING.o scan_asn1SEQUENCE.o scan_asn1ENUMERATED.o \
|
||||
scan_asn1BOOLEAN.o scan_asn1rawint.o scan_asn1SET.o fmt_asn1sint.o \
|
||||
fmt_asn1sintpayload.o scan_asn1oid.o scan_asn1BITSTRING.o \
|
||||
scan_asn1tagint.o fmt_asn1tagint.o fmt_asn1OID.o scan_asn1generic.o \
|
||||
fmt_asn1generic.o scan_asn1rawoid.o fmt_asn1bitstring.o
|
||||
fmt_asn1generic.o scan_asn1rawoid.o fmt_asn1bitstring.o asn1oid.o
|
||||
|
||||
ldap.a: scan_ldapmessage.o fmt_ldapmessage.o fmt_ldapbindrequest.o \
|
||||
scan_ldapbindrequest.o scan_ldapbindresponse.o scan_ldapresult.o \
|
||||
@@ -159,4 +159,6 @@ scan_ldapsearchresultentry.o: scan_ldapsearchresultentry.c asn1.h ldap.h
|
||||
scan_ldapstring.o: scan_ldapstring.c asn1.h ldap.h
|
||||
scan_asn1generic.o: scan_asn1generic.c asn1.h
|
||||
|
||||
asn1oid.o: asn1oid.c asn1.h
|
||||
|
||||
ldap_match_sre.o: ldap_match_sre.c ldap.h
|
||||
|
||||
57
asn1.h
57
asn1.h
@@ -23,10 +23,13 @@ enum asn1_tag {
|
||||
INTEGER=2,
|
||||
BIT_STRING=3,
|
||||
OCTET_STRING=4,
|
||||
_NULL=5,
|
||||
OBJECT_IDENTIFIER=6,
|
||||
ENUMERATED=10,
|
||||
SEQUENCE_OF=16,
|
||||
SET_OF=17,
|
||||
PrintableString=19,
|
||||
IA5String=22,
|
||||
UTCTIME=23
|
||||
};
|
||||
|
||||
@@ -160,4 +163,58 @@ struct oid {
|
||||
size_t* a;
|
||||
};
|
||||
|
||||
enum x509_oid {
|
||||
X509_ATTR_COMMONNAME, X509_ATTR_SURNAME, X509_ATTR_SERIALNUMBER,
|
||||
X509_ATTR_COUNTRY, X509_ATTR_LOCALITY, X509_ATTR_STATEPROVINCE,
|
||||
X509_ATTR_STREET, X509_ATTR_ORG, X509_ATTR_ORGUNIT, X509_ATTR_TITLE,
|
||||
X509_ATTR_DESC, X509_ATTR_GIVENNAME, X509_ATTR_INITIALS,
|
||||
X509_ATTR_GENERATIONQUALIFIER, X509_ATTR_UNIQID, X509_ATTR_DNQUALIFIER,
|
||||
X509_ATTR_EMAIL,
|
||||
|
||||
X509_EXT_SUBJKEYID, X509_EXT_KEYUSAGE, X509_EXT_PRIVKEYUSAGEPERIOD,
|
||||
X509_EXT_SUBJALTNAME, X509_EXT_ISSUERALTNAME, X509_EXT_BASICCONSTRAINTS,
|
||||
X509_EXT_CRL_NUMBER, X509_EXT_REASONCODE, X509_EXT_INSTRUCTIONCODE,
|
||||
X509_EXT_INVALIDITYDATE, X509_EXT_DELTA_CRL_INDICATOR,
|
||||
X509_EXT_ISSUING_DISTRIBUTION_POINT, X509_EXT_NAME_CONSTRAINTS,
|
||||
X509_EXT_CRL_DISTRIBUTION_POINTS, X509_EXT_CERT_POLICIES,
|
||||
X509_EXT_AUTH_KEY_ID, X509_EXT_KEY_USAGE,
|
||||
|
||||
X509_ALG_MD2RSA, X509_ALG_MD4RSA, X509_ALG_MD5RSA, X509_ALG_SHA1RSA,
|
||||
X509_ALG_SHA256RSA, X509_ALG_SHA384RSA, X509_ALG_SHA512RSA,
|
||||
X509_ALG_SHA224RSA, X509_ALG_RSA,
|
||||
};
|
||||
|
||||
extern const struct oidlookup {
|
||||
size_t l;
|
||||
const char* oid,* name;
|
||||
enum x509_oid id;
|
||||
} oid2string[];
|
||||
|
||||
size_t lookupoid(const char* oid,size_t l);
|
||||
|
||||
/* Generic parser and formatter routines: */
|
||||
size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...);
|
||||
size_t fmt_asn1generic(char* dest,const char* fmt,...);
|
||||
/* the format string works like this:
|
||||
* 'i' next argument is a long* (scan) or unsigned long (fmt)
|
||||
* '*' (fmt only) next argument is an unsigned long, tag type is set to APPLICATION and tag is set to that argument
|
||||
* '*' (scan only) next argument is an unsigned long*; for next tag, expect tag type to be APPLICATION and write tag to this unsigned long*
|
||||
* 'b' next argument is a struct string* but the length l in it is in bits, not bytes; if the length is not a multiple of 8, the unused bits are at the end of the last byte in the string
|
||||
* 'S' (fmt only) next argument is struct string *, send as OCTET_STRING
|
||||
* 's' (fmt only) next argument is const char*, use strlen and send as OCTET_STRING
|
||||
* 's' (scan only) next argument is struct string*, parse OCTET_STRING into it
|
||||
* 'o' (fmt only) next argument is struct oid*, send OBJECT_IDENTIFIER
|
||||
* 'o' (scan only) next argument is struct string*, parse raw OBJECT_IDENTIFIER into it; you have to call scan_asn1rawoid on contents of string to process further
|
||||
* '[' start set
|
||||
* ']' end set
|
||||
* '{' start sequence
|
||||
* '}' end sequence
|
||||
* '?' from here till end of input / set / sequence is optional and can be missing
|
||||
* 'u' (scan only) next argument is time_t*, parse UTCTIME into it
|
||||
* 'p' (scan only) like 's' but check that contents of string is printable
|
||||
* 'a' (scan only) like 's' but check that contents of string is ascii
|
||||
* '!' (scan only) next argument is struct string*, fill in region until end of current sequence / set (for optional data)
|
||||
* 'c' context specific value (tag class PRIVATE, type CONSTRUCTED, tag taken from unsigned long arg / written to unsigned long* argument)
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
68
asn1oid.c
Normal file
68
asn1oid.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <string.h>
|
||||
#include "asn1.h"
|
||||
|
||||
#define ENTRY(a,b,c) { sizeof(a)-1, a, b, c }
|
||||
|
||||
const struct oidlookup oid2string[] = {
|
||||
|
||||
/* naming attribute OIDs */
|
||||
ENTRY("\x55\x04\x03", "commonName", X509_ATTR_COMMONNAME),
|
||||
ENTRY("\x55\x04\x04", "surname", X509_ATTR_SURNAME),
|
||||
ENTRY("\x55\x04\x05", "serialNumber", X509_ATTR_SERIALNUMBER),
|
||||
ENTRY("\x55\x04\x06", "countryName", X509_ATTR_COUNTRY),
|
||||
ENTRY("\x55\x04\x07", "localityName", X509_ATTR_LOCALITY),
|
||||
ENTRY("\x55\x04\x08", "stateOrProvinceName", X509_ATTR_STATEPROVINCE),
|
||||
ENTRY("\x55\x04\x09", "street", X509_ATTR_STREET),
|
||||
ENTRY("\x55\x04\x0a", "organizationName", X509_ATTR_ORG),
|
||||
ENTRY("\x55\x04\x0b", "organizationalUnitName", X509_ATTR_ORGUNIT),
|
||||
ENTRY("\x55\x04\x0c", "title", X509_ATTR_TITLE),
|
||||
ENTRY("\x55\x04\x0d", "description", X509_ATTR_DESC),
|
||||
ENTRY("\x55\x04\x2a", "givenName", X509_ATTR_GIVENNAME),
|
||||
ENTRY("\x55\x04\x2b", "initials", X509_ATTR_INITIALS),
|
||||
ENTRY("\x55\x04\x2c", "generationQualifier", X509_ATTR_GENERATIONQUALIFIER),
|
||||
ENTRY("\x55\x04\x2d", "uniqueIdentifier", X509_ATTR_UNIQID),
|
||||
ENTRY("\x55\x04\x2e", "dnQualifier", X509_ATTR_DNQUALIFIER),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x09\x01", "emailAddress", X509_ATTR_EMAIL),
|
||||
|
||||
/* X.509v3 extension OIDs */
|
||||
ENTRY("\x55\x1d\x0e", "subject_key_identifier", X509_EXT_SUBJKEYID),
|
||||
ENTRY("\x55\x1d\x0f", "key_usage", X509_EXT_KEYUSAGE),
|
||||
ENTRY("\x55\x1d\x10", "private_key_usage_period", X509_EXT_PRIVKEYUSAGEPERIOD),
|
||||
ENTRY("\x55\x1d\x11", "subject_alt_name", X509_EXT_SUBJALTNAME),
|
||||
ENTRY("\x55\x1d\x12", "issuer_alt_name", X509_EXT_ISSUERALTNAME),
|
||||
ENTRY("\x55\x1d\x13", "basic_constraints", X509_EXT_BASICCONSTRAINTS),
|
||||
ENTRY("\x55\x1d\x14", "crl_number", X509_EXT_CRL_NUMBER),
|
||||
ENTRY("\x55\x1d\x15", "reasonCode", X509_EXT_REASONCODE),
|
||||
ENTRY("\x55\x1d\x17", "instruction_code", X509_EXT_INSTRUCTIONCODE),
|
||||
ENTRY("\x55\x1d\x18", "invalidity_date", X509_EXT_INVALIDITYDATE),
|
||||
ENTRY("\x55\x1d\x1b", "delta_crl_indicator", X509_EXT_DELTA_CRL_INDICATOR),
|
||||
ENTRY("\x55\x1d\x1c", "issuing_distribution_point", X509_EXT_ISSUING_DISTRIBUTION_POINT),
|
||||
ENTRY("\x55\x1d\x1e", "name_constraints", X509_EXT_NAME_CONSTRAINTS),
|
||||
ENTRY("\x55\x1d\x1f", "crl_distribution_points", X509_EXT_CRL_DISTRIBUTION_POINTS),
|
||||
ENTRY("\x55\x1d\x20", "certificate_policies", X509_EXT_CERT_POLICIES),
|
||||
ENTRY("\x55\x1d\x23", "authority_key_identifier", X509_EXT_AUTH_KEY_ID),
|
||||
ENTRY("\x55\x1d\x25", "ext_key_usage", X509_EXT_KEY_USAGE),
|
||||
|
||||
/* X.509 algorithms */
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x02", "md2WithRSAEncryption", X509_ALG_MD2RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x03", "md4WithRSAEncryption", X509_ALG_MD4RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x04", "md5WithRSAEncryption", X509_ALG_MD5RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05", "SHA1WithRSAEncryption", X509_ALG_SHA1RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b", "SHA256WithRSAEncryption", X509_ALG_SHA256RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0c", "SHA384WithRSAEncryption", X509_ALG_SHA384RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0d", "SHA512WithRSAEncryption", X509_ALG_SHA512RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0e", "SHA224WithRSAEncryption", X509_ALG_SHA224RSA),
|
||||
ENTRY("\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01", "rsaEncryption", X509_ALG_RSA),
|
||||
|
||||
};
|
||||
|
||||
#undef ENTRY
|
||||
|
||||
size_t lookupoid(const char* oid,size_t l) {
|
||||
size_t i;
|
||||
for (i=0; i<sizeof(oid2string)/sizeof(oid2string[0]); ++i)
|
||||
if (oid2string[i].l==l && memcmp(oid,oid2string[i].oid,l)==0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ size_t fmt_asn1generic(char* dest,const char* fmt,...) {
|
||||
size_t curlen=0;
|
||||
size_t cursor=0;
|
||||
size_t seqlen;
|
||||
unsigned long desttag=0;
|
||||
unsigned long appstore;
|
||||
while (*fmt) {
|
||||
char* realdest=dest?dest+cursor:NULL;
|
||||
switch (*fmt) {
|
||||
case 'a': // make next tag use APPLICATION with this tag
|
||||
case '*': // make next tag use APPLICATION with this tag
|
||||
appstore=va_arg(args,unsigned long);
|
||||
application=&appstore;
|
||||
break;
|
||||
@@ -62,14 +63,21 @@ copystring:
|
||||
curlen=fmt_asn1OID(realdest,UNIVERSAL,PRIMITIVE,OBJECT_IDENTIFIER,o->a,o->l);
|
||||
application=NULL;
|
||||
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,SEQUENCE_OF);
|
||||
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
|
||||
|
||||
123
printasn1.c
Normal file
123
printasn1.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/* needs stdio.h and asn1.h included */
|
||||
|
||||
void printasn1(const char* buf,const char* max) {
|
||||
const char* maxstack[100];
|
||||
size_t sptr=0;
|
||||
size_t indent=0;
|
||||
unsigned long tag;
|
||||
enum asn1_tagclass tc;
|
||||
enum asn1_tagtype tt;
|
||||
size_t cl,len;
|
||||
maxstack[sptr]=max;
|
||||
while (buf<max) {
|
||||
size_t i;
|
||||
printf("%*s",indent,"");
|
||||
cl=scan_asn1tag(buf,maxstack[sptr],&tc,&tt,&tag);
|
||||
if (cl==0) {
|
||||
printf("[could not parse tag]\n");
|
||||
return;
|
||||
}
|
||||
printf("tag ");
|
||||
switch (tc) {
|
||||
case UNIVERSAL: printf("UNIVERSAL"); break;
|
||||
case APPLICATION: printf("APPLICATION"); break;
|
||||
case PRIVATE: printf("PRIVATE"); break;
|
||||
case CONTEXT_SPECIFIC: printf("CONTEXT_SPECIFIC"); break;
|
||||
default: printf("[illegal tag class 0x%x]\n",tc); return;
|
||||
}
|
||||
printf(" ");
|
||||
switch (tt) {
|
||||
case PRIMITIVE: printf("PRIMITIVE"); break;
|
||||
case CONSTRUCTED: printf("CONSTRUCTED"); break;
|
||||
default: printf("[illegal tag type 0x%x]\n",tt); return;
|
||||
}
|
||||
printf(" ");
|
||||
if (tc!=UNIVERSAL)
|
||||
printf("%d (0x%x)",tag,tag);
|
||||
else switch (tag) {
|
||||
case 0: printf("EOI"); break;
|
||||
case BOOLEAN: printf("BOOLEAN"); break;
|
||||
case INTEGER: printf("INTEGER"); break;
|
||||
case BIT_STRING: printf("BIT_STRING"); break;
|
||||
case OCTET_STRING: printf("OCTET_STRING"); break;
|
||||
case _NULL: printf("NULL"); break;
|
||||
case OBJECT_IDENTIFIER: printf("OBJECT_IDENTIFIER"); break;
|
||||
case ENUMERATED: printf("ENUMERATED"); break;
|
||||
case SEQUENCE_OF: printf("SEQUENCE_OF"); break;
|
||||
case SET_OF: printf("SET_OF"); break;
|
||||
case PrintableString: printf("PrintableString"); break;
|
||||
case IA5String: printf("IA5String"); break;
|
||||
case UTCTIME: printf("UTCTime"); break;
|
||||
default: printf("[unsupported tag 0x%x]",tag); break;
|
||||
}
|
||||
|
||||
buf+=cl;
|
||||
cl=scan_asn1length(buf,maxstack[sptr],&len);
|
||||
if (cl==0) {
|
||||
puts("[could not parse length]");
|
||||
return;
|
||||
}
|
||||
printf(" length %zu\n",len);
|
||||
buf+=cl;
|
||||
|
||||
if (tc==UNIVERSAL && tt==PRIMITIVE) {
|
||||
if (tag==INTEGER) {
|
||||
unsigned long l;
|
||||
size_t mlen;
|
||||
mlen=scan_asn1rawint(buf,maxstack[sptr],cl,&l);
|
||||
if (mlen)
|
||||
printf("%*s-> %ld\n",indent,"",l);
|
||||
} else if (tag==OCTET_STRING || tag==PrintableString || tag==IA5String || tag==UTCTIME) {
|
||||
printf("%*s-> \"",indent,"");
|
||||
for (i=0; i<len; ++i) {
|
||||
if (buf[i]<' ')
|
||||
printf("\\x%02x",(unsigned char)(buf[i]));
|
||||
else
|
||||
putchar(buf[i]);
|
||||
}
|
||||
printf("\"\n");
|
||||
} else if (tag==OBJECT_IDENTIFIER) {
|
||||
struct oid o;
|
||||
size_t mlen;
|
||||
unsigned long fnord[100];
|
||||
o.l=100;
|
||||
o.a=fnord;
|
||||
mlen=scan_asn1rawoid(buf,buf+len,o.a,&o.l);
|
||||
if (mlen) {
|
||||
printf("%*s-> ",indent,"");
|
||||
for (i=0; i<o.l; ++i)
|
||||
printf("%d%s",o.a[i],i+1==o.l?"\n":".");
|
||||
}
|
||||
i=lookupoid(buf,len);
|
||||
if (i!=(size_t)-1)
|
||||
printf("%*s(%s)\n",indent,"",oid2string[i].name);
|
||||
else {
|
||||
printf("%*s(\"",indent,"");
|
||||
for (i=0; i<len; ++i)
|
||||
printf("\\x%02x",(unsigned char)(buf[i]));
|
||||
printf("\")\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tt==CONSTRUCTED) {
|
||||
printf("%*s{\n",indent,"");
|
||||
indent+=2;
|
||||
if (sptr>=99) {
|
||||
printf("too many nested constructed elements!\n");
|
||||
return;
|
||||
}
|
||||
maxstack[++sptr]=buf+len;
|
||||
} else
|
||||
buf+=len;
|
||||
|
||||
while (sptr && maxstack[sptr]<=buf) {
|
||||
--sptr;
|
||||
indent-=2;
|
||||
printf("%*s}\n",indent,"");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include "asn1.h"
|
||||
|
||||
size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
@@ -12,6 +14,8 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
unsigned long tag;
|
||||
enum asn1_tagclass tc;
|
||||
enum asn1_tagtype tt;
|
||||
unsigned int wantedtag;
|
||||
unsigned long* desttag=NULL;
|
||||
const char* orig=src;
|
||||
va_start(args,fmt);
|
||||
maxstack[0]=max;
|
||||
@@ -34,13 +38,58 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
}
|
||||
if (!curlen) { if (optional) break; else return 0; }
|
||||
src+=curlen;
|
||||
application=0;
|
||||
application=NULL;
|
||||
break;
|
||||
}
|
||||
case 'b': // s = BIT STRING
|
||||
case 's': // s = STRING
|
||||
case 'I': // I = INTEGER, but for bignum integers; writes to an array of size_t, first one contains number of digits after it
|
||||
{
|
||||
struct string* dest=va_arg(args,struct string*);
|
||||
size_t* dest=va_arg(args,size_t*);
|
||||
size_t len,tmp,tlen,j,t;
|
||||
if (!(len=scan_asn1tag(src,maxstack[curmax],&tc,&tt,&tag))) return 0;
|
||||
if (!(tmp=scan_asn1length(src+len,maxstack[curmax],&tlen))) return 0;
|
||||
len+=tmp;
|
||||
j=0; t=1;
|
||||
src+=len;
|
||||
/* asn.1 sends n bytes, most significant first.
|
||||
* we want m digits, most significant first.
|
||||
* if n is not a multiple of sizeof(digit) then we need to
|
||||
* insert a few 0 bytes in the first word
|
||||
*/
|
||||
while (tlen) {
|
||||
j=(j<<8)+(unsigned char)(*src);
|
||||
++src;
|
||||
--tlen;
|
||||
if ((tlen%sizeof(j))==0 && (j || t>1)) {
|
||||
dest[t]=j;
|
||||
j=0;
|
||||
++t;
|
||||
}
|
||||
}
|
||||
if (j) dest[t++]=j;
|
||||
dest[0]=t-1;
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
wantedtag=BIT_STRING; goto stringmain;
|
||||
case 'u':
|
||||
wantedtag=UTCTIME; goto stringmain;
|
||||
case 'p':
|
||||
wantedtag=PrintableString; goto stringmain;
|
||||
case 'a':
|
||||
wantedtag=IA5String; goto stringmain;
|
||||
case 's':
|
||||
wantedtag=OCTET_STRING; goto stringmain;
|
||||
stringmain:
|
||||
{
|
||||
struct string* dest;
|
||||
struct string temp;
|
||||
time_t* desttime=NULL;
|
||||
size_t i;
|
||||
if (wantedtag==UTCTIME) {
|
||||
dest=&temp;
|
||||
desttime=va_arg(args,time_t*);
|
||||
} else
|
||||
dest=va_arg(args,struct string*);
|
||||
dest->l=0;
|
||||
dest->s=0;
|
||||
curlen=scan_asn1string(src,maxstack[curmax],&tc,&tt,&tag,&dest->s,&dest->l);
|
||||
@@ -49,23 +98,96 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
if (tc!=APPLICATION) return 0;
|
||||
*application=tag;
|
||||
} else {
|
||||
if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=(*fmt=='s'?OCTET_STRING:BIT_STRING))
|
||||
if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=wantedtag)
|
||||
return 0;
|
||||
}
|
||||
if (*fmt=='b') { // additional checks for bit strings
|
||||
if (wantedtag==BIT_STRING) { // additional checks for bit strings
|
||||
if (dest->l==0 || // length can't be 0 because the format starts with 1 octet that contains the number of unused bits in the last octet
|
||||
((unsigned char)(dest->s[0])>7) || // it's the number of unused bits in an octet, must be [0..7]
|
||||
(dest->l==1 && dest->s[0])) return 0; // if there is no last octet, there can't be any unused bits in there
|
||||
dest->l=(dest->l-1)*8-dest->s[0];
|
||||
dest->s+=1;
|
||||
} else if (wantedtag==PrintableString) {
|
||||
for (i=0; i<dest->l; ++i) // RFC 2252 section 4.1 production p
|
||||
if (!isalnum(dest->s[i])
|
||||
&& dest->s[i]!='"'
|
||||
&& dest->s[i]!='('
|
||||
&& dest->s[i]!=')'
|
||||
&& dest->s[i]!='+'
|
||||
&& dest->s[i]!=','
|
||||
&& dest->s[i]!='-'
|
||||
&& dest->s[i]!='.'
|
||||
&& dest->s[i]!='/'
|
||||
&& dest->s[i]!=':'
|
||||
&& dest->s[i]!='?'
|
||||
&& dest->s[i]!=' ') return 0;
|
||||
} else if (wantedtag==IA5String) {
|
||||
for (i=0; i<dest->l; ++i) // IA5String is an ASCII string, which means 0 <= s[i] <= 127
|
||||
if ((unsigned char)(dest->s[i]) > 127) return 0;
|
||||
} else if (wantedtag==UTCTIME) {
|
||||
size_t j;
|
||||
struct tm t;
|
||||
memset(&t,0,sizeof(t));
|
||||
/*
|
||||
YYMMDDhhmmZ
|
||||
YYMMDDhhmm+hh'mm'
|
||||
YYMMDDhhmm-hh'mm'
|
||||
YYMMDDhhmmssZ
|
||||
YYMMDDhhmmss+hh'mm'
|
||||
YYMMDDhhmmss-hh'mm'
|
||||
*/
|
||||
if (dest->l<11 || dest->l>17) return 0;
|
||||
j=(dest->s[0]-'0')*10+dest->s[1]-'0';
|
||||
t.tm_year=j+(j<70)*100;
|
||||
|
||||
for (i=0; i<10; ++i)
|
||||
if (!isdigit(dest->s[i])) return 0;
|
||||
j=(dest->s[2]-'0')*10+dest->s[3]-'0'; // is the month plausible?
|
||||
if (j<1 || j>12) return 0;
|
||||
t.tm_mon=j-1;
|
||||
j=(dest->s[4]-'0')*10+dest->s[5]-'0'; // is the day plausible?
|
||||
if (j<1 || j>31) return 0;
|
||||
t.tm_mday=j;
|
||||
j=(dest->s[6]-'0')*10+dest->s[7]-'0'; // is the hour plausible?
|
||||
if (j>23) return 0;
|
||||
t.tm_hour=j;
|
||||
j=(dest->s[8]-'0')*10+dest->s[9]-'0'; // is the minutes plausible?
|
||||
if (j>59) return 0;
|
||||
t.tm_min=j;
|
||||
i=10;
|
||||
if (isdigit(dest->s[10])) {
|
||||
i+=2;
|
||||
j=(dest->s[10]-'0')*10+dest->s[11]-'0'; // is the seconds plausible?
|
||||
if (j>59) return 0;
|
||||
t.tm_sec=j;
|
||||
}
|
||||
*desttime=mktime(&t);
|
||||
if (dest->s[i]=='+' || dest->s[i]=='-') {
|
||||
size_t j;
|
||||
if (dest->l!=15) return 0;
|
||||
for (j=i; j<i+4; ++j)
|
||||
if (!isdigit(dest->s[j])) return 0;
|
||||
j=(dest->s[i]-'0')*10+dest->s[i+1]-'0'; // is the offset minutes plausible?
|
||||
if (j>59) return 0;
|
||||
if (dest->s[i]=='+')
|
||||
*desttime+=j*60;
|
||||
else
|
||||
*desttime-=j*60;
|
||||
j=(dest->s[i+2]-'0')*10+dest->s[i+3]-'0'; // is the offset seconds plausible?
|
||||
if (j>59) return 0;
|
||||
if (dest->s[i]=='+')
|
||||
*desttime+=j;
|
||||
else
|
||||
*desttime-=j;
|
||||
} else if (dest->s[i]!='Z') return 0;
|
||||
}
|
||||
src+=curlen;
|
||||
application=0;
|
||||
application=NULL;
|
||||
break;
|
||||
}
|
||||
case 'o': // o == OID
|
||||
{
|
||||
struct oid* dest=va_arg(args,struct oid*);
|
||||
struct string* dest=va_arg(args,struct string*);
|
||||
curlen=scan_asn1tag(src,maxstack[curmax],&tc,&tt,&tag);
|
||||
if (!curlen) { if (optional) break; else return 0; }
|
||||
if (application) {
|
||||
@@ -79,32 +201,37 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
curlen=scan_asn1length(src,maxstack[curmax],&seqlen);
|
||||
if (!curlen) return 0;
|
||||
src+=curlen;
|
||||
curlen=scan_asn1rawoid(src,src+seqlen,dest->a,&dest->l);
|
||||
if (!curlen) {
|
||||
if (dest->l && !dest->a) {
|
||||
dest->a=malloc(dest->l*sizeof(dest->a[0]));
|
||||
curlen=scan_asn1rawoid(src,src+seqlen,dest->a,&dest->l);
|
||||
}
|
||||
if (!curlen) return 0;
|
||||
}
|
||||
src+=curlen;
|
||||
application=0;
|
||||
dest->s=src;
|
||||
dest->l=seqlen;
|
||||
src+=seqlen;
|
||||
application=NULL;
|
||||
break;
|
||||
}
|
||||
case 'a': // next tag class is APPLICATION instead of UNIVERSAL; write tag to unsigned long*
|
||||
case '*': // next tag class is APPLICATION instead of UNIVERSAL; write tag to unsigned long*
|
||||
{
|
||||
application=va_arg(args,unsigned long*);
|
||||
break;
|
||||
}
|
||||
case 'c': // c = context specific; PRIVATE CONSTRUCTED 0, close with '}'
|
||||
desttag=va_arg(args,unsigned long*);
|
||||
// fall through
|
||||
case '[': // [ = SET
|
||||
case '{': // { = SEQUENCE
|
||||
{
|
||||
curlen=scan_asn1tag(src,maxstack[curmax],&tc,&tt,&tag);
|
||||
if (!curlen) { if (optional) break; else return 0; }
|
||||
if (application) {
|
||||
if (tc!=APPLICATION) return 0;
|
||||
if (tc!=APPLICATION || tt!=CONSTRUCTED) return 0;
|
||||
*application=tag;
|
||||
} else {
|
||||
if (tc!=UNIVERSAL || tt!=CONSTRUCTED || tag!=SEQUENCE_OF)
|
||||
return 0;
|
||||
if (*fmt=='c') {
|
||||
if (tc!=PRIVATE || tt!=CONSTRUCTED)
|
||||
return 0;
|
||||
*desttag=tag;
|
||||
} else {
|
||||
if (tc!=UNIVERSAL || tt!=CONSTRUCTED || tag!=(*fmt=='{'?SEQUENCE_OF:SET_OF))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
src+=curlen;
|
||||
curlen=scan_asn1length(src,maxstack[curmax],&seqlen);
|
||||
@@ -112,24 +239,23 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) {
|
||||
if (curmax>99) return 0;
|
||||
maxstack[++curmax]=src+curlen+seqlen;
|
||||
src+=curlen;
|
||||
application=0;
|
||||
application=NULL;
|
||||
break;
|
||||
}
|
||||
case '!': // save current max-src into size_t
|
||||
// useful for ldap, where you have an application sequence
|
||||
// and the tag defines which encoding you have inside the
|
||||
// sequence, so you can't put it in the format string.
|
||||
// you still need to know the length so you can call this function
|
||||
// again on the rest of the data.
|
||||
case '!': // save current src and max-src into struct string*
|
||||
// useful for optional parts or CHOICEs
|
||||
{
|
||||
size_t* dest=va_arg(args,size_t*);
|
||||
*dest=maxstack[curmax]-src;
|
||||
struct string* dest=va_arg(args,struct string*);
|
||||
dest->s=src;
|
||||
dest->l=maxstack[curmax]-src;
|
||||
break;
|
||||
}
|
||||
case ']': // ] = end of SET
|
||||
case '}': // } = end of SEQUENCE
|
||||
{
|
||||
optional=0;
|
||||
if (curmax==0) return 0;
|
||||
src=maxstack[curmax];
|
||||
--curmax;
|
||||
break;
|
||||
}
|
||||
|
||||
254
scan_certificate.c
Normal file
254
scan_certificate.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "asn1.h"
|
||||
#include "str.h"
|
||||
#include "textcode.h"
|
||||
|
||||
struct x509signature {
|
||||
struct string oid; /* you are not expected to actually decode this */
|
||||
size_t oididx; /* if this is (size_t)-1, then the parser did not know the OID.
|
||||
Otherwise it's the index into oid2string. oid2string[oididx].id
|
||||
should be something like X509_ALG_SHA1RSA (see asn1.h) */
|
||||
struct string bitstring; /* In this string, the length is in bits, not bytes! */
|
||||
/* If the length is not a multiple of 8, then the unused bits are missing in the last byte.
|
||||
* The parser already validated that the last byte is padded with 0 bits */
|
||||
};
|
||||
|
||||
struct x509cert {
|
||||
enum { v1=0, v1988=0, v2=1, v3=2, v1996=2 } version;
|
||||
size_t serial;
|
||||
struct x509signature algid;
|
||||
struct string issuer; /* this is the raw asn.1 structure, a SET of "[{op}]" in scan_asn1generic terms */
|
||||
time_t notbefore, notafter;
|
||||
struct string subject; /* this is the raw asn.1 structure, a SET of "[{op}]" in scan_asn1generic terms */
|
||||
struct x509signature sig;
|
||||
};
|
||||
|
||||
void printasn1(const char* buf,const char* max);
|
||||
|
||||
static int findindn(struct string* dn,enum x509_oid id,struct string* dest) {
|
||||
size_t i;
|
||||
const char* c=dn->s;
|
||||
const char* max=dn->s+dn->l;
|
||||
for (;;) {
|
||||
struct string oid;
|
||||
size_t l=scan_asn1generic(c,max,"[{op}]",&oid,dest);
|
||||
if (l) {
|
||||
i=lookupoid(oid.s,oid.l);
|
||||
if (i!=(size_t)-1) { // recognized the oid!
|
||||
if (oid2string[i].id==id)
|
||||
return 1;
|
||||
}
|
||||
c+=l;
|
||||
} else break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t scan_certificate(const char* cert,size_t l, struct x509cert* C) {
|
||||
char* c=0,* x;
|
||||
/* if it's base64 encoded, decode first */
|
||||
if (l > 27+25+2 && str_start(cert,"-----BEGIN CERTIFICATE-----"))
|
||||
certfound:
|
||||
{
|
||||
size_t cur,used;
|
||||
/* "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----" and newlines */
|
||||
c=malloc((l-27-25-2)/4*3);
|
||||
if (!c) return 0;
|
||||
x=c;
|
||||
for (cur=27; cur+26<l;) {
|
||||
size_t next;
|
||||
if (cert[cur]=='\r') ++cur; /* skip line ending */
|
||||
if (cert[cur]=='\n') ++cur;
|
||||
next=scan_base64(cert+cur,x,&used);
|
||||
if (next==0) break;
|
||||
cur+=next;
|
||||
x+=used;
|
||||
}
|
||||
if (!str_start(cert+cur,"-----END CERTIFICATE-----")) {
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
cert=c;
|
||||
l=x-c;
|
||||
} else {
|
||||
/* Maybe it has text in front of the BEGIN CERTIFICATE line */
|
||||
size_t i,a=1;
|
||||
for (i=0; i+27+25+2<l; ++i) {
|
||||
if (cert[i]!='\n' && cert[i]!='\r' && (cert[i]<' ' || cert[i]>'~')) {
|
||||
a=0;
|
||||
break;
|
||||
}
|
||||
if (str_start(cert+i,"-----BEGIN CERTIFICATE-----")) {
|
||||
cert+=i;
|
||||
l-=i;
|
||||
goto certfound;
|
||||
}
|
||||
}
|
||||
if (a) /* if we end up here, it was ascii but did not contain a certificate. fail. */
|
||||
return 0;
|
||||
}
|
||||
/* if we end up here, we decoded some base64 data or we found some
|
||||
* binary data. See if it looks like x.509 at all. If it does, it
|
||||
* starts with a SEQUENCE_OF, which encodes as '0'. */
|
||||
if (*cert!='0') {
|
||||
parseerror:
|
||||
free(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* now for the heavy lifting */
|
||||
{
|
||||
unsigned long tagforversion; // must be 0
|
||||
unsigned long version;
|
||||
struct string oidalg,algparams,pubkeyalg,extensions,oidsig,sigrest,sigdata;
|
||||
size_t i;
|
||||
if (scan_asn1generic(cert,cert+l,"{{ci]i{o!}{!}{uu}{!}{!}!}{o!}b}",
|
||||
&tagforversion,
|
||||
&version,
|
||||
&C->serial,
|
||||
&oidalg, &algparams,
|
||||
&C->issuer,
|
||||
&C->notbefore, &C->notafter,
|
||||
&C->subject,
|
||||
&pubkeyalg,
|
||||
&extensions,
|
||||
&oidsig, &sigrest, &sigdata)) {
|
||||
|
||||
if (version==0)
|
||||
printf("X.509 certificate\n");
|
||||
else if (version==1)
|
||||
printf("X.509v2 certificate\n");
|
||||
else if (version==2)
|
||||
printf("X.509v3 certificate\n");
|
||||
else
|
||||
printf("unsupported version %ld (must be 0, 1 or 2)\n",version);
|
||||
|
||||
printf("serial number %lu\n",C->serial);
|
||||
|
||||
printf("issuer: ");
|
||||
{
|
||||
struct string s;
|
||||
if (findindn(&C->issuer,X509_ATTR_COUNTRY,&s))
|
||||
printf("C=%.*s ",(int)s.l,s.s);
|
||||
if (findindn(&C->issuer,X509_ATTR_ORG,&s))
|
||||
printf("O=%.*s ",(int)s.l,s.s);
|
||||
if (findindn(&C->issuer,X509_ATTR_COMMONNAME,&s))
|
||||
printf("CN=%.*s ",(int)s.l,s.s);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
{
|
||||
char a[100],b[100];
|
||||
a[fmt_httpdate(a,C->notbefore)]=0;
|
||||
b[fmt_httpdate(b,C->notafter)]=0;
|
||||
printf("valid not before %s and not after %s\n",a,b);
|
||||
}
|
||||
|
||||
printf("subject: ");
|
||||
{
|
||||
struct string s;
|
||||
if (findindn(&C->issuer,X509_ATTR_COUNTRY,&s))
|
||||
printf("C=%.*s ",(int)s.l,s.s);
|
||||
if (findindn(&C->issuer,X509_ATTR_ORG,&s))
|
||||
printf("O=%.*s ",(int)s.l,s.s);
|
||||
if (findindn(&C->issuer,X509_ATTR_COMMONNAME,&s))
|
||||
printf("CN=%.*s ",(int)s.l,s.s);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
i=lookupoid(oidalg.s,oidalg.l);
|
||||
if (i!=(size_t)-1)
|
||||
printf("signature algorithm %s\n",oid2string[i].name);
|
||||
else {
|
||||
unsigned long temp[100];
|
||||
size_t len=100;
|
||||
if (scan_asn1rawoid(oidalg.s,oidalg.s+oidalg.l,temp,&len)) {
|
||||
printf("Unknown signature algorithm (oid ");
|
||||
for (i=0; i<len; ++i)
|
||||
printf("%lu%s",temp[i],i+1<len?".":")\n");
|
||||
} else
|
||||
printf("I don't know the algorithm and I can't parse/print the OID\n");
|
||||
}
|
||||
|
||||
/* pubkeyalg is a SubjectPublicKeyInfo:
|
||||
SubjectPublicKeyInfo ::= SEQUENCE{
|
||||
algorithm AlgorithmIdentifier,
|
||||
subjectPublicKey BIT STRING}
|
||||
|
||||
AlgorithmIdentifier ::= SEQUENCE{
|
||||
algorithm OBJECT IDENTIFIER,
|
||||
parameters ANY DEFINED BY algorithm OPTIONAL}
|
||||
*/
|
||||
|
||||
{
|
||||
struct string pubkeyoid, pubkeyparams, bits;
|
||||
if (scan_asn1generic(pubkeyalg.s,pubkeyalg.s+pubkeyalg.l,"{o!}b",&pubkeyoid,&pubkeyparams,&bits)) {
|
||||
|
||||
i=lookupoid(pubkeyoid.s,pubkeyoid.l);
|
||||
if (i!=(size_t)-1) {
|
||||
printf("public key algorithm %s\n",oid2string[i].name);
|
||||
if (oid2string[i].id==X509_ALG_RSA) {
|
||||
size_t* modulus,* publicExponent;
|
||||
size_t allocsize=bits.l/(8*sizeof(modulus[0]))+2;
|
||||
modulus=malloc(allocsize);
|
||||
publicExponent=malloc(allocsize);
|
||||
if (!modulus || !publicExponent)
|
||||
printf("malloc for RSA bignums failed!\n");
|
||||
else {
|
||||
if (scan_asn1generic(bits.s,bits.s+bits.l/8,"{II}",modulus,publicExponent)) {
|
||||
if (publicExponent[0]==1)
|
||||
printf("public exponent %lu\n",publicExponent[1]);
|
||||
else
|
||||
printf("public exponent is larger than a word?!\n");
|
||||
printf("modulus: ");
|
||||
for (i=1; i<=modulus[0]; ++i) {
|
||||
size_t j,k;
|
||||
for (j=0, k=modulus[i]; j<sizeof(modulus[0]); ++j) {
|
||||
printf("%02lx:",(k>>((sizeof(modulus[0])*8)-(j+1)*8))&0xff);
|
||||
}
|
||||
if ((i-1)%4==3 || i==modulus[0]) printf("\n");
|
||||
}
|
||||
} else
|
||||
printf("bignum scanning failed!\n");
|
||||
}
|
||||
/* for RSA, bits is actually another sequence with two integers, modulus and publicExponent */
|
||||
printf("pubkeyparams len %lu, bits len %lu\n",pubkeyparams.l,bits.l);
|
||||
}
|
||||
} else {
|
||||
unsigned long temp[100];
|
||||
size_t len=100;
|
||||
if (scan_asn1rawoid(pubkeyoid.s,pubkeyoid.s+pubkeyoid.l,temp,&len)) {
|
||||
printf("Unknown public key algorithm (oid ");
|
||||
for (i=0; i<len; ++i)
|
||||
printf("%lu%s",temp[i],i+1<len?".":")\n");
|
||||
} else
|
||||
printf("I don't know the public key algorithm and I can't parse/print the OID\n");
|
||||
}
|
||||
|
||||
} else
|
||||
printf("could not parse public key part!\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// printasn1(cert,cert+l);
|
||||
|
||||
}
|
||||
|
||||
#include "mmap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "printasn1.c"
|
||||
|
||||
int main(int argc,char* argv[]) {
|
||||
char* buf;
|
||||
size_t l,n;
|
||||
struct x509cert c;
|
||||
|
||||
buf=mmap_read(argc>1?argv[1]:"test.pem",&l);
|
||||
if (!buf) { puts("test.pem not found"); return 1; }
|
||||
|
||||
n=scan_certificate(buf,l,&c);
|
||||
}
|
||||
134
t10.c
134
t10.c
@@ -1,115 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <byte.h>
|
||||
#include <stdlib.h>
|
||||
#include "asn1.h"
|
||||
|
||||
void printasn1(const char* buf,const char* max) {
|
||||
const char* maxstack[100];
|
||||
size_t sptr=0;
|
||||
size_t indent=0;
|
||||
unsigned long tag;
|
||||
enum asn1_tagclass tc;
|
||||
enum asn1_tagtype tt;
|
||||
size_t cl,len;
|
||||
maxstack[sptr]=max;
|
||||
while (buf<max) {
|
||||
size_t i;
|
||||
printf("%*s",indent,"");
|
||||
cl=scan_asn1tag(buf,maxstack[sptr],&tc,&tt,&tag);
|
||||
if (cl==0) {
|
||||
printf("[could not parse tag]\n");
|
||||
return;
|
||||
}
|
||||
printf("tag ");
|
||||
switch (tc) {
|
||||
case UNIVERSAL: printf("UNIVERSAL"); break;
|
||||
case APPLICATION: printf("APPLICATION"); break;
|
||||
case PRIVATE: printf("PRIVATE"); break;
|
||||
case CONTEXT_SPECIFIC: printf("CONTEXT_SPECIFIC"); break;
|
||||
default: printf("[illegal tag class 0x%x]\n",tc); return;
|
||||
}
|
||||
printf(" ");
|
||||
switch (tt) {
|
||||
case PRIMITIVE: printf("PRIMITIVE"); break;
|
||||
case CONSTRUCTED: printf("CONSTRUCTED"); break;
|
||||
default: printf("[illegal tag type 0x%x]\n",tt); return;
|
||||
}
|
||||
printf(" ");
|
||||
if (tc!=UNIVERSAL)
|
||||
printf("%d (0x%x)",tag,tag);
|
||||
else switch (tag) {
|
||||
case BOOLEAN: printf("BOOLEAN"); break;
|
||||
case INTEGER: printf("INTEGER"); break;
|
||||
case BIT_STRING: printf("BIT_STRING"); break;
|
||||
case OCTET_STRING: printf("OCTET_STRING"); break;
|
||||
case OBJECT_IDENTIFIER: printf("OBJECT_IDENTIFIER"); break;
|
||||
case ENUMERATED: printf("ENUMERATED"); break;
|
||||
case SEQUENCE_OF: printf("SEQUENCE_OF"); break;
|
||||
case SET_OF: printf("SET_OF"); break;
|
||||
case UTCTIME: printf("UTCTime"); break;
|
||||
default: printf("[unsupported tag 0x%x]",tag); break;
|
||||
}
|
||||
#include "printasn1.c"
|
||||
|
||||
buf+=cl;
|
||||
cl=scan_asn1length(buf,maxstack[sptr],&len);
|
||||
if (cl==0) {
|
||||
puts("[could not parse length]");
|
||||
return;
|
||||
}
|
||||
printf(" length %zu\n",len);
|
||||
buf+=cl;
|
||||
|
||||
if (tc==UNIVERSAL && tt==PRIMITIVE) {
|
||||
if (tag==INTEGER) {
|
||||
unsigned long l;
|
||||
size_t mlen;
|
||||
mlen=scan_asn1rawint(buf,maxstack[sptr],cl,&l);
|
||||
if (mlen)
|
||||
printf("%*s-> %ld\n",indent,"",l);
|
||||
} else if (tag==OCTET_STRING) {
|
||||
printf("%*s-> \"",indent,"");
|
||||
for (i=0; i<len; ++i) {
|
||||
if (buf[i]<' ')
|
||||
printf("\\x%02x",(unsigned char)(buf[i]));
|
||||
else
|
||||
putchar(buf[i]);
|
||||
}
|
||||
printf("\"\n");
|
||||
} else if (tag==OBJECT_IDENTIFIER) {
|
||||
struct oid o;
|
||||
size_t mlen;
|
||||
unsigned long fnord[100];
|
||||
o.l=100;
|
||||
o.a=fnord;
|
||||
mlen=scan_asn1rawoid(buf,maxstack[sptr],o.a,&o.l);
|
||||
if (mlen) {
|
||||
printf("%*s-> ",indent,"");
|
||||
for (i=0; i<o.l; ++i)
|
||||
printf("%d%s",o.a[i],i+1==o.l?"\n":".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tt==CONSTRUCTED) {
|
||||
printf("%*s{\n",indent,"");
|
||||
indent+=2;
|
||||
if (sptr>=99) {
|
||||
printf("too many nested constructed elements!\n");
|
||||
return;
|
||||
}
|
||||
maxstack[++sptr]=buf+len;
|
||||
} else
|
||||
buf+=len;
|
||||
|
||||
while (sptr && maxstack[sptr]<=buf) {
|
||||
--sptr;
|
||||
indent-=2;
|
||||
printf("%*s}\n",indent,"");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long oid[]={1,2,840,113549,1};
|
||||
unsigned long oid[]={1,2,840,113549,1};
|
||||
const unsigned long oidlen = sizeof(oid) / sizeof(oid[0]);
|
||||
|
||||
main() {
|
||||
@@ -122,7 +18,7 @@ main() {
|
||||
o.l=oidlen;
|
||||
o.a=oid;
|
||||
byte_zero(buf,1024);
|
||||
l=fmt_asn1generic(buf,"a{isbo}",8,23,"fnord",&B,&o);
|
||||
l=fmt_asn1generic(buf,"*{isbo}",8,23,"fnord",&B,&o);
|
||||
printf("formatted into %d bytes\n",l);
|
||||
{
|
||||
printf("-> ");
|
||||
@@ -139,9 +35,9 @@ main() {
|
||||
unsigned long a2;
|
||||
unsigned long b;
|
||||
struct string c;
|
||||
struct oid d;
|
||||
struct string d;
|
||||
struct string e;
|
||||
l=scan_asn1generic(buf,buf+l,"a{!isbo}",&a,&a2,&b,&c,&e,&d);
|
||||
l=scan_asn1generic(buf,buf+l,"*{!isbo}",&a,&a2,&b,&c,&e,&d);
|
||||
printf("%lu\n",l);
|
||||
if (l) {
|
||||
printf("got application tag %d (should be 8)\n",a);
|
||||
@@ -155,8 +51,22 @@ main() {
|
||||
printf("\n");
|
||||
|
||||
printf("got oid ");
|
||||
for (i=0; i<d.l; ++i)
|
||||
printf("%d%s",d.a[i],i+1<d.l?".":" (should be 1.2.840.113549.1)\n");
|
||||
{
|
||||
struct oid o;
|
||||
size_t mlen=scan_asn1rawoid(d.s,d.s+d.l,NULL,&o.l);
|
||||
if (mlen==0 && o.l==0) {
|
||||
puts("oid parse error!");
|
||||
return 0;
|
||||
}
|
||||
o.a=malloc(o.l*sizeof(o.a[0]));
|
||||
if (!o.a) {
|
||||
puts("memory allocation error!");
|
||||
return 0;
|
||||
}
|
||||
mlen=scan_asn1rawoid(d.s,d.s+d.l,o.a,&o.l);
|
||||
for (i=0; i<o.l; ++i)
|
||||
printf("%d%s",o.a[i],i+1<o.l?".":" (should be 1.2.840.113549.1)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user