diff --git a/asn1.h b/asn1.h index 78351b7..f74556e 100644 --- a/asn1.h +++ b/asn1.h @@ -208,10 +208,12 @@ size_t lookupoid(const char* oid,size_t l); 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) + * 'i' parse INTEGER; next argument is a long* (scan) or unsigned long (fmt) + * 'B' parse BOOLEAN; next argument is an int* (scan) or int (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 + * 'I' (fmt only) next argument is struct string *, send as BIT_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 diff --git a/fmt_asn1generic.c b/fmt_asn1generic.c index c97ee96..b41251d 100644 --- a/fmt_asn1generic.c +++ b/fmt_asn1generic.c @@ -32,6 +32,17 @@ size_t fmt_asn1generic(char* dest,const char* fmt,...) { application=NULL; curlen+=fmt_asn1length(realdest?realdest+curlen:NULL,0); break; + case 'B': // send boolean + { + int i=va_arg(args,int); + if (i!=0 && i!=1) return 0; + if (application) + curlen=fmt_asn1int(realdest,APPLICATION,PRIMITIVE,*application,i); + else + curlen=fmt_asn1int(realdest,UNIVERSAL,PRIMITIVE,BOOLEAN,i); + application=NULL; + break; + } case 'i': // send integer { unsigned long i=va_arg(args,unsigned long); @@ -50,7 +61,7 @@ size_t fmt_asn1generic(char* dest,const char* fmt,...) { curlen=fmt_asn1bitstring(realdest,UNIVERSAL,PRIMITIVE,BIT_STRING,s->s,s->l); application=NULL; break; - case 'B': + case 'I': stringtype=BIT_STRING; goto stringcopy; case 'A': diff --git a/scan_asn1generic.c b/scan_asn1generic.c index c246efd..06bb093 100644 --- a/scan_asn1generic.c +++ b/scan_asn1generic.c @@ -25,19 +25,26 @@ size_t scan_asn1generic(const char* src,const char* max,const char* fmt,...) { case '?': // ? = rest is optional (until end of sequence) optional=1; break; + case 'B': // B = BOOLEAN case 'i': // i = INTEGER { long* dest=va_arg(args,long*); - *dest=0; - curlen=scan_asn1int(src,maxstack[curmax],&tc,&tt,&tag,dest); + int* bdest=(int*)dest; + long l; + if (*fmt=='B') *bdest=0; else *dest=0; + curlen=scan_asn1int(src,maxstack[curmax],&tc,&tt,&tag,&l); if (application) { if (tc!=APPLICATION) return 0; *application=tag; } else { - if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=INTEGER) + if (tc!=UNIVERSAL || tt!=PRIMITIVE || tag!=(*fmt=='B'?BOOLEAN:INTEGER)) return 0; } if (!curlen) { if (optional) break; else return 0; } + if (*fmt=='B') + *bdest=l; + else + *dest=l; src+=curlen; application=NULL; break; diff --git a/scan_asn1length.c b/scan_asn1length.c index 689ab78..9e20fae 100644 --- a/scan_asn1length.c +++ b/scan_asn1length.c @@ -16,6 +16,7 @@ size_t scan_asn1length(const char* src,const char* max,size_t* value) { l=(unsigned char)src[1]; if (l==0) return 0; /* not minimally encoded: 0x81 0x00 instead of 0x00 */ if (c>sizeof(l)) return 0; /* too many bytes, does not fit into target integer type */ + if (c+1>len) return 0; /* not enough data in input buffer */ for (i=2; i<=c; ++i) l=l*256+(unsigned char)src[i]; if (l<0x7f) return 0; /* not minimally encoded: 0x81 0x70 instead of 0x70 */ diff --git a/scan_certificate.c b/scan_certificate.c index 9a0cc85..9153ed3 100644 --- a/scan_certificate.c +++ b/scan_certificate.c @@ -270,20 +270,22 @@ size_t scan_certificate(const char* cert, size_t l, struct x509cert* C, char** f printf("public exponent %lu\n",publicExponent[1]); else printf("public exponent is larger than a word?!\n"); - printf("modulus: "); + printf("modulus:\n "); for (i=1; i<=modulus[0]; ++i) { size_t j,k; for (j=0, k=modulus[i]; j>((sizeof(modulus[0])*8)-(j+1)*8))&0xff); + printf("%02lx%s",(k>>((sizeof(modulus[0])*8)-(j+1)*8))&0xff,i==modulus[0] && j==sizeof(modulus[0])-1?"":":"); } - if ((i-1)%4==3 || i==modulus[0]) printf("\n"); + if ((i-1)%4==3) + if (i==modulus[0]) + printf("\n"); + else + printf("\n "); } } else printf("bignum scanning failed!\n"); } free(modulus); free(publicExponent); - /* 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]; @@ -298,6 +300,53 @@ size_t scan_certificate(const char* cert, size_t l, struct x509cert* C, char** f } else printf("could not parse public key part!\n"); + + // parse x.509v3 extensions + if (version!=2 && extensions.l) { + printf("Not X.509v3 but extensions present!?\n"); + } else if (extensions.l) { + const char* c=extensions.s; + const char* max=extensions.s+extensions.l; + struct string extoid,extval; + unsigned long noextensions; + if (c!=max) { + size_t n=scan_asn1generic(c,max,"c{!}}!",&noextensions,&extensions,&extval); + if (n==0 || extval.l>0) { + printf("failed to parse X.509v3 extensions!\n"); + c=max; + } else { + c=extensions.s; + max=extensions.s+extensions.l; + } + } + while (c