Created
July 4, 2019 14:42
-
-
Save yossigo/09b530bbde96cb70153aa1dc78abc935 to your computer and use it in GitHub Desktop.
A small client that tests TLS renegotiation in the middle of sending a Redis command.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A small test client that: | |
* 1. Establishes a TLS connection with Redis. | |
* 2. Starts sending a request, getting Redis to read it. | |
* 3. Before completing the command, initiates renegotiation. | |
* | |
* This basically aims to test the ability of the TLS implementation | |
* to respond while busy in an SSL_read() type of operation. | |
*/ | |
#include <sys/socket.h> | |
#include <resolv.h> | |
#include <netdb.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <unistd.h> | |
#include <openssl/bio.h> | |
#include <openssl/ssl.h> | |
#include <openssl/err.h> | |
#include <openssl/pem.h> | |
#include <openssl/x509.h> | |
#include <openssl/x509_vfy.h> | |
int make_socket(const char *addr, int port) | |
{ | |
struct hostent *host; | |
struct sockaddr_in sa; | |
int fd; | |
int ret; | |
host = gethostbyname(addr); | |
assert(host != NULL); | |
fd = socket(AF_INET, SOCK_STREAM, 0); | |
memset(&sa, 0, sizeof(sa)); | |
sa.sin_family = AF_INET; | |
sa.sin_port = ntohs(port); | |
sa.sin_addr.s_addr = *(long *)(host->h_addr); | |
ret = connect(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr)); | |
assert(ret != -1); | |
return fd; | |
} | |
void start_request(SSL *ssl) | |
{ | |
const char request[] = "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$10000\r\n"; | |
int ret = SSL_write(ssl, request, strlen(request)); | |
assert(ret == strlen(request)); | |
fprintf(stderr, ">> Started a request\n"); | |
} | |
void complete_request(SSL *ssl) | |
{ | |
char data[10002] = { 0 }; | |
int ret; | |
data[10000] = '\r'; | |
data[10001] = '\n'; | |
ret = SSL_write(ssl, data, sizeof(data)); | |
assert(ret == sizeof(data)); | |
fprintf(stderr, ">> Completed request, reading response...\n"); | |
char resp[100]; | |
ret = SSL_read(ssl, resp, 100); | |
assert(ret > 0); | |
fprintf(stderr, " Received:\n%.*s\n", ret, resp); | |
} | |
int main() { | |
/* Initialize */ | |
OpenSSL_add_all_algorithms(); | |
ERR_load_BIO_strings(); | |
ERR_load_crypto_strings(); | |
SSL_load_error_strings(); | |
SSL_library_init(); | |
/* Prepare client and context */ | |
const SSL_METHOD *method; | |
SSL_CTX *ctx; | |
SSL *ssl; | |
int sock; | |
int ret; | |
method = TLS_client_method(); | |
ctx = SSL_CTX_new(method); | |
assert(ctx != NULL); | |
/* New connection */ | |
ssl = SSL_new(ctx); | |
sock = make_socket("127.0.0.1", 6379); | |
assert(sock != -1); | |
SSL_set_fd(ssl, sock); | |
ret = SSL_connect(ssl); | |
assert(ret == 1); | |
fprintf(stderr, ">> TLS connection establishd.\n"); | |
/* Run a few request/responses */ | |
int i; | |
for (i = 0; i < 10; i++) { | |
start_request(ssl); | |
complete_request(ssl); | |
} | |
/* Start another request */ | |
start_request(ssl); | |
/* Now request renegotiation; | |
* | |
* NOTE -- on TLS 1.3 this will fail and should use SSL_key_update() | |
* instead. | |
*/ | |
ret = SSL_renegotiate(ssl); | |
assert(ret == 1); | |
/* Now try to complete the request */ | |
complete_request(ssl); | |
fprintf(stderr, "All done.\n"); | |
SSL_free(ssl); | |
close(sock); | |
SSL_CTX_free(ctx); | |
return(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment