On Wed, Nov 05, 2008 at 11:51:44AM +0100, Christophe Mac? wrote:

> Hi,
> I noticed a different behaviour between v0.9.8h and v0.9.8i when
> printing dates of my certificates and crls.
> for example (I patched file crypto/asn1/t_x509.c to print value of
> tm->length after the date) :
>
> [me@mymachine]/usr/local/src/openssl-0.9.8i/apps/openssl x509 -in
> /etc/ssl/stunnel/serveur-cert.pem -startdate -noout
> notBefore=Oct 24 09:29:00 2008 GMT (i=10)
>
> [me@mymachine]/usr/local/src/openssl-0.9.8h/apps/openssl x509 -in
> /etc/ssl/stunnel/serveur-cert.pem -startdate -noout
> notBefore=Oct 24 09:29:19 2008 GMT (i=10)
>
> Seconds are not printed in v0.9.8i, which is normal since there is a
> check if tm->length < 12 (line 432 of crypto/asn1/t_x509.c).


I see the same behaviour:

$ /.../openssl/0.9.8h/bin/openssl x509 \
-in /tmp/serveur-cert.pem -noout -dates
notBefore=Oct 24 09:29:19 2008 GMT
notAfter=Oct 24 09:29:19 2009 GMT

$ /.../openssl/0.9.8i/bin/openssl x509 \
-in /tmp/serveur-cert.pem -noout -dates
notBefore=Oct 24 09:29:00 2008 GMT
notAfter=Oct 24 09:29:00 2009 GMT

And it appears to be the result of the length check you noticed.

> I conclude that the field 'tm->length' seems not to be coherent with
> the field 'tm->data'. I cannot go further in my investigation for the
> moment.


The problem is that while "i" in the code is initialized to the ASN1
string length, it is also used as a loop control variable, clobbering the
initial value:

int ASN1_UTCTIME_print(BIO *bp, ASN1_UTCTIME *tm)
{
char *v;
int gmt=0;
int i;
int y=0,M=0,d=0,h=0,m=0,s=0;

i=tm->length;
v=(char *)tm->data;

if (i < 10) goto err;
if (v[i-1] == 'Z') gmt=1;
---------------------------------------------------------------
for (i=0; i<10; i++)
if ((v[i] > '9') || (v[i] < '0')) goto err;
---------------------------------------------------------------
y= (v[0]-'0')*10+(v[1]-'0');
if (y < 50) y+=100;
M= (v[2]-'0')*10+(v[3]-'0');
if ((M > 12) || (M < 1)) goto err;
d= (v[4]-'0')*10+(v[5]-'0');
h= (v[6]-'0')*10+(v[7]-'0');
m= (v[8]-'0')*10+(v[9]-'0');
if (i >=12 &&
(v[10] >= '0') && (v[10] <= '9') &&
(v[11] >= '0') && (v[11] <= '9'))
s= (v[10]-'0')*10+(v[11]-'0');

if (BIO_printf(bp,"%s %2d %02d:%02d:%02d %d%s",
mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":"") <= 0)
return(0);
else
return(1);
err:
BIO_write(bp,"Bad time value",14);
return(0);
}

Also, the validation is sloppy, garbage (non-digits) in the year, month,
day, hour or minutes triggers an error, while garbage in the seconds
field is silently treated as "00". The correct solution is likely to
ensure that *all* characters up to an optional final "Z" are numeric,
and to not clobber "i".

I could volunteer a patch, but perhaps the OpenSSL team wants to solve
this in slightly different way.

--
Viktor.
__________________________________________________ ____________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openssl-users@openssl.org
Automated List Manager majordomo@openssl.org