Răsfoiți Sursa

Bug 728592 - Allow ns-slapd to start with an invalid server cert

This patch adds a new config attribute (nsslapd-validate-cert).
This new attribute allows one to control the validation of the
server certificate used for SSL/TLS.

The valid settings are "on", "off", and "warn".  The "on" setting
will make the server validate the certificate, treating an invalid
certificate as a hard failure that prevents ns-slapd from starting.
The "warn" setting will validate the certificate, but the server
will start and log an error if the certificate is invalid.  The
"off" setting will skip certificate validation completely, allowing
ns-slapd to start with no reported errors when the certicate is
invalid.  The default setting is "warn" if the attribute is not
specified.
Nathan Kinder 14 ani în urmă
părinte
comite
971dded696

+ 1 - 0
ldap/ldif/template-dse.ldif.in

@@ -29,6 +29,7 @@ nsslapd-dn-validate-strict: off
 nsslapd-rewrite-rfc1274: off
 nsslapd-return-exact-case: on
 nsslapd-ssl-check-hostname: on
+nsslapd-validate-cert: warn
 nsslapd-allow-unauthenticated-binds: off
 nsslapd-require-secure-binds: off
 nsslapd-allow-anonymous-access: on

+ 75 - 3
ldap/servers/slapd/libglobs.c

