@ -60,8 +60,10 @@
# include <ctype.h>
# include <inttypes.h>
# include <string.h>
# include <time.h>
# include <openssl/bio.h>
# include <openssl/bytestring.h>
# include <openssl/mem.h>
# include "internal.h"
@ -464,7 +466,7 @@ int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) {
if ( tm - > type = = V_ASN1_GENERALIZEDTIME ) {
return ASN1_GENERALIZEDTIME_print ( bp , tm ) ;
}
BIO_write ( bp , " Bad time value " , 14 ) ;
BIO_puts ( bp , " Bad time value " ) ;
return 0 ;
}
@ -472,136 +474,29 @@ static const char *const mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
" Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " } ;
int ASN1_GENERALIZEDTIME_print ( BIO * bp , const ASN1_GENERALIZEDTIME * tm ) {
char * v ;
int gmt = 0 ;
int i ;
int y = 0 , M = 0 , d = 0 , h = 0 , m = 0 , s = 0 ;
char * f = NULL ;
int f_len = 0 ;
i = tm - > length ;
v = ( char * ) tm - > data ;
if ( i < 12 ) {
goto err ;
}
if ( v [ i - 1 ] = = ' Z ' ) {
gmt = 1 ;
}
for ( i = 0 ; i < 12 ; i + + ) {
if ( ( v [ i ] > ' 9 ' ) | | ( v [ i ] < ' 0 ' ) ) {
goto err ;
}
}
y = ( v [ 0 ] - ' 0 ' ) * 1000 + ( v [ 1 ] - ' 0 ' ) * 100 + ( v [ 2 ] - ' 0 ' ) * 10 +
( v [ 3 ] - ' 0 ' ) ;
M = ( v [ 4 ] - ' 0 ' ) * 10 + ( v [ 5 ] - ' 0 ' ) ;
if ( ( M > 12 ) | | ( M < 1 ) ) {
goto err ;
}
d = ( v [ 6 ] - ' 0 ' ) * 10 + ( v [ 7 ] - ' 0 ' ) ;
h = ( v [ 8 ] - ' 0 ' ) * 10 + ( v [ 9 ] - ' 0 ' ) ;
m = ( v [ 10 ] - ' 0 ' ) * 10 + ( v [ 11 ] - ' 0 ' ) ;
if ( tm - > length > = 14 & & ( v [ 12 ] > = ' 0 ' ) & & ( v [ 12 ] < = ' 9 ' ) & & ( v [ 13 ] > = ' 0 ' ) & &
( v [ 13 ] < = ' 9 ' ) ) {
s = ( v [ 12 ] - ' 0 ' ) * 10 + ( v [ 13 ] - ' 0 ' ) ;
// Check for fractions of seconds.
if ( tm - > length > = 15 & & v [ 14 ] = = ' . ' ) {
int l = tm - > length ;
f = & v [ 14 ] ; // The decimal point.
f_len = 1 ;
while ( 14 + f_len < l & & f [ f_len ] > = ' 0 ' & & f [ f_len ] < = ' 9 ' ) {
+ + f_len ;
}
}
}
if ( BIO_printf ( bp , " %s %2d %02d:%02d:%02d%.*s %d%s " , mon [ M - 1 ] , d , h , m , s ,
f_len , f , y , ( gmt ) ? " GMT " : " " ) < = 0 ) {
return 0 ;
} else {
return 1 ;
}
err :
BIO_write ( bp , " Bad time value " , 14 ) ;
return 0 ;
}
// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|,
// assumed to be |*len| bytes long, has two leading digits, updates |*out| with
// their value, updates |v| and |len|, and returns one. Otherwise, returns
// zero.
static int consume_two_digits ( int * out , const char * * v , int * len ) {
if ( * len < 2 | | ! isdigit ( ( unsigned char ) ( ( * v ) [ 0 ] ) ) | |
! isdigit ( ( unsigned char ) ( ( * v ) [ 1 ] ) ) ) {
return 0 ;
}
* out = ( ( * v ) [ 0 ] - ' 0 ' ) * 10 + ( ( * v ) [ 1 ] - ' 0 ' ) ;
* len - = 2 ;
* v + = 2 ;
return 1 ;
}
// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|,
// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and
// |*len| and returns one. Otherwise returns zero.
static int consume_zulu_timezone ( const char * * v , int * len ) {
if ( * len = = 0 | | ( * v ) [ 0 ] ! = ' Z ' ) {
CBS cbs ;
CBS_init ( & cbs , tm - > data , tm - > length ) ;
struct tm utc ;
if ( ! CBS_parse_generalized_time ( & cbs , & utc , /*allow_timezone_offset=*/ 0 ) ) {
BIO_puts ( bp , " Bad time value " ) ;
return 0 ;
}
* len - = 1 ;
* v + = 1 ;
return 1 ;
return BIO_printf ( bp , " %s %2d %02d:%02d:%02d %d GMT " , mon [ utc . tm_mon ] ,
utc . tm_mday , utc . tm_hour , utc . tm_min , utc . tm_sec ,
utc . tm_year + 1900 ) > 0 ;
}
int ASN1_UTCTIME_print ( BIO * bp , const ASN1_UTCTIME * tm ) {
const char * v = ( const char * ) tm - > data ;
int len = tm - > length ;
int Y = 0 , M = 0 , D = 0 , h = 0 , m = 0 , s = 0 ;
// YYMMDDhhmm are required to be present.
if ( ! consume_two_digits ( & Y , & v , & len ) | | ! consume_two_digits ( & M , & v , & len ) | |
! consume_two_digits ( & D , & v , & len ) | | ! consume_two_digits ( & h , & v , & len ) | |
! consume_two_digits ( & m , & v , & len ) ) {
goto err ;
}
// https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds
// to be present, but historically this code has forgiven its absence.
consume_two_digits ( & s , & v , & len ) ;
// https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this
// interpretation of the year.
if ( Y < 50 ) {
Y + = 2000 ;
} else {
Y + = 1900 ;
}
if ( M > 12 | | M = = 0 ) {
goto err ;
}
if ( D > 31 | | D = = 0 ) {
goto err ;
}
if ( h > 23 | | m > 59 | | s > 60 ) {
goto err ;
}
// https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z"
// to be present, but historically this code has forgiven its absence.
const int is_gmt = consume_zulu_timezone ( & v , & len ) ;
// https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit
// the specification of timezones using the +hhmm / -hhmm syntax, which is
// the only other thing that might legitimately be found at the end.
if ( len ) {
goto err ;
CBS cbs ;
CBS_init ( & cbs , tm - > data , tm - > length ) ;
struct tm utc ;
if ( ! CBS_parse_utc_time ( & cbs , & utc , /*allow_timezone_offset=*/ 0 ) ) {
BIO_puts ( bp , " Bad time value " ) ;
return 0 ;
}
return BIO_printf ( bp , " %s %2d %02d:%02d:%02d %d%s " , mon [ M - 1 ] , D , h , m , s , Y ,
is_gmt ? " GMT " : " " ) > 0 ;
err :
BIO_write ( bp , " Bad time value " , 14 ) ;
return 0 ;
return BIO_printf ( bp , " %s %2d %02d:%02d:%02d %d GMT " , mon [ utc . tm_mon ] ,
utc . tm_mday , utc . tm_hour , utc . tm_min , utc . tm_sec ,
utc . tm_year + 1900 ) > 0 ;
}