in zookeeper-client/zookeeper-client-c/src/zookeeper.c [2737:2848]
static int init_ssl_for_socket(zsock_t *fd, zhandle_t *zh, int fail_on_error) {
SSL_CTX **ctx;
if (!fd->ssl_sock) {
const SSL_METHOD *method;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
SSL_library_init();
method = SSLv23_client_method();
#else
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
method = TLS_client_method();
#endif
fd->ssl_ctx = SSL_CTX_new(method);
ctx = &fd->ssl_ctx;
SSL_CTX_set_verify(*ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
/*SERVER CA FILE*/
if (SSL_CTX_load_verify_locations(*ctx, fd->cert->ca, 0) != 1) {
SSL_CTX_free(*ctx);
LOG_ERROR(LOGCALLBACK(zh), "Failed to load CA file %s", fd->cert->ca);
errno = EINVAL;
return ZBADARGUMENTS;
}
if (SSL_CTX_set_default_verify_paths(*ctx) != 1) {
SSL_CTX_free(*ctx);
LOG_ERROR(LOGCALLBACK(zh), "Call to SSL_CTX_set_default_verify_paths failed");
errno = EINVAL;
return ZBADARGUMENTS;
}
/*CLIENT CA FILE (With Certificate Chain)*/
if (SSL_CTX_use_certificate_chain_file(*ctx, fd->cert->cert) != 1) {
SSL_CTX_free(*ctx);
LOG_ERROR(LOGCALLBACK(zh), "Failed to load client certificate chain from %s", fd->cert->cert);
errno = EINVAL;
return ZBADARGUMENTS;
}
/*CLIENT PRIVATE KEY*/
SSL_CTX_set_default_passwd_cb_userdata(*ctx, fd->cert->passwd);
if (SSL_CTX_use_PrivateKey_file(*ctx, fd->cert->key, SSL_FILETYPE_PEM) != 1) {
SSL_CTX_free(*ctx);
LOG_ERROR(LOGCALLBACK(zh), "Failed to load client private key from %s", fd->cert->key);
errno = EINVAL;
return ZBADARGUMENTS;
}
/*CHECK*/
if (SSL_CTX_check_private_key(*ctx) != 1) {
SSL_CTX_free(*ctx);
LOG_ERROR(LOGCALLBACK(zh), "SSL_CTX_check_private_key failed");
errno = EINVAL;
return ZBADARGUMENTS;
}
/*MULTIPLE HANDSHAKE*/
SSL_CTX_set_mode(*ctx, SSL_MODE_AUTO_RETRY);
fd->ssl_sock = SSL_new(*ctx);
if (fd->ssl_sock == NULL) {
if (fail_on_error) {
return handle_socket_error_msg(zh, __LINE__, __func__, ZSSLCONNECTIONERROR, "error creating ssl context");
} else {
LOG_ERROR(LOGCALLBACK(zh), "error creating ssl context");
return ZSSLCONNECTIONERROR;
}
}
SSL_set_fd(fd->ssl_sock, fd->sock);
}
while(1) {
int rc;
int sock = fd->sock;
struct timeval tv;
fd_set s_rfds, s_wfds;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&s_rfds);
FD_ZERO(&s_wfds);
rc = SSL_connect(fd->ssl_sock);
if (rc == 1) {
return ZOK;
} else {
rc = SSL_get_error(fd->ssl_sock, rc);
if (rc == SSL_ERROR_WANT_READ) {
FD_SET(sock, &s_rfds);
FD_CLR(sock, &s_wfds);
} else if (rc == SSL_ERROR_WANT_WRITE) {
FD_SET(sock, &s_wfds);
FD_CLR(sock, &s_rfds);
} else {
if (fail_on_error) {
return handle_socket_error_msg(zh, __LINE__, __func__, ZSSLCONNECTIONERROR, "error in ssl connect");
} else {
LOG_ERROR(LOGCALLBACK(zh), "error in ssl connect");
return ZSSLCONNECTIONERROR;
}
}
rc = select(sock + 1, &s_rfds, &s_wfds, NULL, &tv);
if (rc == -1) {
if (fail_on_error) {
return handle_socket_error_msg(zh, __LINE__, __func__, ZSSLCONNECTIONERROR, "error in ssl connect (after select)");
} else {
LOG_ERROR(LOGCALLBACK(zh), "error in ssl connect (after select)");
return ZSSLCONNECTIONERROR;
}
}
}
}
}