diff --git a/CHANGES b/CHANGES index b27502c4477b13edab1986bf65c0923b2e6c0a14..00b2783dc4b1d235f5c418ffef55fe7129a2c461 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ OpenLDAP 2.4.18 Engineering Fixed libldap native getpass usage (ITS#4643) Fixed libldap tls_check_hostname for OpenSSL and MozNSS (ITS#6239) Fixed slapd allow mirrormode to be set to FALSE (ITS#5946) + Fixed slapd certificate parsing (ITS#6241) Fixed slapd dncachesize behavior to unlimited by default (ITS#6222) Fixed slapd incorrectly applying writetimeout when not set (ITS#6220) Fixed slapd server URL matching (ITS#5942) diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 253cf9790ea152bcfd6dd48ebe49332602ab92fa..1957190ab37a4cc1e2ce3c91bf8a526654c103ca 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -273,18 +273,25 @@ certificateValidate( Syntax *syntax, struct berval *in ) } /* X.509 certificate list validation */ +static int +checkTime( struct berval *in, struct berval *out ); + static int certificateListValidate( Syntax *syntax, struct berval *in ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; - ber_len_t len; + ber_len_t len, wrapper_len; + char *wrapper_start; + int wrapper_ok = 0; ber_int_t version = SLAP_X509_V1; + struct berval bvdn, bvtu; ber_init2( ber, in, LBER_USE_DER ); - tag = ber_skip_tag( ber, &len ); /* Signed wrapper */ + tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + wrapper_start = ber->ber_ptr; tag = ber_skip_tag( ber, &len ); /* Sequence */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; tag = ber_peek_tag( ber, &len ); @@ -297,12 +304,18 @@ certificateListValidate( Syntax *syntax, struct berval *in ) tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; ber_skip_data( ber, len ); - tag = ber_skip_tag( ber, &len ); /* Issuer DN */ + tag = ber_peek_tag( ber, &len ); /* Issuer DN */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + len = ber_ptrlen( ber ); + bvdn.bv_val = in->bv_val + len; + bvdn.bv_len = in->bv_len - len; + tag = ber_skip_tag( ber, &len ); ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); /* thisUpdate */ /* Time is a CHOICE { UTCTime, GeneralizedTime } */ if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX; + bvtu.bv_val = (char *)ber->ber_ptr; + bvtu.bv_len = len; ber_skip_data( ber, len ); /* Optional nextUpdate */ tag = ber_skip_tag( ber, &len ); @@ -335,9 +348,44 @@ certificateListValidate( Syntax *syntax, struct berval *in ) /* Signature */ if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; ber_skip_data( ber, len ); + if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1; tag = ber_skip_tag( ber, &len ); /* Must be at end now */ - if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX; + /* NOTE: OpenSSL tolerates CL with garbage past the end */ + if ( len || tag != LBER_DEFAULT ) { + struct berval issuer_dn = BER_BVNULL, thisUpdate; + char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1]; + int rc; + + if ( ! wrapper_ok ) { + return LDAP_INVALID_SYNTAX; + } + + rc = dnX509normalize( &bvdn, &issuer_dn ); + if ( rc != LDAP_SUCCESS ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + thisUpdate.bv_val = tubuf; + thisUpdate.bv_len = sizeof(tubuf); + if ( checkTime( &bvtu, &thisUpdate ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + Debug( LDAP_DEBUG_ANY, + "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n", + issuer_dn.bv_val, thisUpdate.bv_val, 0 ); + +done:; + if ( ! BER_BVISNULL( &issuer_dn ) ) { + ber_memfree( issuer_dn.bv_val ); + } + + return rc; + } + return LDAP_SUCCESS; } @@ -3617,6 +3665,9 @@ checkTime( struct berval *in, struct berval *out ) rc = generalizedTimeValidate( NULL, &bv ); if ( rc == LDAP_SUCCESS && out != NULL ) { + if ( out->bv_len > bv.bv_len ) { + out->bv_val[ bv.bv_len ] = '\0'; + } out->bv_len = bv.bv_len; }