-all: randbytes
+all: randbytes handshake
clean:
- rm libperf.a *.o randbytes
+ rm libperf.a *.o randbytes handshake
libperf.a: perflib/*.c perflib/*.h
gcc -I$(TARGET_OSSL_INCLUDE_PATH) -I. -c perflib/*.c
randbytes: randbytes.c libperf.a
gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o randbytes randbytes.c -lperf -lcrypto
+
+handshake: handshake.c libperf.a
+ gcc -L$(TARGET_OSSL_LIBRARY_PATH) -L. -I$(TARGET_OSSL_INCLUDE_PATH) -I. -o handshake handshake.c -lperf -lcrypto -lssl
--- /dev/null
+/*
+ * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <openssl/ssl.h>
+#include "perflib/perflib.h"
+
+#define NUM_HANDSHAKES_PER_THREAD 1000
+
+int err = 0;
+
+static SSL_CTX *sctx = NULL, *cctx = NULL;
+
+OSSL_TIME *times;
+
+static void do_handshake(size_t num)
+{
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int ret = 1;
+ int i;
+ OSSL_TIME start, end;
+
+ start = ossl_time_now();
+
+ for (i = 0; i < NUM_HANDSHAKES_PER_THREAD; i++) {
+ ret = perflib_create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL);
+ ret &= perflib_create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE);
+ perflib_shutdown_ssl_connection(serverssl, clientssl);
+ serverssl = clientssl = NULL;
+ }
+
+ end = ossl_time_now();
+ times[num] = ossl_time_subtract(end, start);
+
+ if (!ret)
+ err = 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int threadcount;
+ double persec;
+ OSSL_TIME duration, av;
+ uint64_t us;
+ double avcalltime;
+ char *cert;
+ char *privkey;
+ int ret = EXIT_FAILURE;
+ int i;
+
+ if (argc != 3) {
+ printf("Usage: handshake certsdir threadcount\n");
+ return EXIT_FAILURE;
+ }
+
+ threadcount = atoi(argv[2]);
+ if (threadcount < 1) {
+ printf("threadcount must be > 0\n");
+ return EXIT_FAILURE;
+ }
+
+ cert = perflib_mk_file_path(argv[1], "servercert.pem");
+ privkey = perflib_mk_file_path(argv[1], "serverkey.pem");
+ if (cert == NULL || privkey == NULL) {
+ printf("Failed to allocate cert/privkey\n");
+ goto err;
+ }
+
+ times = OPENSSL_malloc(sizeof(OSSL_TIME) * threadcount);
+ if (times == NULL) {
+ printf("Failed to create times array\n");
+ goto err;
+ }
+
+ if (!perflib_create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
+ 0, 0, &sctx, &cctx, cert, privkey)) {
+ printf("Failed to create SSL_CTX pair\n");
+ goto err;
+ }
+
+ if (!perflib_run_multi_thread_test(do_handshake, threadcount, &duration)) {
+ printf("Failed to run the test\n");
+ goto err;
+ }
+
+ if (err) {
+ printf("Error during test\n");
+ goto err;
+ }
+
+ av = times[0];
+ for (i = 1; i < threadcount; i++)
+ av = ossl_time_add(av, times[i]);
+ av = ossl_time_divide(av, NUM_HANDSHAKES_PER_THREAD * threadcount);
+
+ persec = ((NUM_HANDSHAKES_PER_THREAD * threadcount * OSSL_TIME_SECOND)
+ / (double)ossl_time2ticks(duration));
+
+ printf("Average time per handshake: %ldus\n", ossl_time2us(av));
+ printf("Handshakes per second: %lf\n", persec);
+
+ ret = EXIT_SUCCESS;
+ err:
+ OPENSSL_free(cert);
+ OPENSSL_free(privkey);
+ OPENSSL_free(times);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return ret;
+}
* https://www.openssl.org/source/license.html
*/
+#include <string.h>
#include <openssl/crypto.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
#include "perflib/perflib.h"
-int perflib_run_multi_thread_test(void (*f)(void), size_t threadcount,
- OSSL_TIME *duration)
+char *perflib_mk_file_path(const char *dir, const char *file)
{
- OSSL_TIME start, end;
- thread_t *threads;
- size_t i;
-
- threads = OPENSSL_malloc(sizeof(*threads) * threadcount);
- if (threads == NULL)
- return 0;
-
- start = ossl_time_now();
-
- for (i = 0; i < threadcount; i++)
- perflib_run_thread(&threads[i], f);
-
- for (i = 0; i < threadcount; i++)
- perflib_wait_for_thread(threads[i]);
-
- end = ossl_time_now();
- OPENSSL_free(threads);
-
- *duration = ossl_time_subtract(end, start);
-
- return 1;
+ const char *sep = "/";
+ size_t dirlen = dir != NULL ? strlen(dir) : 0;
+ size_t len = dirlen + strlen(sep) + strlen(file) + 1;
+ char *full_file = OPENSSL_zalloc(len);
+
+ if (full_file != NULL) {
+ if (dir != NULL && dirlen > 0) {
+ OPENSSL_strlcpy(full_file, dir, len);
+ OPENSSL_strlcat(full_file, sep, len);
+ }
+ OPENSSL_strlcat(full_file, file, len);
+ }
+
+ return full_file;
}
# pragma once
#include <stdlib.h>
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
#include "perflib/time.h"
# if defined(_WIN32)
# endif
-int perflib_run_thread(thread_t *t, void (*f)(void));
-int perflib_wait_for_thread(thread_t thread);
-int perflib_run_multi_thread_test(void (*f)(void), size_t threadcount,
+int perflib_run_multi_thread_test(void (*f)(size_t), size_t threadcount,
OSSL_TIME *duration);
+char *perflib_mk_file_path(const char *dir, const char *file);
+
+int perflib_create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
+ int min_proto_version, int max_proto_version,
+ SSL_CTX **sctx, SSL_CTX **cctx, char *certfile,
+ char *privkeyfile);
+int perflib_create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx,
+ SSL **sssl, SSL **cssl, BIO *s_to_c_fbio,
+ BIO *c_to_s_fbio);
+int perflib_create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
+int perflib_create_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
+void perflib_shutdown_ssl_connection(SSL *serverssl, SSL *clientssl);
#endif
--- /dev/null
+/*
+ * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/crypto.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include "perflib/perflib.h"
+
+int perflib_create_ssl_ctx_pair(const SSL_METHOD *sm,
+ const SSL_METHOD *cm, int min_proto_version,
+ int max_proto_version, SSL_CTX **sctx,
+ SSL_CTX **cctx, char *certfile,
+ char *privkeyfile)
+{
+ SSL_CTX *serverctx = NULL;
+ SSL_CTX *clientctx = NULL;
+
+ if (sctx != NULL) {
+ if (*sctx != NULL)
+ serverctx = *sctx;
+ else if ((serverctx = SSL_CTX_new(sm)) == NULL)
+ goto err;
+ }
+
+ if (cctx != NULL) {
+ if (*cctx != NULL)
+ clientctx = *cctx;
+ else if ((clientctx = SSL_CTX_new(cm)) == NULL)
+ goto err;
+ }
+
+ if (serverctx != NULL
+ && ((min_proto_version > 0
+ && !SSL_CTX_set_min_proto_version(serverctx,
+ min_proto_version))
+ || (max_proto_version > 0
+ && !SSL_CTX_set_max_proto_version(serverctx,
+ max_proto_version))))
+ goto err;
+
+ if (clientctx != NULL
+ && ((min_proto_version > 0
+ && !SSL_CTX_set_min_proto_version(clientctx,
+ min_proto_version))
+ || (max_proto_version > 0
+ && !SSL_CTX_set_max_proto_version(clientctx,
+ max_proto_version))))
+ goto err;
+
+ if (serverctx != NULL && certfile != NULL && privkeyfile != NULL) {
+ if (SSL_CTX_use_certificate_file(serverctx, certfile,
+ SSL_FILETYPE_PEM) != 1
+ || SSL_CTX_use_PrivateKey_file(serverctx, privkeyfile,
+ SSL_FILETYPE_PEM) != 1
+ || SSL_CTX_check_private_key(serverctx) != 1)
+ goto err;
+ }
+
+ if (sctx != NULL)
+ *sctx = serverctx;
+ if (cctx != NULL)
+ *cctx = clientctx;
+ return 1;
+
+ err:
+ if (sctx != NULL && *sctx == NULL)
+ SSL_CTX_free(serverctx);
+ if (cctx != NULL && *cctx == NULL)
+ SSL_CTX_free(clientctx);
+ return 0;
+}
+
+/*
+ * NOTE: Transfers control of the BIOs - this function will free them on error.
+ * There is no DTLS support at this stage.
+ */
+int perflib_create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx,
+ SSL **sssl, SSL **cssl, BIO *s_to_c_fbio,
+ BIO *c_to_s_fbio)
+{
+ SSL *serverssl = NULL, *clientssl = NULL;
+ BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL;
+
+ if (*sssl != NULL)
+ serverssl = *sssl;
+ else if ((serverssl = SSL_new(serverctx)) == NULL)
+ goto error;
+ if (*cssl != NULL)
+ clientssl = *cssl;
+ else if ((clientssl = SSL_new(clientctx)) == NULL)
+ goto error;
+
+ if ((s_to_c_bio = BIO_new(BIO_s_mem())) == NULL
+ || (c_to_s_bio = BIO_new(BIO_s_mem())) == NULL)
+ goto error;
+
+ if (s_to_c_fbio != NULL
+ && (s_to_c_bio = BIO_push(s_to_c_fbio, s_to_c_bio)) == NULL)
+ goto error;
+ if (c_to_s_fbio != NULL
+ && (c_to_s_bio = BIO_push(c_to_s_fbio, c_to_s_bio)) == NULL)
+ goto error;
+
+ /* 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;
+
+ error:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ BIO_free(s_to_c_bio);
+ BIO_free(c_to_s_bio);
+ BIO_free(s_to_c_fbio);
+ BIO_free(c_to_s_fbio);
+
+ return 0;
+}
+
+#define MAXLOOPS 1000000
+
+/*
+ * 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 perflib_create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
+{
+ int retc = -1, rets = -1, err, abortctr = 0, ret = 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) {
+ printf("SSL_connect() failed %d, %d", retc, err);
+ if (want != SSL_ERROR_SSL)
+ ERR_print_errors_fp(stdout);
+ clienterr = 1;
+ }
+ if (want != SSL_ERROR_NONE && err == want)
+ goto err;
+
+ 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) {
+ printf("SSL_accept() failed %d, %d", rets, err);
+ if (want != SSL_ERROR_SSL)
+ ERR_print_errors_fp(stdout);
+ servererr = 1;
+ }
+ if (want != SSL_ERROR_NONE && err == want)
+ goto err;
+ if (clienterr && servererr)
+ goto err;
+ if (++abortctr == MAXLOOPS) {
+ printf("No progress made");
+ goto err;
+ }
+ } while (retc <=0 || rets <= 0);
+
+ ret = 1;
+ err:
+ return ret;
+}
+
+/*
+ * Create an SSL connection including any post handshake NewSessionTicket
+ * messages.
+ */
+int perflib_create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
+{
+ int i;
+ unsigned char buf;
+ size_t readbytes;
+
+ if (!perflib_create_bare_ssl_connection(serverssl, clientssl, want))
+ 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) {
+ printf("Unexpected data reading ticket\n");
+ return 0;
+ }
+ } else if (SSL_get_error(clientssl, 0) != SSL_ERROR_WANT_READ) {
+ printf("Unexpected error reading ticket\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void perflib_shutdown_ssl_connection(SSL *serverssl, SSL *clientssl)
+{
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+}
#include "perflib/perflib.h"
+struct thread_arg_st {
+ void (*func)(size_t num);
+ size_t num;
+};
+
#if defined(_WIN32)
-static DWORD WINAPI thread_run(LPVOID arg)
+static DWORD WINAPI thread_run(LPVOID varg)
{
- void (*f)(void);
+ struct thread_arg_st *arg = varg;
- *(void **) (&f) = arg;
+ arg->func(arg->num);
- f();
return 0;
}
-int perflib_run_thread(thread_t *t, void (*f)(void))
+int perflib_run_thread(thread_t *t, struct thread_arg_st *arg)
{
- *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL);
+ *t = CreateThread(NULL, 0, thread_run, arg, 0, NULL);
return *t != NULL;
}
#else
-static void *thread_run(void *arg)
+static void *thread_run(void *varg)
{
- void (*f)(void);
+ struct thread_arg_st *arg = varg;
- *(void **) (&f) = arg;
+ arg->func(arg->num);
- f();
return NULL;
}
-int perflib_run_thread(thread_t *t, void (*f)(void))
+int perflib_run_thread(thread_t *t, struct thread_arg_st *arg)
{
- return pthread_create(t, NULL, thread_run, *(void **) &f) == 0;
+ return pthread_create(t, NULL, thread_run, arg) == 0;
}
int perflib_wait_for_thread(thread_t thread)
}
#endif
+
+int perflib_run_multi_thread_test(void (*f)(size_t), size_t threadcount,
+ OSSL_TIME *duration)
+{
+ OSSL_TIME start, end;
+ thread_t *threads;
+ size_t i;
+ struct thread_arg_st *args;
+
+ threads = OPENSSL_malloc(sizeof(*threads) * threadcount);
+ if (threads == NULL)
+ return 0;
+
+ args = OPENSSL_malloc(sizeof(*args) * threadcount);
+ if (args == NULL) {
+ OPENSSL_free(threads);
+ return 0;
+ }
+
+ start = ossl_time_now();
+
+ for (i = 0; i < threadcount; i++) {
+ args[i].func = f;
+ args[i].num = i;
+ perflib_run_thread(&threads[i], &args[i]);
+ }
+
+ for (i = 0; i < threadcount; i++)
+ perflib_wait_for_thread(threads[i]);
+
+ end = ossl_time_now();
+ OPENSSL_free(threads);
+ OPENSSL_free(args);
+
+ *duration = ossl_time_subtract(end, start);
+
+ return 1;
+}
int err = 0;
-void do_randbytes(void)
+void do_randbytes(size_t num)
{
int i;
unsigned char buf[32];