tlstest_helpers.c
// SPDX-License-Identifier: Apache-2.0 AND MIT
#include <openssl/ssl.h>
#include <openssl/err.h>
#define MAXLOOPS 1000000
int create_tls1_3_ctx_pair(OSSL_LIB_CTX *libctx, SSL_CTX **sctx, SSL_CTX **cctx,
char *certfile, char *privkeyfile) {
SSL_CTX *serverctx = NULL, *clientctx = NULL;
if (sctx == NULL || cctx == NULL)
goto err;
serverctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method());
clientctx = SSL_CTX_new_ex(libctx, NULL, TLS_client_method());
if (serverctx == NULL || clientctx == NULL)
goto err;
SSL_CTX_set_options(serverctx,SSL_OP_ALLOW_CLIENT_RENEGOTIATION);
SSL_CTX_set_min_proto_version(serverctx,TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(serverctx,TLS1_3_VERSION);
SSL_CTX_set_min_proto_version(clientctx,TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(clientctx,TLS1_3_VERSION);
if (!SSL_CTX_use_certificate_file(serverctx, certfile,
SSL_FILETYPE_PEM) )
goto err;
if (!SSL_CTX_use_PrivateKey_file(serverctx,privkeyfile,
SSL_FILETYPE_PEM))
goto err;
if (!SSL_CTX_check_private_key(serverctx))
goto err;
*sctx = serverctx;
*cctx = clientctx;
return 1;
err:
SSL_CTX_free(serverctx);
SSL_CTX_free(clientctx);
return 0;
}
int create_tls_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
SSL **cssl) {
SSL *serverssl = NULL, *clientssl = NULL;
BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL;
if(serverctx == NULL || clientctx == NULL)
goto err;
serverssl = SSL_new(serverctx);
clientssl = SSL_new(clientctx);
if (serverssl == NULL || clientssl == NULL)
goto err;
s_to_c_bio = BIO_new(BIO_s_mem());
c_to_s_bio = BIO_new(BIO_s_mem());
if (s_to_c_bio == NULL || c_to_s_bio == NULL)
goto err;
/* Set Non-blocking IO behaviour */
BIO_set_mem_eof_return(s_to_c_bio, -1);
BIO_set_mem_eof_return(c_to_s_bio, -1);
/* Up ref these as we are passing them to two SSL objects */
SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio);
BIO_up_ref(s_to_c_bio);
BIO_up_ref(c_to_s_bio);
SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio);
*sssl = serverssl;
*cssl = clientssl;
return 1;
err:
SSL_free(serverssl);
SSL_free(clientssl);
BIO_free(s_to_c_bio);
BIO_free(c_to_s_bio);
return 0;
}
/* Create an SSL connection, but does not read any post-handshake
* NewSessionTicket messages.
* We stop the connection attempt (and return a failure value) if either peer
* has SSL_get_error() return the value in the |want| parameter. The connection
* attempt could be restarted by a subsequent call to this function.
*/
int create_bare_tls_connection(SSL *serverssl, SSL *clientssl, int want,
int read)
{
int retc = -1, rets = -1, err, abortctr = 0;
int clienterr = 0, servererr = 0;
do {
err = SSL_ERROR_WANT_WRITE;
while (!clienterr && retc <= 0 && err == SSL_ERROR_WANT_WRITE) {
retc = SSL_connect(clientssl);
if (retc <= 0)
err = SSL_get_error(clientssl, retc);
}
if (!clienterr && retc <= 0 && err != SSL_ERROR_WANT_READ) {
fprintf(stderr, "SSL_connect() failed %d, %d", retc, err);
if (want != SSL_ERROR_SSL)
ERR_clear_error();
clienterr = 1;
}
if (want != SSL_ERROR_NONE && err == want)
return 0;
err = SSL_ERROR_WANT_WRITE;
while (!servererr && rets <= 0 && err == SSL_ERROR_WANT_WRITE) {
rets = SSL_accept(serverssl);
if (rets <= 0)
err = SSL_get_error(serverssl, rets);
}
if (!servererr && rets <= 0
&& err != SSL_ERROR_WANT_READ
&& err != SSL_ERROR_WANT_X509_LOOKUP) {
fprintf(stderr, "SSL_accept() failed %d, %d", rets, err);
if (want != SSL_ERROR_SSL)
ERR_clear_error();
servererr = 1;
}
if (want != SSL_ERROR_NONE && err == want)
return 0;
if (clienterr && servererr)
return 0;
if (++abortctr == MAXLOOPS) {
fprintf(stderr, "No progress made");
return 0;
}
} while (retc <=0 || rets <= 0);
return 1;
}
/*
* Create an SSL connection including any post handshake NewSessionTicket
* messages.
*/
int create_tls_connection(SSL *serverssl, SSL *clientssl, int want)
{
int i;
unsigned char buf;
size_t readbytes;
if (!create_bare_tls_connection(serverssl, clientssl, want, 1))
return 0;
/*
* We attempt to read some data on the client side which we expect to fail.
* This will ensure we have received the NewSessionTicket in TLSv1.3 where
* appropriate. We do this twice because there are 2 NewSessionTickets.
*/
for (i = 0; i < 2; i++) {
if (SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes) > 0) {
if (readbytes !=0)
return 0;
} else if (SSL_get_error(clientssl, 0) != SSL_ERROR_WANT_READ) {
return 0;
}
}
return 1;
}