mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-09-08 09:46:31 +00:00
netutils/dropbear: add Dropbear SSH server port for NuttX
Integrated SSH daemon authenticating against FSUTILS_PASSWD, with an ECDSA P-256 host key and an NSH session over a PTY per connection. Built from the upstream Dropbear tarball (pinned commit) and patched for NuttX, using Dropbear's bundled libtomcrypt for all crypto. setsid() (apache/nuttx#19184) and link() now come from NuttX, not local stubs. Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
This commit is contained in:
parent
e44c4f370f
commit
fee2ddbf54
24 changed files with 2449 additions and 1 deletions
|
|
@ -0,0 +1,26 @@
|
|||
--- a/src/dbutil.c
|
||||
+++ b/src/dbutil.c
|
||||
@@ -66,6 +66,10 @@
|
||||
#include "session.h"
|
||||
#include "atomicio.h"
|
||||
|
||||
+#ifdef DROPBEAR_NUTTX
|
||||
+int execv(const char *path, char * const argv[]);
|
||||
+#endif
|
||||
+
|
||||
#define MAX_FMT 100
|
||||
|
||||
static void generic_dropbear_exit(int exitcode, const char* format,
|
||||
--- a/src/signkey.h
|
||||
+++ b/src/signkey.h
|
||||
@@ -150,9 +150,9 @@
|
||||
void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, const buffer *data_buf);
|
||||
#if DROPBEAR_SIGNKEY_VERIFY
|
||||
int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf);
|
||||
int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen);
|
||||
-char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
|
||||
#endif
|
||||
+char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen);
|
||||
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
|
||||
const unsigned char* algoname, unsigned int algolen,
|
||||
const buffer * line, char ** fingerprint);
|
||||
87
netutils/dropbear/patch/0002-use-nuttx-passwd-auth.patch
Normal file
87
netutils/dropbear/patch/0002-use-nuttx-passwd-auth.patch
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
--- a/src/svr-authpasswd.c
|
||||
+++ b/src/svr-authpasswd.c
|
||||
@@ -33,6 +33,77 @@
|
||||
|
||||
#if DROPBEAR_SVR_PASSWORD_AUTH
|
||||
|
||||
+#if DROPBEAR_NUTTX_PASSWD
|
||||
+
|
||||
+/* Process a password auth request, sending success or failure messages as
|
||||
+ * appropriate */
|
||||
+void svr_auth_password(int valid_user) {
|
||||
+
|
||||
+ char * password = NULL;
|
||||
+ unsigned int passwordlen;
|
||||
+ unsigned int changepw;
|
||||
+ int auth_ok = 0;
|
||||
+
|
||||
+ /* check if client wants to change password */
|
||||
+ changepw = buf_getbool(ses.payload);
|
||||
+ if (changepw) {
|
||||
+ /* not implemented by this server */
|
||||
+ send_msg_userauth_failure(0, 1);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ password = buf_getstring(ses.payload, &passwordlen);
|
||||
+ if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN &&
|
||||
+ strlen(password) == passwordlen) {
|
||||
+ auth_ok = dropbear_verify_password(ses.authstate.pw_name, password);
|
||||
+ }
|
||||
+ m_burn(password, passwordlen);
|
||||
+ m_free(password);
|
||||
+
|
||||
+ /* After we have got the payload contents we can exit if the username
|
||||
+ is invalid. Invalid users have already been logged. */
|
||||
+ if (!valid_user) {
|
||||
+ send_msg_userauth_failure(0, 1);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (passwordlen > DROPBEAR_MAX_PASSWORD_LEN) {
|
||||
+ dropbear_log(LOG_WARNING,
|
||||
+ "Too-long password attempt for '%s' from %s",
|
||||
+ ses.authstate.pw_name,
|
||||
+ svr_ses.addrstring);
|
||||
+ send_msg_userauth_failure(0, 1);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (auth_ok == DROPBEAR_SUCCESS) {
|
||||
+ if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
|
||||
+ /* successful password authentication, but extra auth required */
|
||||
+ dropbear_log(LOG_NOTICE,
|
||||
+ "Password auth succeeded for '%s' from %s, extra auth required",
|
||||
+ ses.authstate.pw_name,
|
||||
+ svr_ses.addrstring);
|
||||
+ ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* password auth ok, delete the method flag */
|
||||
+ send_msg_userauth_failure(1, 0); /* Send partial success */
|
||||
+ } else {
|
||||
+ /* successful authentication */
|
||||
+ dropbear_log(LOG_NOTICE,
|
||||
+ "Password auth succeeded for '%s' from %s",
|
||||
+ ses.authstate.pw_name,
|
||||
+ svr_ses.addrstring);
|
||||
+ send_msg_userauth_success();
|
||||
+ }
|
||||
+ } else {
|
||||
+ dropbear_log(LOG_WARNING,
|
||||
+ "Bad password attempt for '%s' from %s",
|
||||
+ ses.authstate.pw_name,
|
||||
+ svr_ses.addrstring);
|
||||
+ send_msg_userauth_failure(0, 1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
/* not constant time when strings are differing lengths.
|
||||
string content isn't leaked, and crypt hashes are predictable length. */
|
||||
static int constant_time_strcmp(const char* a, const char* b) {
|
||||
@@ -131,4 +202,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
+#endif /* DROPBEAR_NUTTX_PASSWD */
|
||||
+
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
--- a/src/sysoptions.h
|
||||
+++ b/src/sysoptions.h
|
||||
@@ -183,7 +183,9 @@ defined(__has_feature)
|
||||
#define LTC_ECC521
|
||||
#endif
|
||||
|
||||
-#define DROPBEAR_LTC_PRNG (DROPBEAR_ECC)
|
||||
+#ifndef DROPBEAR_LTC_PRNG
|
||||
+#define DROPBEAR_LTC_PRNG (DROPBEAR_ECC)
|
||||
+#endif
|
||||
|
||||
/* RSA can be vulnerable to timing attacks which use the time required for
|
||||
* signing to guess the private key. Blinding avoids this attack, though makes
|
||||
@@ -436,7 +438,9 @@ defined(__has_feature)
|
||||
#define DROPBEAR_CLIENT_TCP_FAST_OPEN 0
|
||||
#endif
|
||||
|
||||
-#define DROPBEAR_TRACKING_MALLOC (DROPBEAR_FUZZ)
|
||||
+#ifndef DROPBEAR_TRACKING_MALLOC
|
||||
+#define DROPBEAR_TRACKING_MALLOC (DROPBEAR_FUZZ)
|
||||
+#endif
|
||||
|
||||
/* Used to work around Memory Sanitizer false positives */
|
||||
#if defined(__has_feature)
|
||||
202
netutils/dropbear/patch/0004-use-nuttx-unused-macro.patch
Normal file
202
netutils/dropbear/patch/0004-use-nuttx-unused-macro.patch
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
--- a/src/compat.c
|
||||
+++ b/src/compat.c
|
||||
@@ -89,6 +89,6 @@
|
||||
#ifndef HAVE_GETUSERSHELL
|
||||
static char **curshell, **shells, *strings;
|
||||
-static char **initshells();
|
||||
+static char **initshells(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
@@ -234,7 +234,7 @@
|
||||
curshell = initshells();
|
||||
}
|
||||
|
||||
-static char **initshells() {
|
||||
+static char **initshells(void) {
|
||||
static const char *okshells[] = { COMPAT_USER_SHELLS, NULL };
|
||||
register char **sp, *cp;
|
||||
register FILE *fp;
|
||||
--- a/src/common-algo.c
|
||||
+++ b/src/common-algo.c
|
||||
@@ -39,16 +39,25 @@
|
||||
/* This file (algo.c) organises the ciphers which can be used, and is used to
|
||||
* decide which ciphers/hashes/compression/signing to use during key exchange*/
|
||||
|
||||
-static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
- unsigned long len, void* UNUSED(cipher_state)) {
|
||||
+static int void_cipher(const unsigned char* in, unsigned char* out,
|
||||
+ unsigned long len, void* cipher_state) {
|
||||
+ UNUSED(cipher_state);
|
||||
+
|
||||
if (in != out) {
|
||||
memmove(out, in, len);
|
||||
}
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
-static int void_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
- const unsigned char* UNUSED(key),
|
||||
- int UNUSED(keylen), int UNUSED(num_rounds), void* UNUSED(cipher_state)) {
|
||||
+static int void_start(int cipher, const unsigned char* IV,
|
||||
+ const unsigned char* key,
|
||||
+ int keylen, int num_rounds, void* cipher_state) {
|
||||
+ UNUSED(cipher);
|
||||
+ UNUSED(IV);
|
||||
+ UNUSED(key);
|
||||
+ UNUSED(keylen);
|
||||
+ UNUSED(num_rounds);
|
||||
+ UNUSED(cipher_state);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
--- a/src/common-channel.c
|
||||
+++ b/src/common-channel.c
|
||||
@@ -410,7 +410,9 @@
|
||||
|
||||
#ifndef HAVE_WRITEV
|
||||
static int writechannel_fallback(struct Channel* channel, int fd, circbuffer *cbuf,
|
||||
- const unsigned char *UNUSED(moredata), unsigned int *morelen) {
|
||||
+ const unsigned char *moredata, unsigned int *morelen) {
|
||||
+ UNUSED(moredata);
|
||||
+
|
||||
|
||||
unsigned char *circ_p1, *circ_p2;
|
||||
unsigned int circ_len1, circ_len2;
|
||||
--- a/src/dbutil.c
|
||||
+++ b/src/dbutil.c
|
||||
@@ -138,7 +138,9 @@
|
||||
}
|
||||
|
||||
-static void generic_dropbear_log(int UNUSED(priority), const char* format,
|
||||
+static void generic_dropbear_log(int priority, const char* format,
|
||||
va_list param) {
|
||||
+ UNUSED(priority);
|
||||
+
|
||||
|
||||
char printbuf[1024];
|
||||
|
||||
--- a/src/netio.c
|
||||
+++ b/src/netio.c
|
||||
@@ -47,7 +47,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
-static void cancel_callback(int result, int sock, void* UNUSED(data), const char* UNUSED(errstring)) {
|
||||
+static void cancel_callback(int result, int sock, void* data, const char* errstring) {
|
||||
+ UNUSED(data);
|
||||
+ UNUSED(errstring);
|
||||
+
|
||||
if (result == DROPBEAR_SUCCESS)
|
||||
{
|
||||
m_close(sock);
|
||||
--- a/src/ltc_prng.c
|
||||
+++ b/src/ltc_prng.c
|
||||
@@ -32,8 +32,10 @@
|
||||
@param prng [out] The PRNG state to initialize
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_start(prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_start(prng_state* prng)
|
||||
{
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -44,8 +46,12 @@
|
||||
@param prng PRNG state to update
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_add_entropy(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_add_entropy(const unsigned char* in, unsigned long inlen, prng_state* prng)
|
||||
{
|
||||
+ UNUSED(in);
|
||||
+ UNUSED(inlen);
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -54,8 +60,10 @@
|
||||
@param prng The PRNG to make active
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_ready(prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_ready(prng_state* prng)
|
||||
{
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -66,8 +74,10 @@
|
||||
@param prng The active PRNG to read from
|
||||
@return Number of octets read
|
||||
*/
|
||||
-unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* UNUSED(prng))
|
||||
+unsigned long dropbear_prng_read(unsigned char* out, unsigned long outlen, prng_state* prng)
|
||||
{
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
LTC_ARGCHK(out != NULL);
|
||||
genrandom(out, outlen);
|
||||
return outlen;
|
||||
@@ -78,8 +88,10 @@
|
||||
@param prng The PRNG to terminate
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_done(prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_done(prng_state* prng)
|
||||
{
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
@@ -90,8 +102,11 @@
|
||||
@param prng The PRNG to export
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_export(unsigned char* UNUSED(out), unsigned long* outlen, prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_export(unsigned char* out, unsigned long* outlen, prng_state* prng)
|
||||
{
|
||||
+ UNUSED(out);
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
LTC_ARGCHK(outlen != NULL);
|
||||
|
||||
*outlen = 0;
|
||||
@@ -105,8 +120,12 @@
|
||||
@param prng The PRNG to import
|
||||
@return CRYPT_OK if successful
|
||||
*/
|
||||
-int dropbear_prng_import(const unsigned char* UNUSED(in), unsigned long UNUSED(inlen), prng_state* UNUSED(prng))
|
||||
+int dropbear_prng_import(const unsigned char* in, unsigned long inlen, prng_state* prng)
|
||||
{
|
||||
+ UNUSED(in);
|
||||
+ UNUSED(inlen);
|
||||
+ UNUSED(prng);
|
||||
+
|
||||
return CRYPT_OK;
|
||||
}
|
||||
|
||||
--- a/src/chachapoly.c
|
||||
+++ b/src/chachapoly.c
|
||||
@@ -43,9 +43,13 @@
|
||||
const struct dropbear_cipher dropbear_chachapoly =
|
||||
{&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE};
|
||||
|
||||
-static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV),
|
||||
+static int dropbear_chachapoly_start(int cipher, const unsigned char* IV,
|
||||
const unsigned char *key, int keylen,
|
||||
- int UNUSED(num_rounds), dropbear_chachapoly_state *state) {
|
||||
+ int num_rounds, dropbear_chachapoly_state *state) {
|
||||
+ UNUSED(cipher);
|
||||
+ UNUSED(IV);
|
||||
+ UNUSED(num_rounds);
|
||||
+
|
||||
int err;
|
||||
|
||||
TRACE2(("enter dropbear_chachapoly_start"))
|
||||
Loading…
Add table
Add a link
Reference in a new issue