49f6078a21
Resolves: #725819
210 lines
8.1 KiB
Diff
210 lines
8.1 KiB
Diff
Fix server side VerifyCert allow/try behavior
|
|
|
|
If the olcTLSVerifyClient is set to a value other than "never", the server
|
|
should request that the client send a client certificate for possible use
|
|
with client cert auth (e.g. SASL/EXTERNAL).
|
|
If set to "allow", if the client sends a cert, and there are problems with
|
|
it, the server will warn about problems, but will allow the SSL session to
|
|
proceed without a client cert.
|
|
If set to "try", if the client sends a cert, and there are problems with
|
|
it, the server will warn about those problems, and shutdown the SSL session.
|
|
If set to "demand" or "hard", the client must send a cert, and the server
|
|
will shutdown the SSL session if there are problems.
|
|
I added a new member of the tlsm context structure - tc_warn_only - if this
|
|
is set, tlsm_verify_cert will only warn about errors, and only if TRACE
|
|
level debug is set. This allows the server to warn but allow bad certs
|
|
if "allow" is set, and warn and fail if "try" is set.
|
|
|
|
Author: Rich Megginson <rmeggins@redhat.com>
|
|
Upstream ITS: #7002
|
|
Upstream commit: 210b156ece28a71cb625283fa5c30ee76d639cdc
|
|
Resolves: #725819
|
|
|
|
diff --git a/libraries/libldap/tls_m.c b/libraries/libldap/tls_m.c
|
|
index 72fdf49..997b3eb 100644
|
|
--- a/libraries/libldap/tls_m.c
|
|
+++ b/libraries/libldap/tls_m.c
|
|
@@ -96,6 +96,7 @@ typedef struct tlsm_ctx {
|
|
#endif
|
|
PK11GenericObject **tc_pem_objs; /* array of objects to free */
|
|
int tc_n_pem_objs; /* number of objects */
|
|
+ PRBool tc_warn_only; /* only warn of errors in validation */
|
|
#ifdef LDAP_R_COMPILE
|
|
ldap_pvt_thread_mutex_t tc_refmutex;
|
|
#endif
|
|
@@ -945,6 +946,11 @@ tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
|
|
CERTVerifyLog verifylog;
|
|
SECStatus ret = SECSuccess;
|
|
const char *name;
|
|
+ int debug_level = LDAP_DEBUG_ANY;
|
|
+
|
|
+ if ( errorToIgnore == -1 ) {
|
|
+ debug_level = LDAP_DEBUG_TRACE;
|
|
+ }
|
|
|
|
/* the log captures information about every cert in the chain, so we can tell
|
|
which cert caused the problem and what the problem was */
|
|
@@ -965,7 +971,7 @@ tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
|
|
/* it is possible for CERT_VerifyCertificate return with an error with no logging */
|
|
if ( ret != SECSuccess ) {
|
|
PRErrorCode errcode = PR_GetError();
|
|
- Debug( LDAP_DEBUG_ANY,
|
|
+ Debug( debug_level,
|
|
"TLS: certificate [%s] is not valid - error %d:%s.\n",
|
|
name ? name : "(unknown)",
|
|
errcode, PR_ErrorToString( errcode, PR_LANGUAGE_I_DEFAULT ) );
|
|
@@ -995,17 +1001,17 @@ tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
|
|
"please fix your certs if possible\n", name, 0, 0 );
|
|
} else { /* does not have basicconstraint, or some other error */
|
|
ret = SECFailure;
|
|
- Debug( LDAP_DEBUG_ANY,
|
|
+ Debug( debug_level,
|
|
"TLS: certificate [%s] is not valid - CA cert is not valid\n",
|
|
name, 0, 0 );
|
|
}
|
|
} else if ( errorToIgnore && ( node->error == errorToIgnore ) ) {
|
|
- Debug( LDAP_DEBUG_ANY,
|
|
+ Debug( debug_level,
|
|
"TLS: Warning: ignoring error for certificate [%s] - error %ld:%s.\n",
|
|
name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
|
|
} else {
|
|
ret = SECFailure;
|
|
- Debug( LDAP_DEBUG_ANY,
|
|
+ Debug( debug_level,
|
|
"TLS: certificate [%s] is not valid - error %ld:%s.\n",
|
|
name, node->error, PR_ErrorToString( node->error, PR_LANGUAGE_I_DEFAULT ) );
|
|
}
|
|
@@ -1020,7 +1026,9 @@ tlsm_verify_cert(CERTCertDBHandle *handle, CERTCertificate *cert, void *pinarg,
|
|
if ( ret == SECSuccess ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"TLS: certificate [%s] is valid\n", name, 0, 0 );
|
|
- }
|
|
+ } else if ( errorToIgnore == -1 ) {
|
|
+ ret = SECSuccess;
|
|
+ }
|
|
|
|
return ret;
|
|
}
|
|
@@ -1032,10 +1040,15 @@ tlsm_auth_cert_handler(void *arg, PRFileDesc *fd,
|
|
SECCertificateUsage certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
|
|
SECStatus ret = SECSuccess;
|
|
CERTCertificate *peercert = SSL_PeerCertificate( fd );
|
|
+ int errorToIgnore = 0;
|
|
+ tlsm_ctx *ctx = (tlsm_ctx *)arg;
|
|
+
|
|
+ if (ctx && ctx->tc_warn_only )
|
|
+ errorToIgnore = -1;
|
|
|
|
- ret = tlsm_verify_cert( (CERTCertDBHandle *)arg, peercert,
|
|
+ ret = tlsm_verify_cert( ctx->tc_certdb, peercert,
|
|
SSL_RevealPinArg( fd ),
|
|
- checksig, certUsage, 0 );
|
|
+ checksig, certUsage, errorToIgnore );
|
|
CERT_DestroyCertificate( peercert );
|
|
|
|
return ret;
|
|
@@ -1758,6 +1771,8 @@ tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certnam
|
|
SECCertificateUsage certUsage;
|
|
PRBool checkSig = PR_TRUE;
|
|
SECStatus status;
|
|
+ /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
|
|
+ int errorToIgnore = SEC_ERROR_UNKNOWN_ISSUER;
|
|
|
|
if ( pRetKey ) {
|
|
*pRetKey = key; /* caller will deal with this */
|
|
@@ -1774,9 +1789,11 @@ tlsm_find_and_verify_cert_key(tlsm_ctx *ctx, PRFileDesc *fd, const char *certnam
|
|
} else {
|
|
checkSig = PR_FALSE;
|
|
}
|
|
- /* may not have a CA cert - ok - ignore SEC_ERROR_UNKNOWN_ISSUER */
|
|
+ if ( ctx->tc_warn_only ) {
|
|
+ errorToIgnore = -1;
|
|
+ }
|
|
status = tlsm_verify_cert( ctx->tc_certdb, cert, pin_arg,
|
|
- checkSig, certUsage, SEC_ERROR_UNKNOWN_ISSUER );
|
|
+ checkSig, certUsage, errorToIgnore );
|
|
if ( status == SECSuccess ) {
|
|
rc = 0;
|
|
}
|
|
@@ -1803,10 +1820,14 @@ tlsm_get_client_auth_data( void *arg, PRFileDesc *fd,
|
|
{
|
|
tlsm_ctx *ctx = (tlsm_ctx *)arg;
|
|
int rc;
|
|
+ PRBool saveval;
|
|
|
|
/* don't need caNames - this function will call CERT_VerifyCertificateNow
|
|
which will verify the cert against the known CAs */
|
|
+ saveval = ctx->tc_warn_only;
|
|
+ ctx->tc_warn_only = PR_TRUE;
|
|
rc = tlsm_find_and_verify_cert_key( ctx, fd, ctx->tc_certname, 0, pRetCert, pRetKey );
|
|
+ ctx->tc_warn_only = saveval;
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"TLS: error: unable to perform client certificate authentication for "
|
|
@@ -1837,8 +1858,12 @@ tlsm_clientauth_init( tlsm_ctx *ctx )
|
|
{
|
|
SECStatus status = SECFailure;
|
|
int rc;
|
|
+ PRBool saveval;
|
|
|
|
+ saveval = ctx->tc_warn_only;
|
|
+ ctx->tc_warn_only = PR_TRUE;
|
|
rc = tlsm_find_and_verify_cert_key( ctx, ctx->tc_model, ctx->tc_certname, 0, NULL, NULL );
|
|
+ ctx->tc_warn_only = saveval;
|
|
if ( rc ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"TLS: error: unable to set up client certificate authentication for "
|
|
@@ -1887,6 +1912,7 @@ tlsm_ctx_new ( struct ldapoptions *lo )
|
|
#endif /* HAVE_NSS_INITCONTEXT */
|
|
ctx->tc_pem_objs = NULL;
|
|
ctx->tc_n_pem_objs = 0;
|
|
+ ctx->tc_warn_only = PR_FALSE;
|
|
}
|
|
return (tls_ctx *)ctx;
|
|
}
|
|
@@ -2048,7 +2074,9 @@ tlsm_deferred_ctx_init( void *arg )
|
|
return -1;
|
|
}
|
|
|
|
- if ( ctx->tc_require_cert ) {
|
|
+ if ( !ctx->tc_require_cert ) {
|
|
+ ctx->tc_verify_cert = PR_FALSE;
|
|
+ } else if ( !ctx->tc_is_server ) {
|
|
request_cert = PR_TRUE;
|
|
require_cert = SSL_REQUIRE_NO_ERROR;
|
|
if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
|
|
@@ -2057,8 +2085,22 @@ tlsm_deferred_ctx_init( void *arg )
|
|
}
|
|
if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW )
|
|
ctx->tc_verify_cert = PR_TRUE;
|
|
- } else {
|
|
- ctx->tc_verify_cert = PR_FALSE;
|
|
+ } else { /* server */
|
|
+ /* server does not request certs by default */
|
|
+ /* if allow - client may send cert, server will ignore if errors */
|
|
+ /* if try - client may send cert, server will error if bad cert */
|
|
+ /* if hard or demand - client must send cert, server will error if bad cert */
|
|
+ request_cert = PR_TRUE;
|
|
+ require_cert = SSL_REQUIRE_NO_ERROR;
|
|
+ if ( ctx->tc_require_cert == LDAP_OPT_X_TLS_DEMAND ||
|
|
+ ctx->tc_require_cert == LDAP_OPT_X_TLS_HARD ) {
|
|
+ require_cert = SSL_REQUIRE_ALWAYS;
|
|
+ }
|
|
+ if ( ctx->tc_require_cert != LDAP_OPT_X_TLS_ALLOW ) {
|
|
+ ctx->tc_verify_cert = PR_TRUE;
|
|
+ } else {
|
|
+ ctx->tc_warn_only = PR_TRUE;
|
|
+ }
|
|
}
|
|
|
|
if ( SECSuccess != SSL_OptionSet( ctx->tc_model, SSL_REQUEST_CERTIFICATE, request_cert ) ) {
|
|
@@ -2193,7 +2235,7 @@ tlsm_deferred_ctx_init( void *arg )
|
|
|
|
/* Callback for authenticating certificate */
|
|
if ( SSL_AuthCertificateHook( ctx->tc_model, tlsm_auth_cert_handler,
|
|
- ctx->tc_certdb ) != SECSuccess ) {
|
|
+ ctx ) != SECSuccess ) {
|
|
PRErrorCode err = PR_GetError();
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"TLS: error: could not set auth cert handler for moznss - error %d:%s\n",
|