// SPDX-License-Identifier: Apache-2.0 AND MIT #include #include #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; }