Hello, my colleague Jan Hofmann experimented with new ASN.1 code from openssl-0.9.7-beta4. He achieved buggy behavior when parsing incomplete (truncated) DER data under specific conditions. Openssl does'not detect any error while parsing truncated DER data. He asked on openssl-users mailling list without response. I tried to debug his code down into libcrypto and localized bug in function asn1_d2i_read_bio(). I found this problem in RT/openssl.org since May 2002 (Id #20).
NOTE: Rsync protocol on dev.openssl.org is down now, so I can't view the latest crypto/asn1/a_d2i_fp.c (update local CVS mirror). There is the last and only mail in RT: > [[EMAIL PROTECTED] - Sat May 4 20:44:23 2002]: > > > Experimenting with "openssl smime -decrypt", I found that it did not > > detect that a > > message was truncated. Changing line 173 of crypto/asn1/a_d2i_fp.c > > from > > if (i <= 0) > > to > > if (i < want) > > fixes the problem. I think this is the right code for all cases, but > > somebody who > > actually understands the whole ASN parsing framework should probably > > check it out. > > > > Its a bit more complex than that. The reason for the <=0 test is because > the actual value for 'want' is not always accurate. In particular when a > header is being read 'want' is set to HEADER_SIZE which is 8. > > This is a only upper bound for a sensible header size. A valid header > may only be two octets in length: 0x30, 0x0 for example is a zero > length SEQUENCE. > > So what is actually needed is two different techniques, one to read > in the header and the other the content octets (assuming their > size is accurately known). > > Steve. My try to solve problem is attached. I added variable 'require' parallel to 'want'... I have written this patch only on facts mentioned in Steve's mail. I have not analysed code deeply. Review is needed. I would be pleased, if you would be so kind and have look at this serious bug. Thank you very much. -- Zito
--- openssl-0.9.7-beta4/crypto/asn1/a_d2i_fp.c.Orig Tue Dec 3 10:26:18 2002 +++ openssl-0.9.7-beta4/crypto/asn1/a_d2i_fp.c Tue Dec 3 12:36:46 2002 @@ -140,6 +140,7 @@ #endif #define HEADER_SIZE 8 +#define HEADER_SIZE_MIN 2 static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) { BUF_MEM *b; @@ -148,6 +149,7 @@ int ret=-1; ASN1_CTX c; int want=HEADER_SIZE; + int require=HEADER_SIZE_MIN; int eos=0; int off=0; int len=0; @@ -165,6 +167,7 @@ if (want >= (len-off)) { want-=(len-off); + require-=(len-off); if (!BUF_MEM_grow_clean(b,len+want)) { @@ -172,7 +175,7 @@ goto err; } i=BIO_read(in,&(b->data[len]),want); - if ((i < 0) && ((len-off) == 0)) + if (i < require) { ASN1err(ASN1_F_ASN1_D2I_BIO,ASN1_R_NOT_ENOUGH_DATA); goto err; @@ -204,6 +207,7 @@ /* no data body so go round again */ eos++; want=HEADER_SIZE; + require=HEADER_SIZE_MIN; } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) { @@ -213,21 +217,24 @@ break; else want=HEADER_SIZE; + require=HEADER_SIZE_MIN; } else { /* suck in c.slen bytes of data */ want=(int)c.slen; + require=want; if (want > (len-off)) { want-=(len-off); + require=want; if (!BUF_MEM_grow_clean(b,len+want)) { ASN1err(ASN1_F_ASN1_D2I_BIO,ERR_R_MALLOC_FAILURE); goto err; } i=BIO_read(in,&(b->data[len]),want); - if (i <= 0) + if (i < require) { ASN1err(ASN1_F_ASN1_D2I_BIO,ASN1_R_NOT_ENOUGH_DATA); goto err; @@ -241,6 +248,7 @@ } else want=HEADER_SIZE; + require=HEADER_SIZE_MIN; } }