diff --git a/.github/workflows/async-examples.yml b/.github/workflows/async-examples.yml new file mode 100644 index 00000000000..806f4bf7903 --- /dev/null +++ b/.github/workflows/async-examples.yml @@ -0,0 +1,52 @@ +name: Async Examples + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + async_examples: + if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + name: Checkout wolfSSL + + - name: Build async examples (no configure) + run: | + make -C examples/async clean + make -C examples/async + + - name: Run async examples (ECC + X25519) + run: | + set -euo pipefail + run_pair() { + local mode="$1" + ./examples/async/async_server --"$mode" > "/tmp/async_server_${mode}.log" 2>&1 & + local pid=$! + sleep 1 + ./examples/async/async_client --"$mode" 127.0.0.1 11111 > "/tmp/async_client_${mode}.log" 2>&1 + local rc=$? + kill "$pid" >/dev/null 2>&1 || true + wait "$pid" >/dev/null 2>&1 || true + return "$rc" + } + run_pair ecc + run_pair x25519 + + - name: Print async logs + if: ${{ failure() }} + run: | + for f in /tmp/async_server_*.log /tmp/async_client_*.log; do + if [ -f "$f" ]; then + echo "==> $f" + cat "$f" + fi + done diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 2c35f6da5d8..317672a6f7b 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -81,6 +81,7 @@ jobs: '--enable-all CPPFLAGS=-DWOLFSSL_NO_CLIENT_AUTH', '--enable-all CPPFLAGS=''-DNO_WOLFSSL_CLIENT -DWOLFSSL_NO_CLIENT_AUTH''', '--enable-all CPPFLAGS=''-DNO_WOLFSSL_SERVER -DWOLFSSL_NO_CLIENT_AUTH''', + '--enable-curve25519=nonblock --enable-ecc=nonblock --enable-sp=yes,nonblock CFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK"', ] name: make check if: github.repository_owner == 'wolfssl' @@ -127,6 +128,7 @@ jobs: 'examples/configs/user_settings_dtls13.h', 'examples/configs/user_settings_EBSnet.h', 'examples/configs/user_settings_eccnonblock.h', + 'examples/configs/user_settings_curve25519nonblock.h', 'examples/configs/user_settings_min_ecc.h', 'examples/configs/user_settings_openssl_compat.h', 'examples/configs/user_settings_pkcs7.h', diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 246ded2a456..2987485387e 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -597,6 +597,7 @@ WC_AES_GCM_DEC_AUTH_EARLY WC_ASN_HASH_SHA256 WC_ASN_RUNTIME_DATE_CHECK_CONTROL WC_ASYNC_ENABLE_ECC_KEYGEN +WC_ASYNC_ENABLE_X25519 WC_ASYNC_NO_3DES WC_ASYNC_NO_AES WC_ASYNC_NO_ARC4 diff --git a/configure.ac b/configure.ac index 0e987002833..761b75f8928 100644 --- a/configure.ac +++ b/configure.ac @@ -4816,11 +4816,18 @@ ENABLED_ED25519_SMALL=no # CURVE25519 AC_ARG_ENABLE([curve25519], - [AS_HELP_STRING([--enable-curve25519],[Enable Curve25519 (default: disabled)])], + [AS_HELP_STRING([--enable-curve25519],[Enable Curve25519 (default: disabled). Set to "nonblock" to enable non-blocking support for key gen and shared secret])], [ ENABLED_CURVE25519=$enableval ], [ ENABLED_CURVE25519=no ] ) +# Handle curve25519 nonblock option - enable asynccrypt and asynccrypt-sw early +if test "$ENABLED_CURVE25519" = "nonblock" +then + test -z "$enable_asynccrypt" && enable_asynccrypt=yes + test -z "$enable_asynccrypt_sw" && enable_asynccrypt_sw=yes +fi + if test "$ENABLED_CURVE25519" = "no" && test "$ENABLED_QUIC" = "yes" && test "$ENABLED_FIPS" = "no" then ENABLED_CURVE25519=yes @@ -10328,12 +10335,17 @@ fi if test "$ENABLED_CURVE25519" != "no" then - if test "$ENABLED_CURVE25519" = "small" || test "$ENABLED_LOWRESOURCE" = "yes" + if test "$ENABLED_CURVE25519" = "small" || test "$ENABLED_CURVE25519" = "nonblock" || test "$ENABLED_LOWRESOURCE" = "yes" then AM_CFLAGS="$AM_CFLAGS -DCURVE25519_SMALL" ENABLED_CURVE25519_SMALL=yes fi + if test "$ENABLED_CURVE25519" = "nonblock" + then + AM_CFLAGS="$AM_CFLAGS -DWC_X25519_NONBLOCK" + fi + if test "$ENABLED_CURVE25519" = "no128bit" || test "$ENABLED_32BIT" = "yes" then AM_CFLAGS="$AM_CFLAGS -DNO_CURVED25519_128BIT" diff --git a/examples/async/Makefile b/examples/async/Makefile new file mode 100644 index 00000000000..97bf9500af3 --- /dev/null +++ b/examples/async/Makefile @@ -0,0 +1,45 @@ +CC ?= gcc +AR ?= ar +RM ?= rm -f + +WOLFSSL_TOP ?= $(abspath ../..) +OBJDIR ?= build + +CFLAGS ?= -O0 -g +CFLAGS += -I. +CFLAGS += -I$(WOLFSSL_TOP) +CFLAGS += -I$(WOLFSSL_TOP)/wolfssl +CFLAGS += -I$(WOLFSSL_TOP)/wolfssl/wolfcrypt +CFLAGS += -DWOLFSSL_USER_SETTINGS +CFLAGS += -DUSE_CERT_BUFFERS_256 + +LDFLAGS ?= +LDLIBS ?= + +TARGETS = async_client async_server + +WOLFSSL_SRC := $(wildcard $(WOLFSSL_TOP)/src/*.c) +WOLFCRYPT_SRC := $(wildcard $(WOLFSSL_TOP)/wolfcrypt/src/*.c) +LOCAL_SRC := async_client.c async_server.c + +WOLFSSL_OBJS := $(patsubst $(WOLFSSL_TOP)/%, $(OBJDIR)/%, $(WOLFSSL_SRC:.c=.o)) +WOLFCRYPT_OBJS := $(patsubst $(WOLFSSL_TOP)/%, $(OBJDIR)/%, $(WOLFCRYPT_SRC:.c=.o)) +LOCAL_OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(LOCAL_SRC)) + +OBJS := $(LOCAL_OBJS) $(WOLFSSL_OBJS) $(WOLFCRYPT_OBJS) + +all: $(TARGETS) + +$(TARGETS): %: $(OBJDIR)/%.o $(WOLFSSL_OBJS) $(WOLFCRYPT_OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +$(OBJDIR)/%.o: %.c user_settings.h + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/%.o: $(WOLFSSL_TOP)/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) -r $(OBJDIR) $(TARGETS) diff --git a/examples/async/README.md b/examples/async/README.md index 45229b6abd1..470e4c276ee 100644 --- a/examples/async/README.md +++ b/examples/async/README.md @@ -15,9 +15,10 @@ Tested with: * `./configure --enable-asynccrypt --enable-pkcallbacks --disable-rsa --enable-ecc` ``` -make -./examples/async/async_server -./examples/async/async_client 127.0.0.1 +make -C examples/async +./examples/async/async_server --ecc +./examples/async/async_client --ecc 127.0.0.1 11111 +./examples/async/async_client --x25519 ecc256.badssl.com 443 ``` ## Asynchronous Cryptography Design diff --git a/examples/async/async_client.c b/examples/async/async_client.c index f65066f37a3..146272bfda3 100644 --- a/examples/async/async_client.c +++ b/examples/async/async_client.c @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* TLS client demonstrating asynchronous cryptography features and optionally - * using the crypto or PK callbacks */ +/* TLS client demonstrating asynchronous cryptography features and non-blocking + * operation using WOLFSSL_USER_IO callbacks. */ #ifdef HAVE_CONFIG_H #include @@ -30,209 +30,422 @@ #include #include #include +#include /* socket */ +#include +#include #include -#include -#include +#include +#include #include /* wolfSSL */ -#ifndef WOLFSSL_USER_SETTINGS +#ifdef WOLFSSL_USER_SETTINGS + #include "user_settings.h" +#else #include #endif +#include #include #include #include #include "examples/async/async_tls.h" -/* Test certificates and keys for RSA and ECC */ -#ifndef NO_RSA - #define CERT_FILE "./certs/client-cert.pem" - #define KEY_FILE "./certs/client-key.pem" - #define CA_FILE "./certs/ca-cert.pem" -#elif defined(HAVE_ECC) - #define CERT_FILE "./certs/client-ecc-cert.pem" - #define KEY_FILE "./certs/ecc-client-key.pem" - #define CA_FILE "./certs/ca-ecc-cert.pem" -#else - #error No authentication algorithm (ECC/RSA) -#endif - -int client_async_test(int argc, char** argv) +/* ------------------------------------------------------------------ */ +/* POSIX transport helpers (replace with your BSP/port layer). */ +/* ------------------------------------------------------------------ */ +static int posix_set_nonblocking(int fd) { - int ret = 0; - int sockfd = SOCKET_INVALID; - struct sockaddr_in servAddr; - char buff[TEST_BUF_SZ]; - size_t len; - int devId = 1; /* anything besides -2 (INVALID_DEVID) */ -#ifdef WOLF_CRYPTO_CB - AsyncTlsCryptoCbCtx myCtx; -#endif - int err; - char errBuff[WOLFSSL_MAX_ERROR_SZ]; - - /* declare wolfSSL objects */ - WOLFSSL_CTX* ctx = NULL; - WOLFSSL* ssl = NULL; + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + return -1; + } + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} - /* Check for proper calling convention */ - if (argc != 2) { - printf("usage: %s \n", argv[0]); +static int posix_connect_nonblock(int fd, const struct sockaddr* sa, + socklen_t sa_len, int timeout_ms) +{ + int ret = connect(fd, sa, sa_len); + if (ret == 0) { return 0; } - - /* Create a socket that uses an internet IPv4 address, - * Sets the socket to be stream based (TCP), - * 0 means choose the default protocol. */ - if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - fprintf(stderr, "ERROR: failed to create the socket\n"); - ret = -1; goto exit; + if (ret < 0 && errno != EINPROGRESS) { + return -1; } - /* Initialize the server address struct with zeros */ - memset(&servAddr, 0, sizeof(servAddr)); + /* Wait for connect to finish. */ + fd_set wfds; + struct timeval tv; + FD_ZERO(&wfds); + FD_SET(fd, &wfds); + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + + ret = select(fd + 1, NULL, &wfds, NULL, &tv); + if (ret <= 0) { + return -1; + } + if (FD_ISSET(fd, &wfds)) { + int so_err = 0; + socklen_t len = sizeof(so_err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_err, &len) < 0) { + return -1; + } + if (so_err != 0) { + errno = so_err; + return -1; + } + return 0; + } + return -1; +} - /* Fill in the server address */ - servAddr.sin_family = AF_INET; /* using IPv4 */ - servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ +static int posix_net_connect(const char* host, int port) +{ + char port_str[8]; + struct addrinfo hints; + struct addrinfo* res = NULL; + struct addrinfo* it = NULL; + int fd = -1; + int ret; + + snprintf(port_str, sizeof(port_str), "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(host, port_str, &hints, &res) != 0) { + return -1; + } - /* Get the server IPv4 address from the command line call */ - if (inet_pton(AF_INET, argv[1], &servAddr.sin_addr) != 1) { - fprintf(stderr, "ERROR: invalid address\n"); - ret = -1; goto exit; + for (it = res; it != NULL; it = it->ai_next) { + fd = socket(it->ai_family, it->ai_socktype, it->ai_protocol); + if (fd < 0) { + continue; + } + if (posix_set_nonblocking(fd) != 0) { + close(fd); + fd = -1; + continue; + } + ret = posix_connect_nonblock(fd, it->ai_addr, + (socklen_t)it->ai_addrlen, 5000); + if (ret == 0) { + break; + } + close(fd); + fd = -1; } - /* Connect to the server */ - if ((ret = connect(sockfd, (struct sockaddr*) &servAddr, sizeof(servAddr))) - == -1) { - fprintf(stderr, "ERROR: failed to connect\n"); - goto exit; + if (res != NULL) { + freeaddrinfo(res); } + return fd; +} - /*---------------------------------*/ - /* Start of wolfSSL initialization and configuration */ - /*---------------------------------*/ -#ifdef DEBUG_WOLFSSL - wolfSSL_Debugging_ON(); -#endif +/* ------------------------------------------------------------------ */ +/* WOLFSSL_USER_IO callbacks. */ +/* ------------------------------------------------------------------ */ +static int posix_send_cb(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + int fd = (int)(intptr_t)ctx; + int ret = (int)send(fd, buf, (size_t)sz, 0); + if (ret >= 0) { + return ret; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + return WOLFSSL_CBIO_ERR_GENERAL; +} - /* Initialize wolfSSL */ - if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: Failed to initialize the library\n"); - goto exit; +static int posix_recv_cb(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + int fd = (int)(intptr_t)ctx; + int ret = (int)recv(fd, buf, (size_t)sz, 0); + if (ret >= 0) { + return ret; } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + return WOLFSSL_CBIO_ERR_GENERAL; +} - /* Create and initialize WOLFSSL_CTX */ - if ((ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())) == NULL) { - fprintf(stderr, "ERROR: failed to create WOLFSSL_CTX\n"); - ret = -1; goto exit; +int posix_getdevrandom(unsigned char *out, unsigned int sz); +int posix_getdevrandom(unsigned char *out, unsigned int sz) +{ + ssize_t ret; + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + return -1; + } + ret = read(fd, out, sz); + close(fd); + if (ret != (ssize_t)sz) { + return -1; } + return 0; +} -#ifdef WOLF_CRYPTO_CB - XMEMSET(&myCtx, 0, sizeof(myCtx)); - /* register a devID for crypto callbacks */ - ret = wc_CryptoCb_RegisterDevice(devId, AsyncTlsCryptoCb, &myCtx); - if (ret != 0) { - fprintf(stderr, "wc_CryptoCb_RegisterDevice: error %d", ret); - goto exit; +static void usage(const char* prog) +{ + printf("usage: %s [--ecc|--x25519] [host] [port]\n", prog); +} + +static int parse_client_args(int argc, char** argv, + const char** host, int* port, word16* group) +{ + int i; + int host_set = 0; + int port_set = 0; + + *host = DEFAULT_TLS_HOST; + *port = DEFAULT_TLS_PORT; + *group = WOLFSSL_ECC_SECP256R1; + + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "--ecc") == 0) { + *group = WOLFSSL_ECC_SECP256R1; + } + else if (XSTRCMP(argv[i], "--x25519") == 0) { + *group = WOLFSSL_ECC_X25519; + } + else if (XSTRCMP(argv[i], "--help") == 0) { + return -1; + } + else if (!host_set) { + *host = argv[i]; + host_set = 1; + } + else if (!port_set) { + *port = atoi(argv[i]); + port_set = 1; + } + else { + return -1; + } } + + return 0; +} + +int client_async_test(int argc, char** argv) +{ + int ret = -1; + int net = -1; + WOLFSSL_CTX* ctx = NULL; + WOLFSSL* ssl = NULL; + char rx[128]; + char tx[256]; + int tx_len = 0; + int err = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + int devId = INVALID_DEVID; #endif - /* register a devID for crypto callbacks */ - wolfSSL_CTX_SetDevId(ctx, devId); +#ifdef WOLFSSL_DEBUG_NONBLOCK + int wouldblock_count = 0; + int pending_count = 0; +#endif + const char* host = NULL; + int port = 0; + word16 group = WOLFSSL_ECC_SECP256R1; - /* Load client certificate into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, WOLFSSL_FILETYPE_PEM)) - != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - CERT_FILE); - goto exit; + if (parse_client_args(argc, argv, &host, &port, &group) != 0) { + usage(argv[0]); + return 0; } - /* Load client key into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, WOLFSSL_FILETYPE_PEM)) - != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - KEY_FILE); - goto exit; + net = posix_net_connect(host, port); + if (net < 0) { + return -1; } - /* Load CA certificate into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_FILE, NULL)) - != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - CA_FILE); - goto exit; + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + return -1; + } +#ifdef DEBUG_WOLFSSL + wolfSSL_Debugging_ON(); +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfAsync_DevOpenThread(&devId, NULL) != 0) { + goto out; } +#endif - /* Create a WOLFSSL object */ - if ((ssl = wolfSSL_new(ctx)) == NULL) { - fprintf(stderr, "ERROR: failed to create WOLFSSL object\n"); - ret = -1; goto exit; + ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + if (ctx == NULL) { + goto out; } +#ifdef WOLFSSL_ASYNC_CRYPT + wolfSSL_CTX_SetDevId(ctx, devId); +#endif - /* Attach wolfSSL to the socket */ - if ((ret = wolfSSL_set_fd(ssl, sockfd)) != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: Failed to set the file descriptor\n"); - goto exit; + /* Bare-metal style: disable verification unless you load CA/peer certs. */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); + + wolfSSL_SetIORecv(ctx, posix_recv_cb); + wolfSSL_SetIOSend(ctx, posix_send_cb); + + wolfSSL_CTX_UseSNI(ctx, WOLFSSL_SNI_HOST_NAME, host, strlen(host)); + + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + goto out; } - /* Connect to wolfSSL on the server side */ - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_connect(ssl), - ret != WOLFSSL_SUCCESS); - if (ret != WOLFSSL_SUCCESS) { - fprintf(stderr, "wolfSSL_connect error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); - goto exit; + wolfSSL_SetIOReadCtx(ssl, (void*)(intptr_t)net); + wolfSSL_SetIOWriteCtx(ssl, (void*)(intptr_t)net); + (void)wolfSSL_UseSNI(ssl, WOLFSSL_SNI_HOST_NAME, host, (word16)XSTRLEN(host)); + + for (;;) { + ret = wolfSSL_UseKeyShare(ssl, group); + if (ret == WOLFSSL_SUCCESS) { + break; + } + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto out; + } +#endif + continue; + } + goto out; } - /* Get a message for the server from stdin */ - printf("Message for server: "); - memset(buff, 0, sizeof(buff)); - if (fgets(buff, sizeof(buff), stdin) == NULL) { - fprintf(stderr, "ERROR: failed to get message for server\n"); - ret = -1; goto exit; + /* Non-blocking style loop. */ + for (;;) { + ret = wolfSSL_connect(ssl); + if (ret == WOLFSSL_SUCCESS) { + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto out; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } + goto out; } - len = strnlen(buff, sizeof(buff)); - /* Send the message to the server */ - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_write(ssl, buff, (int)len), - ret <= 0); - if (ret != (int)len) { - fprintf(stderr, "wolfSSL_write error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); - goto exit; + tx_len = XSNPRINTF(tx, sizeof(tx), + "GET / HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: wolfSSL-async\r\n" + "Connection: close\r\n" + "\r\n", + host); + if (tx_len <= 0 || tx_len >= (int)sizeof(tx)) { + goto out; } - /* Read the server data into our buff array */ - memset(buff, 0, sizeof(buff)); - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_read(ssl, buff, sizeof(buff)-1), - ret <= 0); - if (ret < 0) { - fprintf(stderr, "wolfSSL_read error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); - goto exit; + for (;;) { + ret = wolfSSL_write(ssl, tx, tx_len); + if (ret > 0) { + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto out; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } + goto out; } - /* Print to stdout any data the server sends */ - printf("Server: %s\n", buff); + XMEMSET(rx, 0, sizeof(rx)); + for (;;) { + ret = wolfSSL_read(ssl, rx, (int)sizeof(rx) - 1); + if (ret > 0) { + rx[ret] = '\0'; + printf("RX: %s\n", rx); + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto out; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } + goto out; + } - /* Return reporting a success */ +#ifdef WOLFSSL_DEBUG_NONBLOCK + printf("WANT_READ/WRITE count: %d\n", wouldblock_count); + printf("WC_PENDING_E count: %d\n", pending_count); +#endif ret = 0; -exit: - /* Cleanup and return */ - if (sockfd != SOCKET_INVALID) - close(sockfd); /* Close the connection to the server */ - if (ssl) - wolfSSL_free(ssl); /* Free the wolfSSL object */ - if (ctx) - wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ - wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ - - (void)argc; - (void)argv; +out: + if (ssl != NULL) { + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + } + if (ctx != NULL) { + wolfSSL_CTX_free(ctx); + } +#ifdef WOLFSSL_ASYNC_CRYPT + if (devId != INVALID_DEVID) { + wolfAsync_DevClose(&devId); + } +#endif + wolfSSL_Cleanup(); + if (net >= 0) { + close(net); + } return ret; } diff --git a/examples/async/async_server.c b/examples/async/async_server.c index 9292938056e..9c285782dd0 100644 --- a/examples/async/async_server.c +++ b/examples/async/async_server.c @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* TLS server demonstrating asynchronous cryptography features and optionally - * using the crypto or PK callbacks */ +/* TLS server demonstrating asynchronous cryptography features and non-blocking + * operation using WOLFSSL_USER_IO callbacks. */ #ifdef HAVE_CONFIG_H #include @@ -30,11 +30,14 @@ #include #include #include +#include /* socket */ +#include #include #include #include +#include #include #define HAVE_SIGNAL @@ -43,25 +46,26 @@ #endif /* wolfSSL */ -#ifndef WOLFSSL_USER_SETTINGS +#ifdef WOLFSSL_USER_SETTINGS + #include "user_settings.h" +#else #include #endif +#include #include #include #include +#include #include "examples/async/async_tls.h" -/* Test certificates and keys for RSA and ECC */ -#ifndef NO_RSA - #define CERT_FILE "./certs/server-cert.pem" - #define KEY_FILE "./certs/server-key.pem" - #define CA_FILE "./certs/client-cert.pem" -#elif defined(HAVE_ECC) - #define CERT_FILE "./certs/server-ecc.pem" - #define KEY_FILE "./certs/ecc-key.pem" - #define CA_FILE "./certs/client-ecc-cert.pem" +#if ASYNC_ECC_ONLY + #ifndef HAVE_ECC + #error ASYNC_ECC_ONLY requires HAVE_ECC + #endif #else - #error No authentication algorithm (ECC/RSA) + #ifndef NO_RSA + #error RSA not supported in this example configuration + #endif #endif static int mSockfd = SOCKET_INVALID; @@ -79,19 +83,113 @@ static void sig_handler(const int sig) mShutdown = 1; if (mConnd != SOCKET_INVALID) { - close(mConnd); /* Close the connection to the client */ + close(mConnd); mConnd = SOCKET_INVALID; } if (mSockfd != SOCKET_INVALID) { - close(mSockfd); /* Close the socket listening for clients */ + close(mSockfd); mSockfd = SOCKET_INVALID; } } #endif +/* ------------------------------------------------------------------ */ +/* POSIX transport helpers (replace with your BSP/port layer). */ +/* ------------------------------------------------------------------ */ +static int posix_set_nonblocking(int fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + return -1; + } + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +/* ------------------------------------------------------------------ */ +/* WOLFSSL_USER_IO callbacks. */ +/* ------------------------------------------------------------------ */ +static int posix_send_cb(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + int fd = (int)(intptr_t)ctx; + int ret = (int)send(fd, buf, (size_t)sz, 0); + if (ret >= 0) { + return ret; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return WOLFSSL_CBIO_ERR_WANT_WRITE; + } + return WOLFSSL_CBIO_ERR_GENERAL; +} + +static int posix_recv_cb(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + int fd = (int)(intptr_t)ctx; + int ret = (int)recv(fd, buf, (size_t)sz, 0); + if (ret >= 0) { + return ret; + } + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return WOLFSSL_CBIO_ERR_WANT_READ; + } + return WOLFSSL_CBIO_ERR_GENERAL; +} + +int posix_getdevrandom(unsigned char *out, unsigned int sz); +int posix_getdevrandom(unsigned char *out, unsigned int sz) +{ + ssize_t ret; + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + return -1; + } + ret = read(fd, out, sz); + close(fd); + if (ret != (ssize_t)sz) { + return -1; + } + return 0; +} + +static void usage(const char* prog) +{ + printf("usage: %s [--ecc|--x25519] [port]\n", prog); +} + +static int parse_server_args(int argc, char** argv, int* port, word16* group) +{ + int i; + int port_set = 0; + + *port = DEFAULT_PORT; + *group = WOLFSSL_ECC_SECP256R1; + + for (i = 1; i < argc; i++) { + if (XSTRCMP(argv[i], "--ecc") == 0) { + *group = WOLFSSL_ECC_SECP256R1; + } + else if (XSTRCMP(argv[i], "--x25519") == 0) { + *group = WOLFSSL_ECC_X25519; + } + else if (XSTRCMP(argv[i], "--help") == 0) { + return -1; + } + else if (!port_set) { + *port = atoi(argv[i]); + port_set = 1; + } + else { + return -1; + } + } + + return 0; +} + int server_async_test(int argc, char** argv) { - int ret = 0; + int ret = -1; struct sockaddr_in servAddr; struct sockaddr_in clientAddr; socklen_t size = sizeof(clientAddr); @@ -99,12 +197,16 @@ int server_async_test(int argc, char** argv) size_t len; const char* reply = "I hear ya fa shizzle!\n"; int on; - int devId = 1; /* anything besides -2 (INVALID_DEVID) */ -#ifdef WOLF_CRYPTO_CB - AsyncTlsCryptoCbCtx myCtx; + int port = DEFAULT_PORT; + word16 group = WOLFSSL_ECC_SECP256R1; + int err = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + int devId = INVALID_DEVID; +#endif +#ifdef WOLFSSL_DEBUG_NONBLOCK + int wouldblock_count = 0; + int pending_count = 0; #endif - int err; - char errBuff[WOLFSSL_MAX_ERROR_SZ]; /* declare wolfSSL objects */ WOLFSSL_CTX* ctx = NULL; @@ -117,14 +219,18 @@ int server_async_test(int argc, char** argv) } #endif + if (parse_server_args(argc, argv, &port, &group) != 0) { + usage(argv[0]); + return 0; + } + /* Initialize the server address struct with zeros */ memset(&servAddr, 0, sizeof(servAddr)); /* Fill in the server address */ - servAddr.sin_family = AF_INET; /* using IPv4 */ - servAddr.sin_port = htons(DEFAULT_PORT); /* on DEFAULT_PORT */ - servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */ - + servAddr.sin_family = AF_INET; /* using IPv4 */ + servAddr.sin_port = htons(port); + servAddr.sin_addr.s_addr = INADDR_ANY; /* from anywhere */ /* Create a socket that uses an internet IPv4 address, * Sets the socket to be stream based (TCP), @@ -169,10 +275,15 @@ int server_async_test(int argc, char** argv) #endif /* Initialize wolfSSL */ - if ((ret = wolfSSL_Init()) != WOLFSSL_SUCCESS) { + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { fprintf(stderr, "ERROR: Failed to initialize the library\n"); goto exit; } +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfAsync_DevOpenThread(&devId, NULL) != 0) { + goto exit; + } +#endif /* Create and initialize WOLFSSL_CTX */ if ((ctx = wolfSSL_CTX_new(wolfSSLv23_server_method())) == NULL) { @@ -180,45 +291,29 @@ int server_async_test(int argc, char** argv) ret = -1; goto exit; } - -#ifdef WOLF_CRYPTO_CB - XMEMSET(&myCtx, 0, sizeof(myCtx)); - /* register a devID for crypto callbacks */ - ret = wc_CryptoCb_RegisterDevice(devId, AsyncTlsCryptoCb, &myCtx); - if (ret != 0) { - fprintf(stderr, "wc_CryptoCb_RegisterDevice: error %d", ret); - goto exit; - } +#ifdef WOLFSSL_ASYNC_CRYPT + wolfSSL_CTX_SetDevId(ctx, devId); #endif - /* register a devID for crypto callbacks */ - wolfSSL_CTX_SetDevId(ctx, devId); + /* Bare-metal style: disable verification unless you load CA/peer certs. */ + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); - /* Require mutual authentication */ - wolfSSL_CTX_set_verify(ctx, - WOLFSSL_VERIFY_PEER | WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); + wolfSSL_SetIORecv(ctx, posix_recv_cb); + wolfSSL_SetIOSend(ctx, posix_send_cb); /* Load server certificates into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_use_certificate_file(ctx, CERT_FILE, - WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - CERT_FILE); + if ((ret = wolfSSL_CTX_use_certificate_buffer(ctx, serv_ecc_der_256, + sizeof_serv_ecc_der_256, + WOLFSSL_FILETYPE_ASN1)) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load ECC server cert buffer.\n"); goto exit; } /* Load server key into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, - WOLFSSL_FILETYPE_PEM)) != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - KEY_FILE); - goto exit; - } - - /* Load client certificate as "trusted" into WOLFSSL_CTX */ - if ((ret = wolfSSL_CTX_load_verify_locations(ctx, CA_FILE, NULL)) - != WOLFSSL_SUCCESS) { - fprintf(stderr, "ERROR: failed to load %s, please check the file.\n", - CA_FILE); + if ((ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, ecc_key_der_256, + sizeof_ecc_key_der_256, + WOLFSSL_FILETYPE_ASN1)) != WOLFSSL_SUCCESS) { + fprintf(stderr, "ERROR: failed to load ECC server key buffer.\n"); goto exit; } @@ -232,6 +327,10 @@ int server_async_test(int argc, char** argv) fprintf(stderr, "ERROR: failed to accept the connection\n\n"); ret = -1; goto exit; } + if (posix_set_nonblocking(mConnd) != 0) { + fprintf(stderr, "ERROR: failed to set non-blocking socket\n"); + ret = -1; goto exit; + } /* Create a WOLFSSL object */ if ((ssl = wolfSSL_new(ctx)) == NULL) { @@ -239,28 +338,88 @@ int server_async_test(int argc, char** argv) ret = -1; goto exit; } - /* Attach wolfSSL to the socket */ - wolfSSL_set_fd(ssl, mConnd); + wolfSSL_SetIOReadCtx(ssl, (void*)(intptr_t)mConnd); + wolfSSL_SetIOWriteCtx(ssl, (void*)(intptr_t)mConnd); + + for (;;) { + ret = wolfSSL_UseKeyShare(ssl, group); + if (ret == WOLFSSL_SUCCESS) { + break; + } + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto exit; + } +#endif + continue; + } + goto exit; + } /* Establish TLS connection */ - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_accept(ssl), - ret != WOLFSSL_SUCCESS); - if (ret != WOLFSSL_SUCCESS) { - fprintf(stderr, "wolfSSL_accept error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); + for (;;) { + ret = wolfSSL_accept(ssl); + if (ret == WOLFSSL_SUCCESS) { + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto exit; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } goto exit; } - printf("Client connected successfully\n"); /* Read the client data into our buff array */ memset(buff, 0, sizeof(buff)); - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_read(ssl, buff, sizeof(buff)-1), - ret <= 0); - if (ret < 0) { - fprintf(stderr, "wolfSSL_read error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); + for (;;) { + ret = wolfSSL_read(ssl, buff, sizeof(buff) - 1); + if (ret > 0) { + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto exit; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } goto exit; } @@ -279,46 +438,74 @@ int server_async_test(int argc, char** argv) len = strnlen(buff, sizeof(buff)); /* Reply back to the client */ - WOLFSSL_ASYNC_WHILE_PENDING(ret = wolfSSL_write(ssl, buff, (int)len), - ret <= 0); - if (ret != (int)len) { - fprintf(stderr, "wolfSSL_write error %d: %s\n", - err, wolfSSL_ERR_error_string(err, errBuff)); + for (;;) { + ret = wolfSSL_write(ssl, buff, (int)len); + if (ret > 0) { + break; + } + err = wolfSSL_get_error(ssl, 0); + if (err == WC_PENDING_E || + err == WOLFSSL_ERROR_WANT_READ || + err == WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_PENDING_E) { +#ifdef WOLFSSL_DEBUG_NONBLOCK + pending_count++; +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + if (wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW) < 0) { + goto exit; + } +#endif + } + else { +#ifdef WOLFSSL_DEBUG_NONBLOCK + wouldblock_count++; +#endif + } + continue; + } goto exit; } /* Cleanup after this connection */ wolfSSL_shutdown(ssl); if (ssl) { - wolfSSL_free(ssl); /* Free the wolfSSL object */ + wolfSSL_free(ssl); ssl = NULL; } if (mConnd != SOCKET_INVALID) { - close(mConnd); /* Close the connection to the client */ + close(mConnd); mConnd = SOCKET_INVALID; } } printf("Shutdown complete\n"); +#ifdef WOLFSSL_DEBUG_NONBLOCK + printf("WANT_READ/WRITE count: %d\n", wouldblock_count); + printf("WC_PENDING_E count: %d\n", pending_count); +#endif + ret = 0; exit: /* Cleanup and return */ if (ssl) - wolfSSL_free(ssl); /* Free the wolfSSL object */ + wolfSSL_free(ssl); if (mConnd != SOCKET_INVALID) { - close(mConnd); /* Close the connection to the client */ + close(mConnd); mConnd = SOCKET_INVALID; } if (mSockfd != SOCKET_INVALID) { - close(mSockfd); /* Close the socket listening for clients */ + close(mSockfd); mSockfd = SOCKET_INVALID; } if (ctx) - wolfSSL_CTX_free(ctx); /* Free the wolfSSL context object */ - wolfSSL_Cleanup(); /* Cleanup the wolfSSL environment */ - - (void)argc; - (void)argv; + wolfSSL_CTX_free(ctx); +#ifdef WOLFSSL_ASYNC_CRYPT + if (devId != INVALID_DEVID) { + wolfAsync_DevClose(&devId); + } +#endif + wolfSSL_Cleanup(); return ret; } diff --git a/examples/async/async_tls.h b/examples/async/async_tls.h index 1e90ee7bcdb..725beb34127 100644 --- a/examples/async/async_tls.h +++ b/examples/async/async_tls.h @@ -24,8 +24,19 @@ #define WOLFSSL_ASYNC_TLS_EXAMPLES_H #define DEFAULT_PORT 11111 +#define DEFAULT_TLS_PORT 11111 +#define DEFAULT_TLS_HOST "127.0.0.1" #define TEST_BUF_SZ 256 +/* Force ECC-only certs/keys for these async TLS examples. */ +#ifndef ASYNC_ECC_ONLY +#if defined(WC_ECC_NONBLOCK) +#define ASYNC_ECC_ONLY 1 +#else +#define ASYNC_ECC_ONLY 0 +#endif +#endif + #ifdef WOLF_CRYPTO_CB /* Example custom context for crypto callback */ typedef struct { diff --git a/examples/async/include.am b/examples/async/include.am index 5f189451cac..ecc0a3478aa 100644 --- a/examples/async/include.am +++ b/examples/async/include.am @@ -1,29 +1,10 @@ # vim:ft=automake # All paths should be given relative to the root -if BUILD_ASYNCCRYPT - -noinst_HEADERS += examples/async/async_tls.h - -if BUILD_EXAMPLE_CLIENTS -noinst_PROGRAMS += examples/async/async_client -examples_async_async_client_SOURCES = examples/async/async_client.c examples/async/async_tls.c -examples_async_async_client_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) -examples_async_async_client_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la -examples_async_async_client_CFLAGS = $(AM_CFLAGS) -endif - -if BUILD_EXAMPLE_SERVERS -noinst_PROGRAMS += examples/async/async_server -examples_async_async_server_SOURCES = examples/async/async_server.c examples/async/async_tls.c -examples_async_async_server_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD) -examples_async_async_server_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la -examples_async_async_server_CFLAGS = $(AM_CFLAGS) -endif -endif - -dist_example_DATA+= examples/async/async_server.c -dist_example_DATA+= examples/async/async_client.c -DISTCLEANFILES+= examples/async/.libs/async_server -DISTCLEANFILES+= examples/async/.libs/async_client -EXTRA_DIST += examples/async/README.md +EXTRA_DIST += examples/async/README.md \ + examples/async/async_client.c \ + examples/async/async_server.c \ + examples/async/async_tls.c \ + examples/async/async_tls.h \ + examples/async/Makefile \ + examples/async/user_settings.h diff --git a/examples/async/user_settings.h b/examples/async/user_settings.h new file mode 100644 index 00000000000..50bf38aa4b6 --- /dev/null +++ b/examples/async/user_settings.h @@ -0,0 +1,66 @@ +/* Bare-metal user settings for TLS 1.3 client with WOLFSSL_USER_IO. */ +#ifndef WOLFSSL_USER_SETTINGS_H +#define WOLFSSL_USER_SETTINGS_H + +#define WOLFSSL_USER_IO +#define SINGLE_THREADED +#define NO_FILESYSTEM +#define WOLFSSL_IGNORE_FILE_WARN + +#define HAVE_ECC +#define WC_ECC_NONBLOCK +#define WC_ECC_NONBLOCK_ONLY +#define ECC_USER_CURVES /* P256 only */ +#define WOLFSSL_HAVE_SP_ECC +#define WOLFSSL_SP_SMALL +#define WOLFSSL_SP_NONBLOCK +#define WOLFSSL_SP_NO_MALLOC +#define ECC_TIMING_RESISTANT + +#define HAVE_CURVE25519 +#define CURVE25519_SMALL +#define WC_X25519_NONBLOCK + +#define WOLFSSL_ASYNC_CRYPT +#define WOLFSSL_ASYNC_CRYPT_SW +#define WC_NO_ASYNC_THREADING +#define HAVE_WOLF_BIGINT + +#define NO_RSA + +#define HAVE_AESGCM + +#define WOLFSSL_TLS13 +#define WOLFSSL_NO_TLS12 +#define HAVE_HKDF +#define HAVE_TLS_EXTENSIONS +#define HAVE_SUPPORTED_CURVES +#define HAVE_SERVER_RENEGOTIATION_INFO +#define HAVE_ENCRYPT_THEN_MAC +#define HAVE_SNI + +#define HAVE_SESSION_TICKET + +extern int posix_getdevrandom(unsigned char *out, unsigned int sz); +#ifndef HAVE_HASHDRBG + #define CUSTOM_RAND_GENERATE_BLOCK posix_getdevrandom +#else + #define CUSTOM_RAND_GENERATE_SEED posix_getdevrandom +#endif + +/* Minimal feature set - explicitly disable unwanted algorithms. */ +#define NO_DH +#define NO_DSA +#define WOLFSSL_NO_SHAKE256 +#define WOLFSSL_NO_SHAKE128 +#define NO_MD4 +#define NO_MD5 +#define NO_DES3 +#define NO_SHA +#define NO_OLD_TLS + +/* Debugging helper. */ +//#define DEBUG_WOLFSSL +#define WOLFSSL_DEBUG_NONBLOCK + +#endif /* WOLFSSL_USER_SETTINGS_H */ diff --git a/examples/configs/README.md b/examples/configs/README.md index e1749bdeed9..bb876539531 100644 --- a/examples/configs/README.md +++ b/examples/configs/README.md @@ -12,6 +12,7 @@ Example wolfSSL configuration file templates for use when autoconf is not availa * `user_settings_espressif.h`: Example configuration for Espressif ESP32. See also [wolfSSL/IDE/Espressif](https://github.com/wolfSSL/wolfssl/tree/master/IDE/Espressif). * `user_settings_fipsv2.h`: The FIPS v2 (3389) 140-2 certificate build options. * `user_settings_fipsv5.h`: The FIPS v5 (ready) 140-3 build options. Equivalent to `./configure --enable-fips=v5-dev`. +* `user_settings_curve25519nonblock.h`: Example Curve25519 (X25519) non-blocking configuration. * `user_settings_min_ecc.h`: Minimal ECC and SHA-256 only (no TLS). For ECC verify only add `NO_ECC_SIGN`. * `user_settings_platformio.h`: An example for PlatformIO library. See also [platformio/wolfssl](https://registry.platformio.org/libraries/wolfssl/wolfssl). * `user_settings_stm32.h`: Example configuration file generated from the wolfSSL STM32 Cube pack. diff --git a/examples/configs/user_settings_curve25519nonblock.h b/examples/configs/user_settings_curve25519nonblock.h new file mode 100644 index 00000000000..f84e3423e8d --- /dev/null +++ b/examples/configs/user_settings_curve25519nonblock.h @@ -0,0 +1,88 @@ +/* user_settings_curve25519nonblock.h + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Example wolfSSL user_settings.h file for Curve25519 (X25519) non-blocking. + * See doc/dox_comments/header_files/curve25519.h wc_curve25519_set_nonblock. + */ + +/* Settings based on this configure: +./configure --enable-curve25519=nonblock --enable-ecc=nonblock \ + --enable-sp=yes,nonblock \ + CFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK" +*/ + +/* Tested using: +cp ./examples/configs/user_settings_curve25519nonblock.h user_settings.h +./configure --enable-usersettings --enable-debug --disable-examples +make +./wolfcrypt/test/testwolfcrypt +*/ + +/* Example test results: +CURVE25519 non-block key gen: 1273 times +CURVE25519 non-block shared secret: 1275 times +CURVE25519 test passed! +*/ + +#ifndef WOLFSSL_USER_SETTINGS_H +#define WOLFSSL_USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Features */ +#define WOLFCRYPT_ONLY +#define WOLFSSL_ASN_TEMPLATE +#define WOLFSSL_PUBLIC_MP /* expose mp_ math API's */ +#define HAVE_HASHDRBG + +/* Curve25519 (X25519) */ +#define HAVE_CURVE25519 +#define CURVE25519_SMALL +#define WC_X25519_NONBLOCK + +/* Debugging */ +#if 1 + #undef DEBUG_WOLFSSL + #define DEBUG_WOLFSSL + #define WOLFSSL_DEBUG_NONBLOCK +#endif + +/* Disabled algorithms */ +#define NO_OLD_TLS +#define NO_RSA +#define NO_DH +#define NO_PSK +#define NO_MD4 +#define NO_MD5 +#define NO_SHA +#define NO_DSA +#define NO_DES3 +#define NO_RC4 +#define WOLFSSL_NO_SHAKE128 +#define WOLFSSL_NO_SHAKE256 + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_USER_SETTINGS_H */ diff --git a/src/internal.c b/src/internal.c index 6edad7309f4..76b2306b8ff 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6117,7 +6117,7 @@ static int X25519SharedSecret(WOLFSSL* ssl, curve25519_key* priv_key, #ifdef WOLFSSL_ASYNC_CRYPT /* initialize event */ - ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_NONE); if (ret != 0) return ret; #endif @@ -8189,6 +8189,14 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey) #endif /* HAVE_ED25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: + #if defined(WC_X25519_NONBLOCK) && \ + defined(WOLFSSL_ASYNC_CRYPT_SW) && \ + defined(WC_ASYNC_ENABLE_X25519) + if (((curve25519_key*)*pKey)->nbCtx != NULL) { + XFREE(((curve25519_key*)*pKey)->nbCtx, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + } + #endif wc_curve25519_free((curve25519_key*)*pKey); break; #endif /* HAVE_CURVE25519 */ @@ -8236,8 +8244,15 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) #endif /* HAVE_ECC */ #if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \ defined(WC_ASYNC_ENABLE_ECC) - ecc_nb_ctx_t* nbCtx; -#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && WC_ASYNC_ENABLE_ECC*/ + ecc_nb_ctx_t* eccNbCtx; +#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && WC_ASYNC_ENABLE_ECC */ +#ifdef HAVE_CURVE25519 + curve25519_key* x25519Key; +#endif /* HAVE_CURVE25519 */ +#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \ + defined(WC_ASYNC_ENABLE_X25519) + x25519_nb_ctx_t* x25519NbCtx; +#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && WC_ASYNC_ENABLE_X25519 */ if (ssl == NULL || pKey == NULL) { return BAD_FUNC_ARG; @@ -8323,23 +8338,23 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) case DYNAMIC_TYPE_ECC: eccKey = (ecc_key*)*pKey; ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId); + #if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \ + defined(WC_ASYNC_ENABLE_ECC) if (ret == 0) { - #if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \ - defined(WC_ASYNC_ENABLE_ECC) - nbCtx = (ecc_nb_ctx_t*)XMALLOC(sizeof(ecc_nb_ctx_t), - eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (nbCtx == NULL) { + eccNbCtx = (ecc_nb_ctx_t*)XMALLOC(sizeof(ecc_nb_ctx_t), + eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (eccNbCtx == NULL) { ret = MEMORY_E; } else { - ret = wc_ecc_set_nonblock(eccKey, nbCtx); + ret = wc_ecc_set_nonblock(eccKey, eccNbCtx); if (ret != 0) { - XFREE(nbCtx, eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccNbCtx, eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER); } } - #endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && - WC_ASYNC_ENABLE_ECC */ } + #endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && + WC_ASYNC_ENABLE_ECC */ break; #endif /* HAVE_ECC */ #ifdef HAVE_ED25519 @@ -8350,8 +8365,25 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey) #endif /* HAVE_CURVE25519 */ #ifdef HAVE_CURVE25519 case DYNAMIC_TYPE_CURVE25519: - wc_curve25519_init_ex((curve25519_key*)*pKey, ssl->heap, ssl->devId); - ret = 0; + x25519Key = (curve25519_key*)*pKey; + ret = wc_curve25519_init_ex(x25519Key, ssl->heap, ssl->devId); + #if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \ + defined(WC_ASYNC_ENABLE_X25519) + if (ret == 0) { + x25519NbCtx = (x25519_nb_ctx_t*)XMALLOC(sizeof(x25519_nb_ctx_t), + ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (x25519NbCtx == NULL) { + ret = MEMORY_E; + } + else { + ret = wc_curve25519_set_nonblock(x25519Key, x25519NbCtx); + if (ret != 0) { + XFREE(x25519NbCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + } + #endif /* WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && + WC_ASYNC_ENABLE_X25519 */ break; #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED448 diff --git a/src/ssl.c b/src/ssl.c index ff0a4eb0e5f..5f786eb5868 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #ifdef NO_INLINE @@ -4693,6 +4694,10 @@ int wolfSSL_get_error(WOLFSSL* ssl, int ret) return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E)) return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ +#endif +#ifdef WOLFSSL_ASYNC_CRYPT + else if (ssl->error == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) + return WC_PENDING_E; /* map non-blocking crypto */ #endif return ssl->error; } diff --git a/tests/api.c b/tests/api.c index 95b5f377139..f161b980b2b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -59,6 +59,7 @@ #include /* compatibility layer */ #include +#include #include #include @@ -4811,8 +4812,11 @@ int test_ssl_memio_do_handshake(test_ssl_memio_ctx* ctx, int max_rounds, } else { err = wolfSSL_get_error(ctx->c_ssl, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) { + /* retry non-blocking math */ + } + else if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) { char buff[WOLFSSL_MAX_ERROR_SZ]; fprintf(stderr, "error = %d, %s\n", err, wolfSSL_ERR_error_string((word32)err, buff)); @@ -4833,8 +4837,11 @@ int test_ssl_memio_do_handshake(test_ssl_memio_ctx* ctx, int max_rounds, } else { err = wolfSSL_get_error(ctx->s_ssl, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) { + if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) { + /* retry non-blocking math */ + } + else if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) { char buff[WOLFSSL_MAX_ERROR_SZ]; fprintf(stderr, "error = %d, %s\n", err, wolfSSL_ERR_error_string((word32)err, buff)); diff --git a/tests/utils.c b/tests/utils.c index 3ad6e673508..0e78506e70a 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -21,6 +21,7 @@ #include #include +#include #ifdef HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES @@ -182,9 +183,16 @@ int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, } else { err = wolfSSL_get_error(ssl_c, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) + if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) { + /* retry non-blocking math */ + } + else if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) { + char buff[WOLFSSL_MAX_ERROR_SZ]; + fprintf(stderr, "memio client error = %d, %s\n", err, + wolfSSL_ERR_error_string((word32)err, buff)); return -1; + } } } if (!hs_s) { @@ -196,9 +204,16 @@ int test_memio_do_handshake(WOLFSSL *ssl_c, WOLFSSL *ssl_s, } else { err = wolfSSL_get_error(ssl_s, ret); - if (err != WOLFSSL_ERROR_WANT_READ && - err != WOLFSSL_ERROR_WANT_WRITE) + if (err == WC_NO_ERR_TRACE(MP_WOULDBLOCK)) { + /* retry non-blocking math */ + } + else if (err != WOLFSSL_ERROR_WANT_READ && + err != WOLFSSL_ERROR_WANT_WRITE) { + char buff[WOLFSSL_MAX_ERROR_SZ]; + fprintf(stderr, "memio server error = %d, %s\n", err, + wolfSSL_ERR_error_string((word32)err, buff)); return -1; + } } } handshake_complete = hs_c && hs_s; @@ -792,4 +807,3 @@ void DEBUG_WRITE_DER(const byte* der, int derSz, const char* fileName) } } #endif - diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 6534a69e986..8416be2ebd7 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -22,7 +22,14 @@ /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */ -#include +/* + * X25519 configuration macros: + * + * WC_X25519_NONBLOCK: Enable non-blocking support for key gen and shared + * secret. Requires CURVE25519_SMALL. Default: off. + */ + + #include #ifdef NO_CURVED25519_X64 #undef USE_INTEL_SPEEDUP @@ -32,6 +39,8 @@ #include #include +#include +#include #ifdef NO_INLINE #include #else @@ -440,6 +449,85 @@ int wc_curve25519_make_priv(WC_RNG* rng, int keysize, byte* key) return ret; } +#ifdef WC_X25519_NONBLOCK + +static int wc_curve25519_make_pub_nb(curve25519_key* key) +{ + int ret = 0; + + if (key == NULL) { + ret = BAD_FUNC_ARG; + } + else if (key->nbCtx == NULL) { + WOLFSSL_MSG("wc_curve25519_make_pub_nb called with NULL non-blocking " + "context."); + ret = BAD_FUNC_ARG; + } + + if (ret == 0 && key->nbCtx->state == 0) { + /* check clamping */ + ret = curve25519_priv_clamp_check(key->k); + if (ret == 0) { + fe_init(); + } + } + if (ret == 0) { + ret = curve25519_nb(key->p.point, key->k, (byte*)kCurve25519BasePoint, + key->nbCtx); + } + + return ret; +} + +static int wc_curve25519_make_key_nb(WC_RNG* rng, int keysize, + curve25519_key* key) +{ + int ret = 0; + + if (key == NULL || rng == NULL) { + ret = BAD_FUNC_ARG; + } + else if (key->nbCtx == NULL) { + WOLFSSL_MSG("wc_curve25519_make_key_nb called with NULL non-blocking " + "context."); + ret = BAD_FUNC_ARG; + } + + if (ret == 0 && key->nbCtx->state == 0) { + ret = wc_curve25519_make_priv(rng, keysize, key->k); + if (ret == 0) { + key->privSet = 1; + } + } + if (ret == 0) { + ret = wc_curve25519_make_pub_nb(key); + if (ret == 0) { + key->pubSet = 1; + } + } + + return ret; +} + +int wc_curve25519_set_nonblock(curve25519_key* key, x25519_nb_ctx_t* ctx) +{ + int ret = 0; + + if (key != NULL) { + if (ctx != NULL) { + XMEMSET(ctx, 0, sizeof(x25519_nb_ctx_t)); + } + key->nbCtx = ctx; + } + else { + ret = BAD_FUNC_ARG; + } + + return ret; +} + +#endif /* WC_X25519_NONBLOCK */ + /* generate a new keypair. * * return value is propagated from wc_curve25519_make_private() or @@ -461,26 +549,46 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key) } #endif +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519) + if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_X25519) { + if (wc_AsyncSwInit(&key->asyncDev, ASYNC_SW_X25519_MAKE)) { + WC_ASYNC_SW* sw = &key->asyncDev.sw; + sw->x25519Make.rng = rng; + sw->x25519Make.size = keysize; + sw->x25519Make.key = key; + return WC_PENDING_E; + } + } +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 */ + #ifdef WOLFSSL_SE050 ret = se050_curve25519_create_key(key, keysize); -#else - ret = wc_curve25519_make_priv(rng, keysize, key->k); - if (ret == 0) { - key->privSet = 1; -#ifdef WOLFSSL_CURVE25519_BLINDING - ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point), - key->p.point, (int)sizeof(key->k), - key->k, rng); +#elif defined(WC_X25519_NONBLOCK) + if (key->nbCtx != NULL) { + ret = wc_curve25519_make_key_nb(rng, keysize, key); + } + else +#endif +#if !defined(WOLFSSL_SE050) + { + ret = wc_curve25519_make_priv(rng, keysize, key->k); if (ret == 0) { - ret = wc_curve25519_set_rng(key, rng); - } + key->privSet = 1; +#ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point), + key->p.point, (int)sizeof(key->k), key->k, rng); + if (ret == 0) { + ret = wc_curve25519_set_rng(key, rng); + } #else - ret = wc_curve25519_make_pub((int)sizeof(key->p.point), key->p.point, - (int)sizeof(key->k), key->k); + ret = wc_curve25519_make_pub((int)sizeof(key->p.point), + key->p.point, (int)sizeof(key->k), key->k); #endif - key->pubSet = (ret == 0); + key->pubSet = (ret == 0); + } } -#endif +#endif /* !WOLFSSL_SE050 */ + return ret; } @@ -494,12 +602,61 @@ int wc_curve25519_shared_secret(curve25519_key* private_key, out, outlen, EC25519_BIG_ENDIAN); } +#ifdef WC_X25519_NONBLOCK + +static int wc_curve25519_shared_secret_nb(curve25519_key* privKey, + curve25519_key* pubKey, byte* out, word32* outlen, int endian) +{ + int ret = FP_WOULDBLOCK; + + switch (privKey->nbCtx->ssState) { + case 0: + XMEMSET(&privKey->nbCtx->o, 0, sizeof(privKey->nbCtx->o)); + privKey->nbCtx->ssState = 1; + break; + case 1: + ret = curve25519_nb(privKey->nbCtx->o.point, privKey->k, + pubKey->p.point, privKey->nbCtx); + if (ret == 0) { + ret = FP_WOULDBLOCK; + privKey->nbCtx->ssState = 2; + } + break; + case 2: + #ifdef WOLFSSL_ECDHX_SHARED_NOT_ZERO + int i; + byte t = 0; + + for (i = 0; i < CURVE25519_KEYSIZE; i++) { + t |= privKey->nbCtx->o.point[i]; + } + if (t == 0) { + ret = ECC_OUT_OF_RANGE_E; + } + else + #endif /* WOLFSSL_ECDHX_SHARED_NOT_ZERO */ + { + curve25519_copy_point(out, privKey->nbCtx->o.point, endian); + *outlen = CURVE25519_KEYSIZE; + ret = 0; + } + break; + } + + if (ret != FP_WOULDBLOCK) { + XMEMSET(privKey->nbCtx, 0, sizeof(x25519_nb_ctx_t)); + } + + return ret; +} + +#endif /* WC_X25518_NONBLOCK */ + int wc_curve25519_shared_secret_ex(curve25519_key* private_key, curve25519_key* public_key, byte* out, word32* outlen, int endian) { - int ret; - ECPoint o; + int ret = 0; /* sanity check */ if (private_key == NULL || public_key == NULL || @@ -531,51 +688,78 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key, } #endif - XMEMSET(&o, 0, sizeof(o)); +#ifdef WC_X25519_NONBLOCK + +#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519) + if (private_key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_X25519) { + if (wc_AsyncSwInit(&private_key->asyncDev, + ASYNC_SW_X25519_SHARED_SEC)) { + WC_ASYNC_SW* sw = &private_key->asyncDev.sw; + sw->x25519SharedSec.priv = private_key; + sw->x25519SharedSec.pub = public_key; + sw->x25519SharedSec.out = out; + sw->x25519SharedSec.outLen = outlen; + sw->x25519SharedSec.endian = endian; + return WC_PENDING_E; + } + } +#endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 */ -#ifdef FREESCALE_LTC_ECC - /* input point P on Curve25519 */ - ret = nxp_ltc_curve25519(&o, private_key->k, &public_key->p, - kLTC_Curve25519); -#else - #ifdef WOLFSSL_SE050 - if (!private_key->privSet) { - /* use NXP SE050: "privSet" is not set */ - ret = se050_curve25519_shared_secret(private_key, public_key, &o); + if (private_key->nbCtx != NULL) { + ret = wc_curve25519_shared_secret_nb(private_key, public_key, out, + outlen, endian); } else - #endif +#endif /* WC_X25519_NONBLOCK */ { + ECPoint o; + + XMEMSET(&o, 0, sizeof(o)); + +#ifdef FREESCALE_LTC_ECC + /* input point P on Curve25519 */ + ret = nxp_ltc_curve25519(&o, private_key->k, &public_key->p, + kLTC_Curve25519); +#else + #ifdef WOLFSSL_SE050 + if (!private_key->privSet) { + /* use NXP SE050: "privSet" is not set */ + ret = se050_curve25519_shared_secret(private_key, public_key, &o); + } + else + #endif /* WOLFSSL_SE050 */ + { #ifndef WOLFSSL_CURVE25519_BLINDING - SAVE_VECTOR_REGISTERS(return _svr_ret;); + SAVE_VECTOR_REGISTERS(return _svr_ret;); - ret = curve25519(o.point, private_key->k, public_key->p.point); + ret = curve25519(o.point, private_key->k, public_key->p.point); - RESTORE_VECTOR_REGISTERS(); + RESTORE_VECTOR_REGISTERS(); #else - ret = curve25519_smul_blind(o.point, private_key->k, public_key->p.point, - private_key->rng); -#endif - } + ret = curve25519_smul_blind(o.point, private_key->k, + public_key->p.point, private_key->rng); #endif + } +#endif /* FREESCALE_LTC_ECC */ #ifdef WOLFSSL_ECDHX_SHARED_NOT_ZERO - if (ret == 0) { - int i; - byte t = 0; - for (i = 0; i < CURVE25519_KEYSIZE; i++) { - t |= o.point[i]; + if (ret == 0) { + int i; + byte t = 0; + for (i = 0; i < CURVE25519_KEYSIZE; i++) { + t |= o.point[i]; + } + if (t == 0) { + ret = ECC_OUT_OF_RANGE_E; + } } - if (t == 0) { - ret = ECC_OUT_OF_RANGE_E; +#endif /* WOLFSSL_ECDHX_SHARED_NOT_ZERO */ + if (ret == 0) { + curve25519_copy_point(out, o.point, endian); + *outlen = CURVE25519_KEYSIZE; } - } -#endif - if (ret == 0) { - curve25519_copy_point(out, o.point, endian); - *outlen = CURVE25519_KEYSIZE; - } - ForceZero(&o, sizeof(o)); + ForceZero(&o, sizeof(o)); + } return ret; } @@ -931,30 +1115,40 @@ int wc_curve25519_delete(curve25519_key* key, curve25519_key** key_p) { int wc_curve25519_init_ex(curve25519_key* key, void* heap, int devId) { - if (key == NULL) - return BAD_FUNC_ARG; + int ret = 0; - XMEMSET(key, 0, sizeof(*key)); + if (key == NULL) { + ret = BAD_FUNC_ARG; + } + else { + XMEMSET(key, 0, sizeof(*key)); - /* currently the format for curve25519 */ - key->dp = &curve25519_sets[0]; + /* currently the format for curve25519 */ + key->dp = &curve25519_sets[0]; -#ifdef WOLF_CRYPTO_CB - key->devId = devId; -#else - (void)devId; -#endif - (void)heap; /* if needed for XMALLOC/XFREE in future */ + #ifdef WOLF_CRYPTO_CB + key->devId = devId; + #else + (void)devId; + #endif + (void)heap; /* if needed for XMALLOC/XFREE in future */ -#ifndef FREESCALE_LTC_ECC - fe_init(); -#endif + #ifndef FREESCALE_LTC_ECC + fe_init(); + #endif -#ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wc_curve25519_init_ex key->k", key->k, CURVE25519_KEYSIZE); -#endif + #ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wc_curve25519_init_ex key->k", key->k, + CURVE25519_KEYSIZE); + #endif - return 0; + #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_X25519) + ret = wolfAsync_DevCtxInit(&key->asyncDev, WOLFSSL_ASYNC_MARKER_X25519, + heap, devId); + #endif + } + + return ret; } int wc_curve25519_init(curve25519_key* key) diff --git a/wolfcrypt/src/fe_low_mem.c b/wolfcrypt/src/fe_low_mem.c index d2b2d8ae8bf..52f52b5ea96 100644 --- a/wolfcrypt/src/fe_low_mem.c +++ b/wolfcrypt/src/fe_low_mem.c @@ -179,6 +179,256 @@ int curve25519(byte *result, const byte *n, const byte *p) fe_normalize(result); return 0; } + +#ifdef WC_X25519_NONBLOCK + +int fe_inv__distinct_nb(byte *r, const byte *x, fe_inv__distinct_nb_ctx_t* ctx) +{ + int ret = FP_WOULDBLOCK; + + switch (ctx->state) { + case 0: + fe_mul__distinct(ctx->s, x, x); + fe_mul__distinct(r, ctx->s, x); + ctx->i = 0; + ctx->subState = 0; + ctx->state = 1; + break; + case 1: + if (ctx->i < 248) { + if (ctx->subState == 0) { + fe_mul__distinct(ctx->s, r, r); + ctx->subState = 1; + } + else { + fe_mul__distinct(r, ctx->s, x); + ctx->subState = 0; + ++(ctx->i); + } + } + else { + ctx->state = 2; + ctx->subState = 0; + } + break; + case 2: + switch (ctx->subState) { + case 0: + fe_mul__distinct(ctx->s, r, r); + ctx->subState = 1; + break; + case 1: + fe_mul__distinct(r, ctx->s, ctx->s); + ctx->subState = 2; + break; + case 2: + fe_mul__distinct(ctx->s, r, x); + ctx->subState = 3; + break; + case 3: + fe_mul__distinct(r, ctx->s, ctx->s); + ctx->subState = 4; + break; + case 4: + fe_mul__distinct(ctx->s, r, r); + ctx->subState = 5; + break; + case 5: + fe_mul__distinct(r, ctx->s, x); + ctx->subState = 6; + break; + case 6: + fe_mul__distinct(ctx->s, r, r); + ctx->subState = 7; + break; + case 7: + fe_mul__distinct(r, ctx->s, x); + ret = 0; + break; + default: + ctx->subState = 0; + break; + } + break; + } + + if (ret == 0) { + XMEMSET(ctx, 0, sizeof(fe_inv__distinct_nb_ctx_t)); + } + + return ret; +} + + +int curve25519_nb(byte *result, const byte *n, const byte *p, + struct x25519_nb_ctx_t* ctx) +{ + int ret = FP_WOULDBLOCK; + + switch (ctx->state) { + case 0: + XMEMSET(ctx->zm, 0, sizeof(ctx->zm)); + ctx->zm[0] = 1; + XMEMSET(ctx->xm1, 0, sizeof(ctx->xm1)); + ctx->xm1[0] = 1; + XMEMSET(ctx->zm1, 0, sizeof(ctx->zm1)); + lm_copy(ctx->xm, p); + ctx->i = 253; + ctx->subState = 0; + ctx->state = 1; + break; + case 1: + if (ctx->i >= 0) { + switch (ctx->subState) { + case 0: + ctx->bit = (n[ctx->i >> 3] >> (ctx->i & 7)) & 1; + /* Diffadd step 1 */ + lm_add(ctx->a, ctx->xm, ctx->zm); + lm_sub(ctx->b, ctx->xm1, ctx->zm1); + fe_mul__distinct(ctx->da, ctx->a, ctx->b); + ctx->subState = 1; + break; + case 1: + /* Diffadd step 2 */ + lm_sub(ctx->b, ctx->xm, ctx->zm); + lm_add(ctx->a, ctx->xm1, ctx->zm1); + fe_mul__distinct(ctx->cb, ctx->a, ctx->b); + ctx->subState = 2; + break; + case 2: + /* Diffadd step 3 */ + lm_add(ctx->a, ctx->da, ctx->cb); + fe_mul__distinct(ctx->b, ctx->a, ctx->a); + ctx->subState = 3; + break; + case 3: + /* Diffadd step 4 */ + fe_mul__distinct(ctx->xm1, f25519_one, ctx->b); + ctx->subState = 4; + break; + case 4: + /* Diffadd step 5 */ + lm_sub(ctx->a, ctx->da, ctx->cb); + fe_mul__distinct(ctx->b, ctx->a, ctx->a); + ctx->subState = 5; + break; + case 5: + /* Diffadd step 6 */ + fe_mul__distinct(ctx->zm1, p, ctx->b); + ctx->subState = 6; + break; + case 6: + /* Double step 1 */ + fe_mul__distinct(ctx->x1sq, ctx->xm, ctx->xm); + ctx->subState = 7; + break; + case 7: + /* Double step 2 */ + fe_mul__distinct(ctx->z1sq, ctx->zm, ctx->zm); + ctx->subState = 8; + break; + case 8: + /* Double step 3 */ + fe_mul__distinct(ctx->x1z1, ctx->xm, ctx->zm); + ctx->subState = 9; + break; + case 9: + /* Double step 4 */ + lm_sub(ctx->a, ctx->x1sq, ctx->z1sq); + fe_mul__distinct(ctx->xm, ctx->a, ctx->a); + ctx->subState = 10; + break; + case 10: + /* Double step 5 */ + fe_mul_c(ctx->a, ctx->x1z1, 486662); + lm_add(ctx->a, ctx->x1sq, ctx->a); + lm_add(ctx->a, ctx->z1sq, ctx->a); + fe_mul__distinct(ctx->x1sq, ctx->x1z1, ctx->a); + ctx->subState = 11; + break; + case 11: + fe_mul_c(ctx->zm, ctx->x1sq, 4); + ctx->subState = 12; + break; + case 12: + /* Diffadd2 step 1 */ + lm_add(ctx->a, ctx->xm, ctx->zm); + lm_sub(ctx->b, p, f25519_one); + fe_mul__distinct(ctx->da, ctx->a, ctx->b); + ctx->subState = 13; + break; + case 13: + /* Diffadd2 step 2 */ + lm_sub(ctx->b, ctx->xm, ctx->zm); + lm_add(ctx->a, p, f25519_one); + fe_mul__distinct(ctx->cb, ctx->a, ctx->b); + ctx->subState = 14; + break; + case 14: + /* Diffadd2 step 3 */ + lm_add(ctx->a, ctx->da, ctx->cb); + fe_mul__distinct(ctx->b, ctx->a, ctx->a); + ctx->subState = 15; + break; + case 15: + /* Diffadd2 step 4 */ + fe_mul__distinct(ctx->xms, ctx->zm1, ctx->b); + ctx->subState = 16; + break; + case 16: + /* Diffadd2 step 5 */ + lm_sub(ctx->a, ctx->da, ctx->cb); + fe_mul__distinct(ctx->b, ctx->a, ctx->a); + ctx->subState = 17; + break; + case 17: + /* Diffadd2 step 6 */ + fe_mul__distinct(ctx->zms, ctx->xm1, ctx->b); + ctx->subState = 18; + break; + case 18: + /* Select: + * bit = 1 --> (P_(2m+1), P_(2m)) + * bit = 0 --> (P_(2m), P_(2m-1)) + */ + fe_select(ctx->xm1, ctx->xm1, ctx->xm, ctx->bit); + fe_select(ctx->zm1, ctx->zm1, ctx->zm, ctx->bit); + fe_select(ctx->xm, ctx->xm, ctx->xms, ctx->bit); + fe_select(ctx->zm, ctx->zm, ctx->zms, ctx->bit); + --(ctx->i); + ctx->subState = 0; + break; + default: + ctx->subState = 0; + break; + } + } + else { + ctx->state = 2; + } + break; + case 2: + /* Freeze out of projective coordinates */ + if (fe_inv__distinct_nb(ctx->zm1, ctx->zm, + &ctx->inv_distinct_nb_ctx) == 0) { + ctx->state = 3; + } + break; + case 3: + fe_mul__distinct(result, ctx->zm1, ctx->xm); + fe_normalize(result); + ret = 0; + break; + } + + if (ret == 0) { + XMEMSET(ctx, 0, sizeof(x25519_nb_ctx_t)); + } + + return ret; +} +#endif /* WC_X25519_NONBLOCK */ + #endif /* !FREESCALE_LTC_ECC */ #endif /* CURVE25519_SMALL */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a14991294df..83b43257019 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -38202,7 +38202,12 @@ static wc_test_ret_t curve25519_overflow_test(WC_RNG* rng) /* test against known test vector */ XMEMSET(shared, 0, sizeof(shared)); y = sizeof(shared); - if (wc_curve25519_shared_secret(&userA, &userA, shared, &y) != 0) { + ret = wc_curve25519_shared_secret(&userA, &userA, shared, &y); + #if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userA.asyncDev, WC_ASYNC_FLAG_NONE); + #endif + if (ret != 0) { ret = WC_TEST_RET_ENC_I(i); break; } @@ -38580,6 +38585,117 @@ static wc_test_ret_t curve255519_der_test(void) } #endif /* !NO_ASN && HAVE_CURVE25519_KEY_EXPORT && HAVE_CURVE25519_KEY_IMPORT */ +#ifdef WC_X25519_NONBLOCK +/* build and test with: + * ./configure --enable-curve25519=nonblock CFLAGS="-DWOLFSSL_DEBUG_NONBLOCK" + * make + * ./wolfcrypt/test/testwolfcrypt + */ +static int x25519_nonblock_test(WC_RNG* rng) +{ + int ret = 0; + x25519_nb_ctx_t nbCtx; + curve25519_key userA; + curve25519_key userB; +#ifdef HAVE_CURVE25519_SHARED_SECRET + byte sharedA[32]; + byte sharedB[32]; + word32 x; + word32 y; +#endif + int count; + + XMEMSET(&nbCtx, 0, sizeof(nbCtx)); + + ret = wc_curve25519_init(&userA); + if (ret != 0) { + printf("wc_curve25519_init 1 %d\n", ret); + return -10722; + } + ret = wc_curve25519_set_nonblock(&userA, &nbCtx); + if (ret != 0) { + printf("wc_curve25519_set_nonblock 1 %d\n", ret); + return -10723; + } + count = 0; + do { + ret = wc_curve25519_make_key(rng, 32, &userA); + count++; + } while (ret == FP_WOULDBLOCK); + if (ret != 0) { + printf("wc_curve25519_make_key_nb 1 %d\n", ret); + return -10724; + } +#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK) + /* CURVE25519 non-block key gen: 5335 times */ + printf("CURVE25519 non-block key gen: %d times\n", count); +#endif + + ret = wc_curve25519_init(&userB); + if (ret != 0) { + printf("wc_curve25519_init 2 %d\n", ret); + wc_curve25519_free(&userA); + return -10724; + } + ret = wc_curve25519_set_nonblock(&userB, &nbCtx); + if (ret != 0) { + printf("wc_curve25519_set_nonblock 2 %d\n", ret); + return -10725; + } + count = 0; + do { + ret = wc_curve25519_make_key(rng, 32, &userB); + count++; + } while (ret == FP_WOULDBLOCK); + if (ret != 0) { + printf("wc_curve25519_make_key_nb 2 %d\n", ret); + return -10726; + } + +#ifdef HAVE_CURVE25519_SHARED_SECRET + x = sizeof(sharedA); + do { + ret = wc_curve25519_shared_secret(&userA, &userB, sharedA, &x); + } while (ret == FP_WOULDBLOCK); + if (ret != 0) { + printf("wc_curve25519_shared_secret_nb 1 %d\n", ret); + return -10727; + } + + y = sizeof(sharedB); + count = 0; + do { + ret = wc_curve25519_shared_secret(&userB, &userA, sharedB, &y); + count++; + } + while (ret == FP_WOULDBLOCK); + if (ret != 0) { + printf("wc_curve25519_shared_secret_nb 2 %d\n", ret); + return -10728; + } +#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK) + /* CURVE25519 non-block shared secret: 5337 times */ + printf("CURVE25519 non-block shared secret: %d times\n", count); +#endif + + /* compare shared secret keys to test they are the same */ + if (y != x) { + return -10729; + } + + if (XMEMCMP(sharedA, sharedB, x) != 0) { + return -10730; + } +#endif /* HAVE_CURVE25519_SHARED_SECRET */ + + wc_curve25519_free(&userA); + wc_curve25519_free(&userB); + + return 0; +} + +#endif /* WC_X25519_NONBLOCK */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) { WC_RNG rng; @@ -38681,23 +38797,41 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) /* make curve25519 keys */ ret = wc_curve25519_make_key(&rng, 32, userA); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); ret = wc_curve25519_make_key(&rng, 32, userB); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); #ifdef HAVE_CURVE25519_SHARED_SECRET /* find shared secret key */ x = sizeof(sharedA); - if ((ret = wc_curve25519_shared_secret(userA, userB, sharedA, &x)) != 0) { + ret = wc_curve25519_shared_secret(userA, userB, sharedA, &x); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (ret != 0) { printf("wc_curve25519_shared_secret 1 failed\n"); ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); } y = sizeof(sharedB); - if ((ret = wc_curve25519_shared_secret(userB, userA, sharedB, &y)) != 0) { + ret = wc_curve25519_shared_secret(userB, userA, sharedB, &y); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (ret != 0) { printf("wc_curve25519_shared_secret 2 failed\n"); ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); } @@ -38729,7 +38863,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) /* test shared key after importing a public key */ XMEMSET(sharedB, 0, sizeof(sharedB)); y = sizeof(sharedB); - if (wc_curve25519_shared_secret(userB, pubKey, sharedB, &y) != 0) { + ret = wc_curve25519_shared_secret(userB, pubKey, sharedB, &y); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (ret != 0) { ERROR_OUT(WC_TEST_RET_ENC_NC, cleanup); } @@ -38751,6 +38890,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) XMEMSET(sharedB, 0, sizeof(sharedB)); y = sizeof(sharedB); ret = wc_curve25519_shared_secret(userA, userB, sharedB, &y); + #if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); @@ -38761,6 +38904,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) XMEMSET(sharedB, 0, sizeof(sharedB)); y = sizeof(sharedB); ret = wc_curve25519_shared_secret(userB, userA, sharedB, &y); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); @@ -38780,16 +38927,28 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) #endif ret = wc_curve25519_make_key(&rng, 32, userB); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); x = sizeof(sharedA); ret = wc_curve25519_shared_secret(userA, userB, sharedA, &x); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userA->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); y = sizeof(sharedB); ret = wc_curve25519_shared_secret(userB, userA, sharedB, &y); +#if defined(WOLFSSL_ASYNC_CRYPT) + if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) + ret = wc_AsyncWait(ret, &userB->asyncDev, WC_ASYNC_FLAG_NONE); +#endif if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); @@ -38815,6 +38974,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) goto cleanup; #endif +#ifdef WC_X25519_NONBLOCK + ret = x25519_nonblock_test(&rng); + if (ret != 0) { + goto cleanup; + } +#endif /* WC_X25519_NONBLOCK */ + cleanup: /* clean up keys when done */ diff --git a/wolfssl/wolfcrypt/curve25519.h b/wolfssl/wolfcrypt/curve25519.h index a791d6799a4..f73b9c31b22 100644 --- a/wolfssl/wolfcrypt/curve25519.h +++ b/wolfssl/wolfcrypt/curve25519.h @@ -74,6 +74,46 @@ typedef struct ECPoint { #define WC_CURVE25519KEY_TYPE_DEFINED #endif +#ifdef WC_X25519_NONBLOCK + +typedef struct fe_inv__distinct_nb_ctx_t { + int state; + int subState; + byte s[F25519_SIZE]; + int i; +} fe_inv__distinct_nb_ctx_t; + +typedef struct x25519_nb_ctx_t { + /* state for curve25519 operation */ + int state; + int subState; + /* state for shared secret */ + int ssState; + int i; + int bit; + /* Current point: P_m */ + byte xm[F25519_SIZE]; + byte zm[F25519_SIZE]; + /* Predecessor: P_(m-1) */ + byte xm1[F25519_SIZE]; + byte zm1[F25519_SIZE]; + /* Temporary P_(2m+1) */ + byte xms[F25519_SIZE]; + byte zms[F25519_SIZE]; + /* Temporary buffers for non-blocking diffadd/double */ + byte a[F25519_SIZE]; + byte b[F25519_SIZE]; + byte da[F25519_SIZE]; + byte cb[F25519_SIZE]; + byte x1sq[F25519_SIZE]; + byte z1sq[F25519_SIZE]; + byte x1z1[F25519_SIZE]; + fe_inv__distinct_nb_ctx_t inv_distinct_nb_ctx; + ECPoint o; /* point for shared secret */ +} x25519_nb_ctx_t; + +#endif /* WC_X25519_NONBLOCK */ + /* A CURVE25519 Key */ struct curve25519_key { int idx; /* Index into the ecc_sets[] for the parameters of @@ -100,6 +140,10 @@ struct curve25519_key { byte keyIdSet; #endif +#ifdef WC_X25519_NONBLOCK + x25519_nb_ctx_t* nbCtx; +#endif /* WC_X25519_NONBLOCK */ + /* bit fields */ WC_BITFIELD pubSet:1; WC_BITFIELD privSet:1; @@ -137,6 +181,26 @@ int wc_curve25519_make_priv(WC_RNG* rng, int keysize, byte* priv); WOLFSSL_API int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key); +#ifdef WC_X25519_NONBLOCK + +/*! + \brief Enable non-blocking support for X25519 operations on a key. + When enabled, wc_curve25519_make_key() and + wc_curve25519_shared_secret() will return FP_WOULDBLOCK during + operation, allowing the caller to + yield and resume. Requires WC_X25519_NONBLOCK and CURVE25519_SMALL. + + \param key Pointer to curve25519_key structure to configure + \param ctx Pointer to x25519_nb_ctx_t context for state tracking, + or NULL to disable non-blocking mode + + \return 0 on success, BAD_FUNC_ARG if key is NULL +*/ +WOLFSSL_API +int wc_curve25519_set_nonblock(curve25519_key* key, x25519_nb_ctx_t* ctx); + +#endif /* WC_X25519_NONBLOCK */ + WOLFSSL_API int wc_curve25519_shared_secret(curve25519_key* private_key, curve25519_key* public_key, diff --git a/wolfssl/wolfcrypt/fe_operations.h b/wolfssl/wolfcrypt/fe_operations.h index 02490e24637..d1f4dc2892c 100644 --- a/wolfssl/wolfcrypt/fe_operations.h +++ b/wolfssl/wolfcrypt/fe_operations.h @@ -68,25 +68,52 @@ Bounds on each t[i] vary depending on context. #endif #if defined(CURVE25519_SMALL) || defined(ED25519_SMALL) - #define F25519_SIZE 32 - - WOLFSSL_LOCAL void lm_copy(byte* x, const byte* a); - WOLFSSL_LOCAL void lm_add(byte* r, const byte* a, const byte* b); - WOLFSSL_LOCAL void lm_sub(byte* r, const byte* a, const byte* b); - WOLFSSL_LOCAL void lm_neg(byte* r,const byte* a); - WOLFSSL_LOCAL void lm_invert(byte* r, const byte* x); - WOLFSSL_LOCAL void lm_mul(byte* r,const byte* a, const byte* b); + +#define F25519_SIZE 32 + +#include + +WOLFSSL_LOCAL void lm_copy(byte*, const byte*); +WOLFSSL_LOCAL void lm_add(byte*, const byte*, const byte*); +WOLFSSL_LOCAL void lm_sub(byte*, const byte*, const byte*); +WOLFSSL_LOCAL void lm_neg(byte*,const byte*); +WOLFSSL_LOCAL void lm_invert(byte*, const byte*); +WOLFSSL_LOCAL void lm_mul(byte*,const byte*,const byte*); + +#ifdef WC_X25519_NONBLOCK + +/* Use standard wolfSSL non-blocking error code */ +#ifndef FP_WOULDBLOCK +#include +#define FP_WOULDBLOCK MP_WOULDBLOCK #endif +struct fe_inv__distinct_nb_ctx_t; +struct x25519_nb_ctx_t; + +WOLFSSL_LOCAL int fe_inv__distinct_nb(byte *r, const byte *x, + struct fe_inv__distinct_nb_ctx_t* ctx); + +WOLFSSL_LOCAL int curve25519_nb(byte * q, const byte * n, const byte * p, + struct x25519_nb_ctx_t* ctx); + +#endif /* WC_X25519_NONBLOCK */ + +#else + #ifdef WC_X25519_NONBLOCK + #error The X25519 non-blocking requires CURVE25519_SMALL \ + (--enable-curve25519=small) + #endif +#endif /* CURVE25519_SMALL || ED25519_SMALL */ + #if !defined(FREESCALE_LTC_ECC) WOLFSSL_LOCAL void fe_init(void); -WOLFSSL_LOCAL int curve25519_base(byte * q, const byte * n); -WOLFSSL_LOCAL int curve25519(byte * q, const byte * n, const byte * p); +WOLFSSL_LOCAL int curve25519(byte * q, const byte * n, const byte * p); #ifdef WOLFSSL_CURVE25519_BLINDING -WOLFSSL_LOCAL int curve25519_blind(byte * q, const byte * n, const byte* mask, - const byte * p, const byte* rz); +WOLFSSL_LOCAL int curve25519_blind(byte* q, const byte* n, const byte* mask, + const byte* p, const byte* rz); #endif #endif