From cee3e02223bd7e7e258d1c6fae7b2b3516370634 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Thu, 13 Aug 2009 02:35:53 +0000
Subject: [PATCH] ITS#6241

---
 CHANGES                     |  1 +
 servers/slapd/schema_init.c | 59 ++++++++++++++++++++++++++++++++++---
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/CHANGES b/CHANGES
index b27502c447..00b2783dc4 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 253cf9790e..1957190ab3 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;
 	}
 
-- 
GitLab