From 6c12e1ff897862287cd7df7e0ca82af25c3828f0 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 1 Jul 2025 11:59:40 +0100 Subject: [PATCH 01/10] Add support for SSL error handling - Allow the registration of an optional callback using serf_ssl_error_cb_set(). - If the callback is registered, return a fixed string describing the error as created by the underlying crypto library. Example: [minfrin@rocky9 subversion]$ svn info https://svn.example.com/svn/example/core/ svn: E170013: Unable to connect to a repository at URL 'https://svn.example.com/svn/example/core' svn: E120171: TLS: error:0308010C:digital envelope routines::unsupported svn: E120171: Error running context: An error occurred during SSL communication --- buckets/ssl_buckets.c | 70 ++++++++++++++++++++++++++++++++----------- serf_bucket_types.h | 16 ++++++++++ 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 9760e73c..69957ad5 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -187,6 +187,10 @@ struct serf_ssl_context_t { X509 *cached_cert; EVP_PKEY *cached_cert_pw; + /* Error callback */ + serf_ssl_error_cb_t error_callback; + void *error_userdata; + apr_status_t pending_err; /* Status of a fatal error, returned on subsequent encrypt or decrypt @@ -334,10 +338,20 @@ detect_renegotiate(const SSL *s, int where, int ret) static void log_ssl_error(serf_ssl_context_t *ctx) { - unsigned long e = ERR_get_error(); - serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, - "SSL Error: %s\n", ERR_error_string(e, NULL)); + unsigned long err; + + while ((err = ERR_get_error())) { + + serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, + "SSL Error: %s\n", ERR_error_string(err, NULL)); + if (err && ctx->error_callback) { + char ebuf[256]; + ERR_error_string_n(err, ebuf, sizeof(ebuf)); + ctx->error_callback(ctx->error_userdata, ebuf); + } + + } } static void bio_set_data(BIO *bio, void *data) @@ -1056,15 +1070,6 @@ static apr_status_t status_from_ssl_error(serf_ssl_context_t *ctx, status = ctx->pending_err; ctx->pending_err = APR_SUCCESS; } else { - /*unsigned long l = ERR_peek_error(); - int lib = ERR_GET_LIB(l); - int reason = ERR_GET_REASON(l);*/ - - /* ### Detect more specific errors? - When lib is ERR_LIB_SSL, then reason is one of the - many SSL_R_XXXX reasons in ssl.h - */ - if (SSL_in_init(ctx->ssl)) ctx->fatal_err = SERF_ERROR_SSL_SETUP_FAILED; else @@ -1536,6 +1541,7 @@ static apr_status_t init_ssl_libraries(void) static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) { serf_ssl_context_t *ctx = SSL_get_app_data(ssl); + unsigned long err = 0; apr_status_t status; serf__log(LOGLVL_DEBUG, LOGCOMP_SSL, __FILE__, ctx->config, @@ -1606,7 +1612,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) return 1; } else { - int err = ERR_get_error(); + err = ERR_get_error(); ERR_clear_error(); if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 && ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) { @@ -1652,22 +1658,40 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) } return 1; } + else { + err = ERR_get_error(); + ERR_clear_error(); + + goto error; + } } } PKCS12_free(p12); bio_meth_free(biom); - return 0; + + goto error; } else { - serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, - "OpenSSL cert error: %d %d\n", ERR_GET_LIB(err), - ERR_GET_REASON(err)); PKCS12_free(p12); bio_meth_free(biom); + + goto error; } } } +error: + + serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, + "OpenSSL cert error: %d %d\n", ERR_GET_LIB(err), + ERR_GET_REASON(err)); + + if (err && ctx->error_callback) { + char ebuf[256]; + ERR_error_string_n(err, ebuf, sizeof(ebuf)); + ctx->error_callback(ctx->error_userdata, ebuf); + } + return 0; } @@ -1724,6 +1748,15 @@ void serf_ssl_server_cert_chain_callback_set( context->server_cert_userdata = data; } +void serf_ssl_error_cb_set( + serf_ssl_context_t *context, + serf_ssl_error_cb_t callback, + void *data) +{ + context->error_callback = callback; + context->error_userdata = data; +} + static int ssl_new_session(SSL *ssl, SSL_SESSION *session) { serf_ssl_context_t *ctx = SSL_get_app_data(ssl); @@ -1788,6 +1821,9 @@ static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator) ssl_ctx->protocol_callback = NULL; ssl_ctx->protocol_userdata = NULL; + ssl_ctx->error_callback = NULL; + ssl_ctx->error_userdata = NULL; + SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER, validate_server_certificate); SSL_CTX_set_options(ssl_ctx->ctx, SSL_OP_ALL); diff --git a/serf_bucket_types.h b/serf_bucket_types.h index 121dda66..b3eb2fc8 100644 --- a/serf_bucket_types.h +++ b/serf_bucket_types.h @@ -647,6 +647,22 @@ void serf_ssl_server_cert_chain_callback_set( serf_ssl_server_cert_chain_cb_t cert_chain_callback, void *data); +/** + * Callback type for detailed TLS error strings. + */ +typedef apr_status_t (*serf_ssl_error_cb_t)( + void *data, + const char *message); + +/** + * Set a callback to return any detailed certificate error from the underlying + * cryptographic library.. + */ +void serf_ssl_error_cb_set( + serf_ssl_context_t *context, + serf_ssl_error_cb_t callback, + void *data); + /** * Use the default root CA certificates as included with the OpenSSL library. */ From f7c70c90eadfacd2dc2e7e66b6572c834ca1a29c Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 1 Jul 2025 12:16:22 +0100 Subject: [PATCH 02/10] The correct term is "baton". --- buckets/ssl_buckets.c | 12 ++++++------ serf_bucket_types.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 69957ad5..981d4fba 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -189,7 +189,7 @@ struct serf_ssl_context_t { /* Error callback */ serf_ssl_error_cb_t error_callback; - void *error_userdata; + void *error_baton; apr_status_t pending_err; @@ -348,7 +348,7 @@ static void log_ssl_error(serf_ssl_context_t *ctx) if (err && ctx->error_callback) { char ebuf[256]; ERR_error_string_n(err, ebuf, sizeof(ebuf)); - ctx->error_callback(ctx->error_userdata, ebuf); + ctx->error_callback(ctx->error_baton, ebuf); } } @@ -1689,7 +1689,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) if (err && ctx->error_callback) { char ebuf[256]; ERR_error_string_n(err, ebuf, sizeof(ebuf)); - ctx->error_callback(ctx->error_userdata, ebuf); + ctx->error_callback(ctx->error_baton, ebuf); } return 0; @@ -1751,10 +1751,10 @@ void serf_ssl_server_cert_chain_callback_set( void serf_ssl_error_cb_set( serf_ssl_context_t *context, serf_ssl_error_cb_t callback, - void *data) + void *baton) { context->error_callback = callback; - context->error_userdata = data; + context->error_baton = baton; } static int ssl_new_session(SSL *ssl, SSL_SESSION *session) @@ -1822,7 +1822,7 @@ static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator) ssl_ctx->protocol_userdata = NULL; ssl_ctx->error_callback = NULL; - ssl_ctx->error_userdata = NULL; + ssl_ctx->error_baton = NULL; SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER, validate_server_certificate); diff --git a/serf_bucket_types.h b/serf_bucket_types.h index b3eb2fc8..082165f7 100644 --- a/serf_bucket_types.h +++ b/serf_bucket_types.h @@ -651,7 +651,7 @@ void serf_ssl_server_cert_chain_callback_set( * Callback type for detailed TLS error strings. */ typedef apr_status_t (*serf_ssl_error_cb_t)( - void *data, + void *baton, const char *message); /** @@ -661,7 +661,7 @@ typedef apr_status_t (*serf_ssl_error_cb_t)( void serf_ssl_error_cb_set( serf_ssl_context_t *context, serf_ssl_error_cb_t callback, - void *data); + void *baton); /** * Use the default root CA certificates as included with the OpenSSL library. From 6b6d66e0e4c4df0c65dca033772eef5a595ff964 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 1 Jul 2025 12:54:28 +0100 Subject: [PATCH 03/10] Add additional detail to the error callback description. --- serf_bucket_types.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/serf_bucket_types.h b/serf_bucket_types.h index 082165f7..cc2f4eea 100644 --- a/serf_bucket_types.h +++ b/serf_bucket_types.h @@ -648,7 +648,14 @@ void serf_ssl_server_cert_chain_callback_set( void *data); /** - * Callback type for detailed TLS error strings. + * Callback type for detailed TLS error strings. This callback will be fired + * every time the underlying crypto library encounters an error. The message + * lasts only as long as the callback, if the caller wants to set aside the + * message for later use, a copy must be made. + * + * It is possible that for a given error multiple strings will be returned + * in multiple callbacks. The caller may choose to handle all strings, or + * may choose to ignore all strings but the last most detailed one. */ typedef apr_status_t (*serf_ssl_error_cb_t)( void *baton, @@ -656,7 +663,10 @@ typedef apr_status_t (*serf_ssl_error_cb_t)( /** * Set a callback to return any detailed certificate error from the underlying - * cryptographic library.. + * cryptographic library. + * + * The callback is associated with the context, however the choice of baton + * will depend on the needs of the caller. */ void serf_ssl_error_cb_set( serf_ssl_context_t *context, From 217d1dd071a1ba6417298373d251450e9a145b02 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Tue, 1 Jul 2025 16:54:01 +0100 Subject: [PATCH 04/10] Add the APR status to the error callback. --- buckets/ssl_buckets.c | 15 ++++----------- serf_bucket_types.h | 1 + 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 981d4fba..8cc2abdd 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -348,7 +348,7 @@ static void log_ssl_error(serf_ssl_context_t *ctx) if (err && ctx->error_callback) { char ebuf[256]; ERR_error_string_n(err, ebuf, sizeof(ebuf)); - ctx->error_callback(ctx->error_baton, ebuf); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); } } @@ -1682,15 +1682,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) error: - serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, - "OpenSSL cert error: %d %d\n", ERR_GET_LIB(err), - ERR_GET_REASON(err)); - - if (err && ctx->error_callback) { - char ebuf[256]; - ERR_error_string_n(err, ebuf, sizeof(ebuf)); - ctx->error_callback(ctx->error_baton, ebuf); - } + log_ssl_error(ctx); return 0; } @@ -2135,8 +2127,9 @@ apr_status_t serf_ssl_add_crl_from_file(serf_ssl_context_t *ssl_ctx, result = X509_STORE_add_crl(store, crl); if (!result) { + ssl_ctx->fatal_err = status = SERF_ERROR_SSL_CERT_FAILED; log_ssl_error(ssl_ctx); - return SERF_ERROR_SSL_CERT_FAILED; + return status; } /* TODO: free crl when closing ssl session */ diff --git a/serf_bucket_types.h b/serf_bucket_types.h index cc2f4eea..0fec8acf 100644 --- a/serf_bucket_types.h +++ b/serf_bucket_types.h @@ -659,6 +659,7 @@ void serf_ssl_server_cert_chain_callback_set( */ typedef apr_status_t (*serf_ssl_error_cb_t)( void *baton, + apr_status_t status, const char *message); /** From 2a9afdfea4bf67a72460ded71dfdaed9e0feabb1 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Wed, 2 Jul 2025 09:17:52 +0100 Subject: [PATCH 05/10] Don't log handled errors. --- buckets/ssl_buckets.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 8cc2abdd..c6202f62 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -342,9 +342,6 @@ static void log_ssl_error(serf_ssl_context_t *ctx) while ((err = ERR_get_error())) { - serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, - "SSL Error: %s\n", ERR_error_string(err, NULL)); - if (err && ctx->error_callback) { char ebuf[256]; ERR_error_string_n(err, ebuf, sizeof(ebuf)); From 4863887c815709c531c894780761ee8fa16d4916 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Wed, 2 Jul 2025 09:26:01 +0100 Subject: [PATCH 06/10] Remove unnecessary ERR_get_error() and simplify. --- buckets/ssl_buckets.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index c6202f62..947fdce1 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -1656,31 +1656,27 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) return 1; } else { - err = ERR_get_error(); - ERR_clear_error(); - - goto error; + log_ssl_error(ctx); + break; } } } PKCS12_free(p12); bio_meth_free(biom); - goto error; + log_ssl_error(ctx); + break; } else { PKCS12_free(p12); bio_meth_free(biom); - goto error; + log_ssl_error(ctx); + break; } } } -error: - - log_ssl_error(ctx); - return 0; } From 83cb75d1a43fb3038b0cbbd9443bd51665fc3f9d Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Wed, 2 Jul 2025 09:34:43 +0100 Subject: [PATCH 07/10] Do not hang indefintely when the file can't be found, handle the error. --- buckets/ssl_buckets.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 947fdce1..7be20dc4 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -1576,9 +1576,13 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) status = apr_file_open(&cert_file, cert_path, APR_READ, APR_OS_DEFAULT, ctx->pool); - /* TODO: this will hang indefintely when the file can't be found. */ if (status) { - continue; + if (ctx->error_callback) { + char ebuf[256]; + apr_strerror(status, ebuf, sizeof(ebuf)); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + break; } biom = bio_meth_file_new(); From 1c8c2fa2f53e9ec70d764eba824656724dfc5a94 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Fri, 4 Jul 2025 15:52:22 +0100 Subject: [PATCH 08/10] Add error handling to new openssl3+ support. --- buckets/ssl_buckets.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 6c800c9f..43e42b8d 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -1095,6 +1095,15 @@ static apr_status_t status_from_ssl_error(serf_ssl_context_t *ctx, log_ssl_error(ctx); } break; + + case SSL_ERROR_WANT_X509_LOOKUP: + /* The ssl_need_client_cert() function returned -1 because an + * error occurred inside that function. The error has already + * been handled, just return the fatal error. + */ + status = ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + break; + default: status = ctx->fatal_err = SERF_ERROR_SSL_COMM_FAILED; log_ssl_error(ctx); @@ -1660,10 +1669,6 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) store = OSSL_STORE_open_ex(cert_uri, NULL, NULL, ui_method, ctx, NULL, NULL, NULL); if (!store) { - int err = ERR_get_error(); - serf__log(LOGLVL_ERROR, LOGCOMP_SSL, __FILE__, ctx->config, - "OpenSSL store error (%s): %d %d\n", cert_uri, - ERR_GET_LIB(err), ERR_GET_REASON(err)); break; } @@ -1719,10 +1724,12 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) OSSL_STORE_INFO_free(info); } - /* FIXME: openssl error checking goes here */ - OSSL_STORE_close(store); + if (ERR_peek_error()) { + break; + } + /* walk the leaf certificates, choose the best one */ while ((c = sk_X509_pop(leaves))) { @@ -1789,6 +1796,12 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) X509_STORE_free(requests); UI_destroy_method(ui_method); + if (ERR_peek_error()) { + log_ssl_error(ctx); + + return -1; + } + /* we settled on a cert and key, cache it for later */ if (*cert && *pkey) { From b881b442b3b77d0f8e54f48792711867fc882a2e Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Sat, 5 Jul 2025 09:54:11 +0100 Subject: [PATCH 09/10] Return a client side error when we cannot parse PKCS12 files. Don't send nothing instead and fail because the server said access is denied. --- buckets/ssl_buckets.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 43e42b8d..003204b6 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -1866,7 +1866,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) apr_strerror(status, ebuf, sizeof(ebuf)); ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); } - break; + return -1; } biom = bio_meth_file_new(); @@ -1945,7 +1945,7 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) } else { log_ssl_error(ctx); - break; + return -1; } } } @@ -1953,14 +1953,14 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) bio_meth_free(biom); log_ssl_error(ctx); - break; + return -1; } else { PKCS12_free(p12); bio_meth_free(biom); log_ssl_error(ctx); - break; + return -1; } } } From 1407bdcbe044f40a6fbbe7ba049bf4117f355d32 Mon Sep 17 00:00:00 2001 From: Graham Leggett Date: Sat, 5 Jul 2025 10:22:12 +0100 Subject: [PATCH 10/10] Put certificate failures into context, so that end users have more than just a low level openssl error. --- buckets/ssl_buckets.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c index 003204b6..0d09917e 100644 --- a/buckets/ssl_buckets.c +++ b/buckets/ssl_buckets.c @@ -1669,6 +1669,14 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) store = OSSL_STORE_open_ex(cert_uri, NULL, NULL, ui_method, ctx, NULL, NULL, NULL); if (!store) { + + if (ctx->error_callback) { + char ebuf[1024]; + ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + apr_snprintf(ebuf, sizeof(ebuf), "could not open URI: %s", cert_uri); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + break; } @@ -1678,6 +1686,14 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) info = OSSL_STORE_load(store); if (!info) { + + if (ctx->error_callback) { + char ebuf[1024]; + ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + apr_snprintf(ebuf, sizeof(ebuf), "could not read URI: %s", cert_uri); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + break; } @@ -1862,7 +1878,9 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) if (status) { if (ctx->error_callback) { - char ebuf[256]; + char ebuf[1024]; + apr_snprintf(ebuf, sizeof(ebuf), "could not open PKCS12: %s", cert_path); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); apr_strerror(status, ebuf, sizeof(ebuf)); ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); } @@ -1944,6 +1962,14 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) return 1; } else { + + if (ctx->error_callback) { + char ebuf[1024]; + ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + apr_snprintf(ebuf, sizeof(ebuf), "could not parse PKCS12: %s", cert_path); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + log_ssl_error(ctx); return -1; } @@ -1952,6 +1978,13 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) PKCS12_free(p12); bio_meth_free(biom); + if (ctx->error_callback) { + char ebuf[1024]; + ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + apr_snprintf(ebuf, sizeof(ebuf), "PKCS12 needs a password: %s", cert_path); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + log_ssl_error(ctx); return -1; } @@ -1959,6 +1992,13 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey) PKCS12_free(p12); bio_meth_free(biom); + if (ctx->error_callback) { + char ebuf[1024]; + ctx->fatal_err = SERF_ERROR_SSL_CERT_FAILED; + apr_snprintf(ebuf, sizeof(ebuf), "could not parse PKCS12: %s", cert_path); + ctx->error_callback(ctx->error_baton, ctx->fatal_err, ebuf); + } + log_ssl_error(ctx); return -1; }