in buckets/ssl_buckets.c [1556:1692]
static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
{
serf_ssl_context_t *ctx = SSL_get_app_data(ssl);
apr_status_t status;
serf__log(LOGLVL_DEBUG, LOGCOMP_SSL, __FILE__, ctx->config,
"Server requests a client certificate.\n");
if (ctx->cached_cert) {
*cert = ctx->cached_cert;
*pkey = ctx->cached_cert_pw;
return 1;
}
while (ctx->cert_callback) {
const char *cert_path;
apr_file_t *cert_file;
BIO *bio;
BIO_METHOD *biom;
PKCS12 *p12;
int i;
int retrying_success = 0;
if (ctx->cert_file_success) {
status = APR_SUCCESS;
cert_path = ctx->cert_file_success;
ctx->cert_file_success = NULL;
retrying_success = 1;
} else {
status = ctx->cert_callback(ctx->cert_userdata, &cert_path);
}
if (status || !cert_path) {
break;
}
/* Load the x.509 cert file stored in PKCS12 */
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;
}
biom = bio_meth_file_new();
bio = BIO_new(biom);
bio_set_data(bio, cert_file);
ctx->cert_path = cert_path;
p12 = d2i_PKCS12_bio(bio, NULL);
BIO_free(bio);
apr_file_close(cert_file);
i = PKCS12_parse(p12, NULL, pkey, cert, NULL);
if (i == 1) {
PKCS12_free(p12);
bio_meth_free(biom);
ctx->cached_cert = *cert;
ctx->cached_cert_pw = *pkey;
if (!retrying_success && ctx->cert_cache_pool) {
const char *c;
c = apr_pstrdup(ctx->cert_cache_pool, ctx->cert_path);
apr_pool_userdata_setn(c, "serf:ssl:cert",
apr_pool_cleanup_null,
ctx->cert_cache_pool);
}
return 1;
}
else {
int err = ERR_get_error();
ERR_clear_error();
if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&
ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {
if (ctx->cert_pw_callback) {
const char *password;
if (ctx->cert_pw_success) {
status = APR_SUCCESS;
password = ctx->cert_pw_success;
ctx->cert_pw_success = NULL;
} else {
status = ctx->cert_pw_callback(ctx->cert_pw_userdata,
ctx->cert_path,
&password);
}
if (!status && password) {
i = PKCS12_parse(p12, password, pkey, cert, NULL);
if (i == 1) {
PKCS12_free(p12);
bio_meth_free(biom);
ctx->cached_cert = *cert;
ctx->cached_cert_pw = *pkey;
if (!retrying_success && ctx->cert_cache_pool) {
const char *c;
c = apr_pstrdup(ctx->cert_cache_pool,
ctx->cert_path);
apr_pool_userdata_setn(c, "serf:ssl:cert",
apr_pool_cleanup_null,
ctx->cert_cache_pool);
}
if (!retrying_success && ctx->cert_pw_cache_pool) {
const char *c;
c = apr_pstrdup(ctx->cert_pw_cache_pool,
password);
apr_pool_userdata_setn(c, "serf:ssl:certpw",
apr_pool_cleanup_null,
ctx->cert_pw_cache_pool);
}
return 1;
}
}
}
PKCS12_free(p12);
bio_meth_free(biom);
return 0;
}
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);
}
}
}
return 0;
}