diff --git a/netutils/dropbear/CMakeLists.txt b/netutils/dropbear/CMakeLists.txt index 8ca691be094..5e7a6237ae6 100644 --- a/netutils/dropbear/CMakeLists.txt +++ b/netutils/dropbear/CMakeLists.txt @@ -135,6 +135,13 @@ if(CONFIG_NETUTILS_DROPBEAR) file(GLOB_RECURSE LIBTOMCRYPT_SRCS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/dropbear/libtomcrypt/src/*.c") list(FILTER LIBTOMCRYPT_SRCS EXCLUDE REGEX ".*/prngs/sober128tab\\.c$") + + # Drop the bundled libtomcrypt HMAC modules replaced by the NuttX adapter. + list(FILTER LIBTOMCRYPT_SRCS EXCLUDE REGEX ".*/mac/hmac/hmac_init\\.c$") + list(FILTER LIBTOMCRYPT_SRCS EXCLUDE REGEX ".*/mac/hmac/hmac_process\\.c$") + list(FILTER LIBTOMCRYPT_SRCS EXCLUDE REGEX ".*/mac/hmac/hmac_done\\.c$") + list(APPEND DROPBEAR_SRCS port/dropbear_ltc_hmac_sha256.c) + list(APPEND DROPBEAR_SRCS ${LIBTOMCRYPT_SRCS}) if(CONFIG_NETUTILS_DROPBEAR_SCP) @@ -225,6 +232,15 @@ if(CONFIG_NETUTILS_DROPBEAR) set_source_files_properties(${LIBTOMCRYPT_SRCS} PROPERTIES COMPILE_DEFINITIONS LTC_SOURCE=1) + # 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) + 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 8e7c0868e7c..fa93e6605b9 100644 --- a/netutils/dropbear/Kconfig +++ b/netutils/dropbear/Kconfig @@ -17,13 +17,23 @@ menuconfig NETUTILS_DROPBEAR depends on DEV_URANDOM depends on LIBC_NETDB depends on LIBC_GAISTRERROR - select CRYPTO + depends on ALLOW_BSD_COMPONENTS + depends on CRYPTO_CRYPTODEV + depends on CRYPTO_CRYPTODEV_SOFTWARE_CRYPTO select CRYPTO_RANDOM_POOL ---help--- Enable a minimal Dropbear SSH server port for NuttX. This initial port is based on the ESP-IDF MCU test port and provides a single foreground SSH server process with SSH sessions backed by NSH. + The port computes the hmac-sha2-256 packet MAC through the NuttX + crypto device (/dev/crypto, CRYPTO_SHA2_256_HMAC) instead of the + bundled libtomcrypt implementation, which is dropped from the + build. The SHA-256 hash descriptor itself stays in the + application: Dropbear's key derivation clones partially-updated + hash states (hashkeys() in common-kex.c), which cannot be + represented by a kernel crypto session. + if NETUTILS_DROPBEAR config NETUTILS_DROPBEAR_STACKSIZE diff --git a/netutils/dropbear/Makefile b/netutils/dropbear/Makefile index 53b1f2f720b..3012edc2963 100644 --- a/netutils/dropbear/Makefile +++ b/netutils/dropbear/Makefile @@ -119,6 +119,16 @@ CSRCS += \ TOMMATH_SRCS = $(shell if [ -d "$(DROPBEAR_UNPACKNAME)/libtommath" ]; then find "$(DROPBEAR_UNPACKNAME)/libtommath" -name "*.c"; fi) TOMCRYPT_SRCS = $(shell if [ -d "$(DROPBEAR_UNPACKNAME)/libtomcrypt/src" ]; then find "$(DROPBEAR_UNPACKNAME)/libtomcrypt/src" -name "*.c" ! -name "sober128tab.c"; fi) +# Drop the bundled libtomcrypt HMAC modules replaced by the NuttX adapter. + +TOMCRYPT_SRCS := $(filter-out \ + %/mac/hmac/hmac_init.c \ + %/mac/hmac/hmac_process.c \ + %/mac/hmac/hmac_done.c, \ + $(TOMCRYPT_SRCS)) + +CSRCS += port/dropbear_ltc_hmac_sha256.c + CSRCS += $(TOMMATH_SRCS) CSRCS += $(TOMCRYPT_SRCS) @@ -130,6 +140,11 @@ 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)) +# 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 + MAINSRC = dropbear_main.c ifneq ($(CONFIG_NETUTILS_DROPBEAR_SCP),) diff --git a/netutils/dropbear/port/dropbear_ltc_hmac_sha256.c b/netutils/dropbear/port/dropbear_ltc_hmac_sha256.c new file mode 100644 index 00000000000..52f796c0057 --- /dev/null +++ b/netutils/dropbear/port/dropbear_ltc_hmac_sha256.c @@ -0,0 +1,227 @@ +/**************************************************************************** + * apps/netutils/dropbear/port/dropbear_ltc_hmac_sha256.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. + * + ****************************************************************************/ + +/* LibTomCrypt-compatible incremental HMAC API backed by a + * CRYPTO_SHA2_256_HMAC /dev/crypto session (hmac-sha2-256, the only MAC the + * NuttX Dropbear configuration enables): init opens the session, process + * feeds data with COP_FLAG_UPDATE, done reads the tag and frees the session. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "includes.h" + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DROPBEAR_HMAC_SHA256_DIGESTLEN 32 +#define DROPBEAR_HMAC_SHA256_BLOCKLEN 64 + +/* Stash the /dev/crypto session id in the unused md hash-state buffer so the + * upstream hmac_state needs no patch (hash index uses the existing field). + */ + +#define HMAC_SES(h) (*(FAR unsigned int *)&(h)->md) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int g_dropbear_hmac_cryptofd = -1; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int dropbear_hmac_cryptodev_fd(void) +{ + int fd; + int cfd; + + if (g_dropbear_hmac_cryptofd >= 0) + { + return g_dropbear_hmac_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_hmac_cryptofd = cfd; + return g_dropbear_hmac_cryptofd; +} + +static int dropbear_hmac_hash_is_sha256(int hash) +{ + int ret; + + ret = hash_is_valid(hash); + if (ret != CRYPT_OK) + { + return ret; + } + + if (hash_descriptor[hash].hashsize != DROPBEAR_HMAC_SHA256_DIGESTLEN || + hash_descriptor[hash].blocksize != DROPBEAR_HMAC_SHA256_BLOCKLEN) + { + return CRYPT_INVALID_HASH; + } + + return CRYPT_OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, + unsigned long keylen) +{ + struct session_op session; + int cfd; + int ret; + + LTC_ARGCHK(hmac != NULL); + LTC_ARGCHK(key != NULL); + + if (keylen == 0) + { + return CRYPT_INVALID_KEYSIZE; + } + + ret = dropbear_hmac_hash_is_sha256(hash); + if (ret != CRYPT_OK) + { + return ret; + } + + cfd = dropbear_hmac_cryptodev_fd(); + if (cfd < 0) + { + return CRYPT_ERROR; + } + + memset(&session, 0, sizeof(session)); + session.mac = CRYPTO_SHA2_256_HMAC; + session.mackey = (caddr_t)key; + session.mackeylen = keylen; + if (ioctl(cfd, CIOCGSESSION, &session) < 0) + { + return CRYPT_ERROR; + } + + hmac->hash = hash; + HMAC_SES(hmac) = session.ses; + return CRYPT_OK; +} + +int hmac_process(hmac_state *hmac, const unsigned char *in, + unsigned long inlen) +{ + struct crypt_op cryp; + int cfd; + + LTC_ARGCHK(hmac != NULL); + LTC_ARGCHK(in != NULL || inlen == 0); + + cfd = dropbear_hmac_cryptodev_fd(); + if (cfd < 0) + { + return CRYPT_ERROR; + } + + memset(&cryp, 0, sizeof(cryp)); + cryp.ses = HMAC_SES(hmac); + cryp.op = COP_ENCRYPT; + cryp.flags = COP_FLAG_UPDATE; + cryp.len = inlen; + cryp.src = (caddr_t)in; + if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) + { + return CRYPT_ERROR; + } + + return CRYPT_OK; +} + +int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen) +{ + unsigned char digest[DROPBEAR_HMAC_SHA256_DIGESTLEN]; + struct crypt_op cryp; + unsigned long copylen; + int cfd; + int ret = CRYPT_ERROR; + + LTC_ARGCHK(hmac != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + cfd = dropbear_hmac_cryptodev_fd(); + if (cfd < 0) + { + goto out; + } + + memset(&cryp, 0, sizeof(cryp)); + cryp.ses = HMAC_SES(hmac); + cryp.op = COP_ENCRYPT; + cryp.len = 0; + cryp.mac = (caddr_t)digest; + if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) + { + goto out; + } + + copylen = MIN(*outlen, DROPBEAR_HMAC_SHA256_DIGESTLEN); + memcpy(out, digest, copylen); + *outlen = copylen; + ret = CRYPT_OK; + +out: + if (cfd >= 0) + { + ioctl(cfd, CIOCFSESSION, &HMAC_SES(hmac)); + } + + zeromem(digest, sizeof(digest)); + zeromem(hmac, sizeof(*hmac)); + return ret; +}