add missing check to length parser

add code to iterate through x509v3 extensions
This commit is contained in:
leitner
2014-04-23 14:10:48 +00:00
parent bfc0f242ee
commit 7233b84786
5 changed files with 80 additions and 10 deletions

4
asn1.h
View File

@@ -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

View File

@@ -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':

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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]); ++j) {
printf("%02lx:",(k>>((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<max) {
size_t n=scan_asn1generic(c,max,"{os}",&extoid,&extval);
if (n) {
size_t i=lookupoid(extoid.s,extoid.l);
if (i!=(size_t)-1) {
printf("X.509 extension %s\n",oid2string[i].name);
} else {
unsigned long temp[100];
size_t len=100;
if (scan_asn1rawoid(extoid.s,extoid.s+extoid.l,temp,&len)) {
printf("Unknown X.509v3 extension (oid ");
for (i=0; i<len; ++i)
printf("%lu%s",temp[i],i+1<len?".":")\n");
} else
printf("Failed to parse X.509v3 extension OID\n");
}
c+=n;
} else {
printf("X.509v3 extension parse error!\n");
printasn1(c,max);
break;
}
}
}
/*
&extensions,
&oidsig, &sigrest, &sigdata))) {
*/
}
return n;