diff --git a/netutils/dropbear/CMakeLists.txt b/netutils/dropbear/CMakeLists.txt index 4261c2bc0..8e4015a5c 100644 --- a/netutils/dropbear/CMakeLists.txt +++ b/netutils/dropbear/CMakeLists.txt @@ -68,6 +68,11 @@ if(CONFIG_NETUTILS_DROPBEAR) patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i "${CMAKE_CURRENT_SOURCE_DIR}/patch/0005-use-nuttx-sha256-hmac.patch" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + execute_process( + COMMAND + patch -s -N -l -p1 -d "${DROPBEAR_UNPACKNAME}" -i + "${CMAKE_CURRENT_SOURCE_DIR}/patch/0006-use-nuttx-chachapoly-cryptodev.patch" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") message(STATUS "Generating default_options_guard.h") execute_process( COMMAND @@ -151,6 +156,12 @@ if(CONFIG_NETUTILS_DROPBEAR) port/dropbear_ltc_hmac_sha256.c) endif() + if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY) + # Replace the bundled chacha20-poly1305 with the /dev/crypto adapter. + list(REMOVE_ITEM DROPBEAR_SRCS dropbear/src/chachapoly.c) + list(APPEND DROPBEAR_SRCS port/dropbear_chachapoly.c) + endif() + list(APPEND DROPBEAR_SRCS ${LIBTOMCRYPT_SRCS}) if(CONFIG_NETUTILS_DROPBEAR_SCP) @@ -216,6 +227,10 @@ if(CONFIG_NETUTILS_DROPBEAR) DROPBEAR_NUTTX_HMAC_SHA256=1) endif() + if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY) + target_compile_definitions(${PROGNAME} PRIVATE DROPBEAR_NUTTX_CHACHAPOLY=1) + endif() + if(CONFIG_NETUTILS_DROPBEAR_SCP) target_compile_definitions( scp PRIVATE LOCALOPTIONS_H_EXISTS=1 DROPBEAR_NUTTX=1 @@ -246,6 +261,17 @@ if(CONFIG_NETUTILS_DROPBEAR) set_source_files_properties(${LIBTOMCRYPT_SRCS} PROPERTIES COMPILE_DEFINITIONS LTC_SOURCE=1) + if(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY) + # The NuttX crypto backend pulled in by /dev/crypto also exports + # ecc_make_key. Dropbear only uses libtomcrypt's ecc_make_key_ex, so rename + # the unused plain wrapper to avoid a multiple definition. Append so the + # LTC_SOURCE define set above is preserved. + set_property( + SOURCE dropbear/libtomcrypt/src/pk/ecc/ecc_make_key.c + APPEND + PROPERTY COMPILE_DEFINITIONS ecc_make_key=dropbear_ltc_ecc_make_key) + endif() + target_compile_options(${PROGNAME} PRIVATE -Wno-pointer-sign -Wno-format) if(CONFIG_NETUTILS_DROPBEAR_SCP) diff --git a/netutils/dropbear/Kconfig b/netutils/dropbear/Kconfig index d86775afd..a84c17064 100644 --- a/netutils/dropbear/Kconfig +++ b/netutils/dropbear/Kconfig @@ -100,6 +100,19 @@ config NETUTILS_DROPBEAR_NUTTX_CRYPTO modules, reducing flash usage. This requires a flat build because Dropbear calls the kernel crypto functions directly. +config NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY + bool "Use NuttX /dev/crypto for chacha20-poly1305" + default y + depends on NETUTILS_DROPBEAR_NUTTX_CRYPTO + select CRYPTO_CRYPTODEV + select CRYPTO_SW_AES + select CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO + ---help--- + Implement the chacha20-poly1305@openssh.com cipher through the NuttX + crypto device (/dev/crypto) using the CRYPTO_CHACHA20 and + CRYPTO_POLY1305 algorithms instead of the bundled libtomcrypt + implementation. + config NETUTILS_DROPBEAR_PORT int "Dropbear listen port" default 2222 diff --git a/netutils/dropbear/Makefile b/netutils/dropbear/Makefile index dab411d57..aa53b2878 100644 --- a/netutils/dropbear/Makefile +++ b/netutils/dropbear/Makefile @@ -68,6 +68,10 @@ CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_SHA256=1 CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_HMAC_SHA256=1 endif +ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),) +CFLAGS += ${DEFINE_PREFIX}DROPBEAR_NUTTX_CHACHAPOLY=1 +endif + dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}Channel=dropbear_channel dropbear_nshsession.c_CFLAGS += ${DEFINE_PREFIX}ChanType=dropbear_chantype @@ -138,6 +142,13 @@ CSRCS += port/dropbear_ltc_sha256.c CSRCS += port/dropbear_ltc_hmac_sha256.c endif +ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),) +# Replace the bundled chacha20-poly1305 with the /dev/crypto adapter. + +CSRCS := $(filter-out dropbear/src/chachapoly.c,$(CSRCS)) +CSRCS += port/dropbear_chachapoly.c +endif + CSRCS += $(TOMMATH_SRCS) CSRCS += $(TOMCRYPT_SRCS) @@ -149,6 +160,13 @@ endif # Match the ESP-IDF port behavior: LTC_SOURCE is only for libtomcrypt sources. $(foreach src,$(TOMCRYPT_SRCS),$(eval $(src)_CFLAGS += ${DEFINE_PREFIX}LTC_SOURCE=1)) +ifneq ($(CONFIG_NETUTILS_DROPBEAR_NUTTX_CHACHAPOLY),) +# The NuttX crypto backend pulled in by /dev/crypto also exports ecc_make_key. +# Dropbear only uses libtomcrypt's ecc_make_key_ex, so rename the unused plain +# wrapper to avoid a link-time multiple definition. +dropbear/libtomcrypt/src/pk/ecc/ecc_make_key.c_CFLAGS += ${DEFINE_PREFIX}ecc_make_key=dropbear_ltc_ecc_make_key +endif + MAINSRC = dropbear_main.c ifneq ($(CONFIG_NETUTILS_DROPBEAR_SCP),) @@ -181,6 +199,7 @@ $(DROPBEAR_UNPACKNAME): $(DROPBEAR_ZIP) $(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0003-allow-localoptions-to-override-tracking-malloc.patch; true $(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0004-use-nuttx-unused-macro.patch; true $(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0005-use-nuttx-sha256-hmac.patch; true + $(Q) $(PATCH) -s -N -l -p1 -d $(DROPBEAR_UNPACKNAME) -i $(APPDIR)$(DELIM)netutils$(DELIM)dropbear$(DELIM)patch$(DELIM)0006-use-nuttx-chachapoly-cryptodev.patch; true @echo "Generating default_options_guard.h" $(Q) sh $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)ifndef_wrapper.sh \ < $(DROPBEAR_UNPACKNAME)$(DELIM)src$(DELIM)default_options.h \ diff --git a/netutils/dropbear/patch/0006-use-nuttx-chachapoly-cryptodev.patch b/netutils/dropbear/patch/0006-use-nuttx-chachapoly-cryptodev.patch new file mode 100644 index 000000000..ef23cb5ba --- /dev/null +++ b/netutils/dropbear/patch/0006-use-nuttx-chachapoly-cryptodev.patch @@ -0,0 +1,20 @@ +--- a/src/chachapoly.h ++++ b/src/chachapoly.h +@@ -31,10 +31,17 @@ + + #if DROPBEAR_CHACHA20POLY1305 + ++#ifdef DROPBEAR_NUTTX_CHACHAPOLY ++typedef struct { ++ unsigned char key_main[32]; ++ unsigned char key_header[32]; ++} dropbear_chachapoly_state; ++#else + typedef struct { + chacha_state chacha; + chacha_state header; + } dropbear_chachapoly_state; ++#endif + + extern const struct dropbear_cipher dropbear_chachapoly; + extern const struct dropbear_cipher_mode dropbear_mode_chachapoly; diff --git a/netutils/dropbear/port/dropbear_chachapoly.c b/netutils/dropbear/port/dropbear_chachapoly.c new file mode 100644 index 000000000..2dcb10543 --- /dev/null +++ b/netutils/dropbear/port/dropbear_chachapoly.c @@ -0,0 +1,328 @@ +/**************************************************************************** + * apps/netutils/dropbear/port/dropbear_chachapoly.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "includes.h" + +#include +#include +#include +#include + +#include + +#include "algo.h" +#include "dbutil.h" +#include "chachapoly.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CHACHA20_KEY_LEN 32 +#define CHACHA20_BLOCKSIZE 8 +#define CHACHA20_IV_LEN 16 +#define POLY1305_KEY_LEN 32 +#define POLY1305_TAG_LEN 16 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct ltc_cipher_descriptor g_dropbear_chachapoly_dummy = +{ + .name = NULL +}; + +static const struct dropbear_hash g_dropbear_chachapoly_mac = +{ + NULL, + POLY1305_KEY_LEN, + POLY1305_TAG_LEN +}; + +static int g_dropbear_cryptofd = -1; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct dropbear_cipher dropbear_chachapoly = +{ + &g_dropbear_chachapoly_dummy, + CHACHA20_KEY_LEN * 2, + CHACHA20_BLOCKSIZE +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int dropbear_cryptodev_fd(void) +{ + int fd; + int cfd; + + if (g_dropbear_cryptofd >= 0) + { + return g_dropbear_cryptofd; + } + + fd = open("/dev/crypto", O_RDWR); + if (fd < 0) + { + return -1; + } + + if (ioctl(fd, CRIOGET, &cfd) < 0) + { + close(fd); + return -1; + } + + close(fd); + g_dropbear_cryptofd = cfd; + return g_dropbear_cryptofd; +} + +static int dropbear_chacha(FAR const unsigned char *key, unsigned int seq, + uint64_t counter, FAR const unsigned char *in, + FAR unsigned char *out, size_t len) +{ + struct session_op session; + struct crypt_op cryp; + unsigned char iv[CHACHA20_IV_LEN]; + int cfd; + int ret = CRYPT_ERROR; + int i; + + cfd = dropbear_cryptodev_fd(); + if (cfd < 0) + { + return CRYPT_ERROR; + } + + memset(iv, 0, sizeof(iv)); + for (i = 0; i < 8; i++) + { + iv[i] = (unsigned char)(counter >> (8 * i)); + } + + STORE64H((uint64_t)seq, iv + 8); + + memset(&session, 0, sizeof(session)); + session.cipher = CRYPTO_CHACHA20; + session.key = (caddr_t)key; + session.keylen = CHACHA20_KEY_LEN; + if (ioctl(cfd, CIOCGSESSION, &session) < 0) + { + return CRYPT_ERROR; + } + + memset(&cryp, 0, sizeof(cryp)); + cryp.ses = session.ses; + cryp.op = COP_ENCRYPT; + cryp.len = len; + cryp.src = (caddr_t)in; + cryp.dst = (caddr_t)out; + cryp.iv = (caddr_t)iv; + cryp.ivlen = sizeof(iv); + if (ioctl(cfd, CIOCCRYPT, &cryp) == 0) + { + ret = CRYPT_OK; + } + + ioctl(cfd, CIOCFSESSION, &session.ses); + return ret; +} + +static int dropbear_poly1305(FAR const unsigned char *key, + FAR const unsigned char *in, size_t len, + FAR unsigned char *tag) +{ + struct session_op session; + struct crypt_op cryp; + int cfd; + int ret = CRYPT_ERROR; + + cfd = dropbear_cryptodev_fd(); + if (cfd < 0) + { + return CRYPT_ERROR; + } + + memset(&session, 0, sizeof(session)); + session.mac = CRYPTO_POLY1305; + session.mackey = (caddr_t)key; + session.mackeylen = POLY1305_KEY_LEN; + if (ioctl(cfd, CIOCGSESSION, &session) < 0) + { + return CRYPT_ERROR; + } + + memset(&cryp, 0, sizeof(cryp)); + cryp.ses = session.ses; + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_UPDATE; + cryp.len = len; + cryp.src = (caddr_t)in; + if (ioctl(cfd, CIOCCRYPT, &cryp) == 0) + { + cryp.flags = 0; + cryp.len = 0; + cryp.mac = (caddr_t)tag; + if (ioctl(cfd, CIOCCRYPT, &cryp) == 0) + { + ret = CRYPT_OK; + } + } + + ioctl(cfd, CIOCFSESSION, &session.ses); + return ret; +} + +static int dropbear_chachapoly_start(int cipher, + FAR const unsigned char *iv, + FAR const unsigned char *key, + int keylen, int num_rounds, + FAR dropbear_chachapoly_state *state) +{ + UNUSED(cipher); + UNUSED(iv); + + if (keylen != CHACHA20_KEY_LEN * 2 || num_rounds != 0) + { + return CRYPT_ERROR; + } + + if (dropbear_cryptodev_fd() < 0) + { + return CRYPT_ERROR; + } + + memcpy(state->key_main, key, CHACHA20_KEY_LEN); + memcpy(state->key_header, key + CHACHA20_KEY_LEN, CHACHA20_KEY_LEN); + return CRYPT_OK; +} + +static int dropbear_chachapoly_crypt(unsigned int seq, + FAR const unsigned char *in, + FAR unsigned char *out, + unsigned long len, unsigned long taglen, + FAR dropbear_chachapoly_state *state, + int direction) +{ + unsigned char key[POLY1305_KEY_LEN]; + unsigned char tag[POLY1305_TAG_LEN]; + unsigned char zero[POLY1305_KEY_LEN]; + int ret = CRYPT_ERROR; + + if (len < 4 || taglen != POLY1305_TAG_LEN) + { + return CRYPT_ERROR; + } + + memset(zero, 0, sizeof(zero)); + if (dropbear_chacha(state->key_main, seq, 0, zero, key, + sizeof(key)) != CRYPT_OK) + { + goto out; + } + + if (direction == LTC_DECRYPT) + { + if (dropbear_poly1305(key, in, len, tag) != CRYPT_OK) + { + goto out; + } + + if (constant_time_memcmp(in + len, tag, sizeof(tag)) != 0) + { + goto out; + } + } + + if (dropbear_chacha(state->key_header, seq, 0, in, out, 4) != CRYPT_OK) + { + goto out; + } + + if (dropbear_chacha(state->key_main, seq, 1, in + 4, out + 4, + len - 4) != CRYPT_OK) + { + goto out; + } + + if (direction == LTC_ENCRYPT) + { + if (dropbear_poly1305(key, out, len, out + len) != CRYPT_OK) + { + goto out; + } + } + + ret = CRYPT_OK; + +out: + zeromem(key, sizeof(key)); + zeromem(tag, sizeof(tag)); + return ret; +} + +static int +dropbear_chachapoly_getlength(unsigned int seq, FAR const unsigned char *in, + FAR unsigned int *outlen, unsigned long len, + FAR dropbear_chachapoly_state *state) +{ + unsigned char buf[4]; + + if (len < sizeof(buf)) + { + return CRYPT_ERROR; + } + + if (dropbear_chacha(state->key_header, seq, 0, in, buf, + sizeof(buf)) != CRYPT_OK) + { + return CRYPT_ERROR; + } + + LOAD32H(*outlen, buf); + return CRYPT_OK; +} + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct dropbear_cipher_mode dropbear_mode_chachapoly = +{ + (void *)dropbear_chachapoly_start, + NULL, + NULL, + (void *)dropbear_chachapoly_crypt, + (void *)dropbear_chachapoly_getlength, + &g_dropbear_chachapoly_mac +};