static int init_ssl_for_socket()

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;
                }
            }
        }
    }
}