@@ -114,9 +114,10 @@ typedef enum {
 	CONFIG_CONSTANT_STRING, /* for #define values, e.g. */
 	CONFIG_SPECIAL_REFERRALLIST, /* this is a berval list */
 	CONFIG_SPECIAL_SSLCLIENTAUTH, /* maps strings to an enumeration */
-    CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
+	CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
 	CONFIG_STRING_OR_EMPTY, /* use an empty string */
-	CONFIG_SPECIAL_ANON_ACCESS_SWITCH /* maps strings to an enumeration */
+	CONFIG_SPECIAL_ANON_ACCESS_SWITCH, /* maps strings to an enumeration */
+	CONFIG_SPECIAL_VALIDATE_CERT_SWITCH /* maps strings to an enumeration */
 } ConfigVarType;
 
 static int config_set_onoff( const char *attrname, char *value,
@@ -640,7 +641,11 @@ static struct config_get_and_set {
 	{CONFIG_ALLOWED_TO_DELETE_ATTRIBUTE, config_set_allowed_to_delete_attrs,
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.allowed_to_delete_attrs,
-		CONFIG_STRING, (ConfigGetFunc)config_get_allowed_to_delete_attrs}
+		CONFIG_STRING, (ConfigGetFunc)config_get_allowed_to_delete_attrs},
+	{CONFIG_VALIDATE_CERT_ATTRIBUTE, config_set_validate_cert_switch,
+                NULL, 0,
+                (void**)&global_slapdFrontendConfig.validate_cert, CONFIG_SPECIAL_VALIDATE_CERT_SWITCH,
+                (ConfigGetFunc)config_get_validate_cert_switch}
 #ifdef MEMPOOL_EXPERIMENTAL
 	,{CONFIG_MEMPOOL_SWITCH_ATTRIBUTE, config_set_mempool_switch,
 		NULL, 0,
@@ -905,6 +910,7 @@ FrontendConfig_init () {
   cfg->maxsasliosize = SLAPD_DEFAULT_MAX_SASLIO_SIZE;
   cfg->localssf = SLAPD_DEFAULT_LOCAL_SSF;
   cfg->minssf = SLAPD_DEFAULT_MIN_SSF;
+  cfg->validate_cert = SLAPD_VALIDATE_CERT_WARN;
 
 #ifdef _WIN32
   cfg->conntablesize = SLAPD_DEFAULT_CONNTABLESIZE;
@@ -4625,6 +4631,17 @@ config_get_anon_access_switch(void)
 	return retVal;
 }
 
+int
+config_get_validate_cert_switch(void)
+{
+	int retVal = 0;
+	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+	CFG_LOCK_READ(slapdFrontendConfig);
+	retVal = slapdFrontendConfig->validate_cert;
+	CFG_UNLOCK_READ(slapdFrontendConfig);
+	return retVal;
+}
+
 int
 config_set_maxbersize( const char *attrname, char *value, char *errorbuf, int apply )
 {
@@ -5575,6 +5592,44 @@ config_set_anon_access_switch( const char *attrname, char *value,
 	return retVal;
 }
 
+int
+config_set_validate_cert_switch( const char *attrname, char *value,
+		char *errorbuf, int apply )
+{
+	int retVal = LDAP_SUCCESS;
+	slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+	if (config_value_is_null(attrname, value, errorbuf, 0)) {
+		return LDAP_OPERATIONS_ERROR;
+	}
+
+	if ((strcasecmp(value, "on") != 0) && (strcasecmp(value, "off") != 0) &&
+	    (strcasecmp(value, "warn") != 0)) {
+		PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+			"%s: invalid value \"%s\". Valid values are \"on\", "
+			"\"off\", or \"warn\".", attrname, value);
+		retVal = LDAP_OPERATIONS_ERROR;
+	}
+
+	if (!apply) {
+		/* we can return now if we aren't applying the changes */
+		return retVal;
+	}
+
+	CFG_LOCK_WRITE(slapdFrontendConfig);
+
+	if (strcasecmp(value, "on") == 0 ) {
+		slapdFrontendConfig->validate_cert = SLAPD_VALIDATE_CERT_ON;
+	} else if (strcasecmp(value, "off") == 0 ) {
+		slapdFrontendConfig->validate_cert = SLAPD_VALIDATE_CERT_OFF;
+	} else if (strcasecmp(value, "warn") == 0) {
+		slapdFrontendConfig->validate_cert = SLAPD_VALIDATE_CERT_WARN;
+	}
+
+	CFG_UNLOCK_WRITE(slapdFrontendConfig);
+	return retVal;
+}
+
 int
 config_get_force_sasl_external(void)
 {
@@ -5884,6 +5939,23 @@ config_set_value(
         slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
         break;
 
+    case CONFIG_SPECIAL_VALIDATE_CERT_SWITCH:
+        if (!value) {
+            slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");
+            break;
+        }
+
+        if (*((int *)value) == SLAPD_VALIDATE_CERT_ON) {
+            sval = "on";
+        } else if (*((int *)value) == SLAPD_VALIDATE_CERT_WARN) {
+            sval = "warn";
+        } else {
+            sval = "off";
+        }
+        slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
+
+        break;
+
     default:
         PR_ASSERT(0); /* something went horribly wrong . . . */
         break;

+ 2 - 0
ldap/servers/slapd/proto-slap.h

@@ -369,6 +369,7 @@ int config_set_require_secure_binds(const char *attrname, char *value, char *err
 int config_set_anon_access_switch(const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_localssf(const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_minssf(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_validate_cert_switch(const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, int apply);
 int config_set_csnlogging(const char *attrname, char *value, char *errorbuf, int apply);
 int config_set_force_sasl_external(const char *attrname, char *value, char *errorbuf, int apply );
@@ -507,6 +508,7 @@ int config_get_require_secure_binds(void);
 int config_get_anon_access_switch(void);
 int config_get_localssf(void);
 int config_get_minssf(void);
+int config_get_validate_cert_switch(void);
 int config_get_csnlogging();
 #ifdef MEMPOOL_EXPERIMENTAL
 int config_get_mempool_switch();

+ 7 - 0
ldap/servers/slapd/slap.h

@@ -334,6 +334,11 @@ typedef void	(*VFP0)(void);
 #define SLAPD_ANON_ACCESS_ON            1
 #define SLAPD_ANON_ACCESS_ROOTDSE       2
 
+/* Server certificate validation */
+#define SLAPD_VALIDATE_CERT_OFF         0
+#define SLAPD_VALIDATE_CERT_ON          1
+#define SLAPD_VALIDATE_CERT_WARN        2
+
 struct subfilt {
 	char	*sf_type;
 	char	*sf_initial;
@@ -1829,6 +1834,7 @@ typedef struct _slapdEntryPoints {
 #define CONFIG_ANON_ACCESS_ATTRIBUTE "nsslapd-allow-anonymous-access"
 #define CONFIG_LOCALSSF_ATTRIBUTE "nsslapd-localssf"
 #define CONFIG_MINSSF_ATTRIBUTE "nsslapd-minssf"
+#define CONFIG_VALIDATE_CERT_ATTRIBUTE "nsslapd-validate-cert"
 #ifndef _WIN32
 #define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser"
 #endif /* !_WIN32 */
@@ -2004,6 +2010,7 @@ typedef struct _slapdFrontendConfig {
   int security;
   int SSLclientAuth;
   int ssl_check_hostname;
+  int validate_cert;
   int sizelimit;
   int SNMPenabled;
   char *SNMPdescription;

+ 28 - 14
ldap/servers/slapd/ssl.c

@@ -1016,11 +1016,38 @@ int slapd_ssl_init2(PRFileDesc **fd, int startTLS)
             /* Step Six  -- Configure Secure Server Mode  */
             if(pr_sock) {
                 SECCertificateUsage returnedUsages;
-                rv = CERT_VerifyCertificateNow(
+
+                if (config_get_validate_cert_switch() == SLAPD_VALIDATE_CERT_OFF) {
+                    /* If we're set to ignore certificate verification issues,
+                     * just skip performing verification. */
+                    rv = SECSuccess;
+                } else {
+                    /* Check if the certificate is valid. */
+                    rv = CERT_VerifyCertificateNow(
                                     CERT_GetDefaultCertDB(), cert, PR_TRUE,
                                     certificateUsageSSLServer, 
                                     SSL_RevealPinArg(pr_sock),
                                     &returnedUsages);
+
+                    if (rv != SECSuccess) {
+                        /* Log warning */
+                        errorCode = PR_GetError();
+                        slapd_SSL_warn("CERT_VerifyCertificateNow: "
+                                       "verify certificate failed "
+                                       "for cert %s of family %s ("
+                                       SLAPI_COMPONENT_NAME_NSPR
+                                       " error %d - %s)",
+                                       cert_name, *family, errorCode,
+                                       slapd_pr_strerror(errorCode));
+
+                        /* If we're set to only warn, go ahead and
+                         * override rv to allow us to start up. */
+                        if (config_get_validate_cert_switch() == SLAPD_VALIDATE_CERT_WARN) {
+                            rv = SECSuccess;
+                        }
+                    }
+                }
+
                 if (SECSuccess == rv) {
                     if( slapd_pk11_fortezzaHasKEA(cert) == PR_TRUE ) {
                         rv = SSL_ConfigSecureServer(*fd, cert, key, kt_fortezza);
@@ -1037,19 +1064,6 @@ int slapd_ssl_init2(PRFileDesc **fd, int startTLS)
                                 cert_name, *family, errorCode, 
                                 slapd_pr_strerror(errorCode));
                     }
-                } else {
-                    /* verify certificate failed */
-                    /* If the common name in the subject DN for the certificate
-                     * is not identical to the domain name passed in the 
-                     * hostname parameter, SECFailure. */
-                    errorCode = PR_GetError();
-                    slapd_SSL_warn("CERT_VerifyCertificateNow: "
-                                   "verify certificate failed "
-                                   "for cert %s of family %s ("
-                                   SLAPI_COMPONENT_NAME_NSPR
-                                   " error %d - %s)",
-                                   cert_name, *family, errorCode, 
-                                   slapd_pr_strerror(errorCode));
                 }
             }
             if (cert) {