100% unit test coverage
This commit is contained in:
@@ -12,17 +12,66 @@ size_t scan_asn1length(const char* src,const char* max,size_t* value) {
|
||||
} else {
|
||||
/* Highest bit set: lower 7 bits is the length of the length value in bytes. */
|
||||
c&=0x7f;
|
||||
if (!c) return 0; /* length 0x80 means indefinite length encoding, not supported here */
|
||||
if (!c)
|
||||
return 0; /* length 0x80 means indefinite length encoding, not supported here */
|
||||
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 */
|
||||
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 */
|
||||
if (l<0x7f)
|
||||
return 0; /* not minimally encoded: 0x81 0x70 instead of 0x70 */
|
||||
}
|
||||
if (l>len-i) return 0; /* if the length would not fit into the buffer, return 0 */
|
||||
if (l>len-i)
|
||||
return 0; /* if the length would not fit into the buffer, return 0 */
|
||||
*value=l;
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
char buf[10];
|
||||
unsigned long l;
|
||||
/* empty input */
|
||||
assert(scan_asn1length(buf,buf,&l)==0);
|
||||
/* regular 1-byte encoding */
|
||||
strcpy(buf,"\x23");
|
||||
assert(scan_asn1length(buf,buf+1,&l)==0); // length fits but value doesn't
|
||||
assert(scan_asn1length(buf,buf+0x23,&l)==0); // length fits but value doesn't
|
||||
assert(scan_asn1length(buf,buf+0x24,&l)==1 && l==0x23); // OK
|
||||
/* not minimally encoded */
|
||||
strcpy(buf,"\x81\x23"); // not minimal, should have been "\x23"
|
||||
assert(scan_asn1length(buf,buf+10,&l)==0);
|
||||
/* indefinite length encoding not supported */
|
||||
strcpy(buf,"\x80");
|
||||
assert(scan_asn1length(buf,buf+1,&l)==0);
|
||||
/* regular 2-byte encoding */
|
||||
strcpy(buf,"\x81\x97");
|
||||
assert(scan_asn1length(buf,buf+2,&l)==0); // length fits but value doesn't
|
||||
assert(scan_asn1length(buf,buf+255,&l)==2 && l==0x97);
|
||||
/* non-minimal multi-byte */
|
||||
memcpy(buf,"\x82\x00\x97",3); // not minimal, should have been "\x81\x97"
|
||||
assert(scan_asn1length(buf,buf+3,&l)==0);
|
||||
/* value not representable */
|
||||
memcpy(buf,"\x89\x01\x02\x03\x04\x05\x06\x07\x08\x09",10); // can't fit 9 bytes into long
|
||||
// this will also fail the "length bytes fit in input buffer"
|
||||
assert(scan_asn1length(buf,buf+10,&l)==0);
|
||||
/* value does not fit in input buffer */
|
||||
memcpy(buf,"\x81\x80",2); // length 0x80
|
||||
assert(scan_asn1length(buf,buf+10,&l)==0); // length fits, value doesn't
|
||||
assert(scan_asn1length(buf,buf+0x90,&l)==2 && l==0x80); // OK
|
||||
assert(scan_asn1length(buf,buf+1,&l)==0); // length doesn't fit
|
||||
// three byte encoding
|
||||
memcpy(buf,"\x82\x80\x00",3); // length 0x8000
|
||||
assert(scan_asn1length(buf,buf+10,&l)==0); // length fits, value doesn't
|
||||
assert(scan_asn1length(buf,buf+0x8010,&l)==3 && l==0x8000); // OK
|
||||
assert(scan_asn1length(buf,buf+2,&l)==0); // length doesn't fit
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#endif
|
||||
|
||||
size_t scan_asn1tag(const char* src,const char* max,enum asn1_tagclass* tc,enum asn1_tagtype* tt,unsigned long* tag) {
|
||||
if (max<=src) return 0;
|
||||
if (max<=src)
|
||||
return 0;
|
||||
*tc=(*src&0xC0);
|
||||
*tt=(*src&0x20);
|
||||
/* The lower 5 bits are the tag, unless it's 0x1f, in which case the
|
||||
@@ -15,6 +16,8 @@ size_t scan_asn1tag(const char* src,const char* max,enum asn1_tagclass* tc,enum
|
||||
* in the sequence is marked by a cleared high bit */
|
||||
if ((*src & 0x1f) == 0x1f) {
|
||||
size_t res=scan_asn1tagint(src+1,max,tag);
|
||||
if (res && *tag < 0x1f) // non-minimal encoding
|
||||
return 0;
|
||||
return res+!!res; /* add 1 unless it's 0, then leave 0 */
|
||||
} else {
|
||||
*tag=*src&0x1f;
|
||||
@@ -30,7 +33,28 @@ int main() {
|
||||
enum asn1_tagclass tc;
|
||||
enum asn1_tagtype tt;
|
||||
unsigned long tag;
|
||||
char buf[10];
|
||||
char buf[15];
|
||||
assert(scan_asn1tag(buf,buf,&tc,&tt,&tag)==0); // empty input
|
||||
strcpy(buf,"\x01"); assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==1 && tc==UNIVERSAL && tt==PRIMITIVE && tag==BOOLEAN);
|
||||
/* incomplete input */
|
||||
strcpy(buf,"\x1f"); assert(scan_asn1tag(buf,buf+1,&tc,&tt,&tag)==0);
|
||||
/* long-form encoding when short-form would have sufficed */
|
||||
strcpy(buf,"\x1f\x1e");
|
||||
assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==0);
|
||||
/* OK */
|
||||
strcpy(buf,"\x1f\x1f");
|
||||
assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==2 && tc==UNIVERSAL && tt==PRIMITIVE && tag==0x1f);
|
||||
/* non-minimal encoding */
|
||||
strcpy(buf,"\x1f\x80\x01");
|
||||
assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==0);
|
||||
/* incomplete encoding */
|
||||
assert(scan_asn1tag(buf,buf+2,&tc,&tt,&tag)==0);
|
||||
strcpy(buf,"\x1f\x81\x00");
|
||||
assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==3 && tc==UNIVERSAL && tt==PRIMITIVE && tag==0x80);
|
||||
/* value not representable */
|
||||
memcpy(buf,"\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7f",11);
|
||||
assert(scan_asn1tag(buf,buf+12,&tc,&tt,&tag)==0);
|
||||
memcpy(buf,"\x1f\x8f\xff\xff\xff\x7f",7);
|
||||
assert(scan_asn1tag(buf,buf+10,&tc,&tt,&tag)==6 && tc==UNIVERSAL && tt==PRIMITIVE && tag==0xffffffff);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,12 +4,15 @@ size_t scan_asn1tagint(const char* src,const char* bounds,unsigned long* val) {
|
||||
const char* orig=src;
|
||||
unsigned long l=0;
|
||||
if (src>=bounds || /* empty input */
|
||||
(unsigned char)src[0]==0x80) return 0; /* catch non-minimal encoding */
|
||||
(unsigned char)src[0]==0x80)
|
||||
return 0; /* catch non-minimal encoding */
|
||||
for (;; ++src) {
|
||||
if (src>=bounds || /* incomplete input */
|
||||
l>>(sizeof(l)*8-7)) return 0; /* catch integer overflow */
|
||||
l>>(sizeof(l)*8-7))
|
||||
return 0; /* catch integer overflow */
|
||||
l=l*128+(*src&0x7F);
|
||||
if (!(*src&0x80)) break;
|
||||
if (!(*src&0x80))
|
||||
break;
|
||||
}
|
||||
*val=l;
|
||||
return src-orig+1;
|
||||
|
||||
Reference in New Issue
Block a user