From 62ea53c1e5c5d9a96263c966e20b6d6ffd764b41 Mon Sep 17 00:00:00 2001 From: Egor Duda Date: Sat, 11 Jun 2022 13:35:06 +0300 Subject: [PATCH] Implement no-touch-required and verify-requred for authorized_keys file --- auth.h | 4 ++++ signkey.c | 4 ++-- signkey.h | 1 + sk-ecdsa.c | 13 ++++++++++--- sk-ecdsa.h | 4 +++- sk-ed25519.c | 13 ++++++++++--- sk-ed25519.h | 4 +++- svr-authpubkey.c | 10 ++++++++++ svr-authpubkeyoptions.c | 14 ++++++++++++++ 9 files changed, 57 insertions(+), 10 deletions(-) diff --git a/auth.h b/auth.h index 2063cad..6bfabc7 100644 --- a/auth.h +++ b/auth.h @@ -139,6 +139,10 @@ struct PubKeyOptions { int no_pty_flag; /* "command=" option. */ char * forced_command; +#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 + int no_touch_required_flag; + int verify_required_flag; +#endif }; #endif diff --git a/signkey.c b/signkey.c index b2f436d..378957d 100644 --- a/signkey.c +++ b/signkey.c @@ -688,7 +688,7 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) { ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); if (eck && *eck) { - return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen); + return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask); } } #endif @@ -696,7 +696,7 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) { dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype); if (eck && *eck) { - return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen); + return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask); } } #endif diff --git a/signkey.h b/signkey.h index cc7fd8b..5bc7e7b 100644 --- a/signkey.h +++ b/signkey.h @@ -127,6 +127,7 @@ struct SIGN_key { /* application ID for U2F/FIDO key types, a malloced string */ char * sk_app; unsigned int sk_applen; + unsigned char sk_flags_mask; #endif }; diff --git a/sk-ecdsa.c b/sk-ecdsa.c index bd4d353..bed7e50 100644 --- a/sk-ecdsa.c +++ b/sk-ecdsa.c @@ -8,7 +8,9 @@ #include "sk-ecdsa.h" #include "ssh.h" -int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen) { +int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, + const char* app, unsigned int applen, + unsigned char sk_flags_mask) { hash_state hs; unsigned char subhash[SHA256_HASH_SIZE]; buffer *sk_buffer = NULL, *sig_buffer = NULL; @@ -41,13 +43,18 @@ int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, buf_free(sk_buffer); buf_free(sig_buffer); - /* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */ - if (!(flags & SSH_SK_USER_PRESENCE_REQD)) { + if (~flags & sk_flags_mask & SSH_SK_USER_PRESENCE_REQD) { if (ret == DROPBEAR_SUCCESS) { dropbear_log(LOG_WARNING, "Rejecting, user-presence not set"); } ret = DROPBEAR_FAILURE; } + if (~flags & sk_flags_mask & SSH_SK_USER_VERIFICATION_REQD) { + if (ret == DROPBEAR_SUCCESS) { + dropbear_log(LOG_WARNING, "Rejecting, user-verification not set"); + } + ret = DROPBEAR_FAILURE; + } TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret)) return ret; diff --git a/sk-ecdsa.h b/sk-ecdsa.h index 7a01305..e883bf8 100644 --- a/sk-ecdsa.h +++ b/sk-ecdsa.h @@ -8,7 +8,9 @@ #include "buffer.h" #include "signkey.h" -int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen); +int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, + const char* app, unsigned int applen, + unsigned char sk_flags_mask); #endif diff --git a/sk-ed25519.c b/sk-ed25519.c index 902a5e6..b4827e3 100644 --- a/sk-ed25519.c +++ b/sk-ed25519.c @@ -8,7 +8,9 @@ #include "ed25519.h" #include "ssh.h" -int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen) { +int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, + const char* app, unsigned int applen, + unsigned char sk_flags_mask) { int ret = DROPBEAR_FAILURE; unsigned char *s; @@ -52,13 +54,18 @@ int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const bu ret = DROPBEAR_SUCCESS; } - /* TODO: allow "no-touch-required" or "verify-required" authorized_keys options */ - if (!(flags & SSH_SK_USER_PRESENCE_REQD)) { + if (~flags & sk_flags_mask & SSH_SK_USER_PRESENCE_REQD) { if (ret == DROPBEAR_SUCCESS) { dropbear_log(LOG_WARNING, "Rejecting, user-presence not set"); } ret = DROPBEAR_FAILURE; } + if (~flags & sk_flags_mask & SSH_SK_USER_VERIFICATION_REQD) { + if (ret == DROPBEAR_SUCCESS) { + dropbear_log(LOG_WARNING, "Rejecting, user-verification not set"); + } + ret = DROPBEAR_FAILURE; + } out: buf_free(sk_buffer); TRACE(("leave buf_sk_ed25519_verify: ret %d", ret)) diff --git a/sk-ed25519.h b/sk-ed25519.h index ad8561e..74ab7c8 100644 --- a/sk-ed25519.h +++ b/sk-ed25519.h @@ -8,7 +8,9 @@ #include "buffer.h" #include "ed25519.h" -int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, const char* app, unsigned int applen); +int buf_sk_ed25519_verify(buffer *buf, const dropbear_ed25519_key *key, const buffer *data_buf, + const char* app, unsigned int applen, + unsigned char sk_flags_mask); #endif diff --git a/svr-authpubkey.c b/svr-authpubkey.c index 5c4ef4d..59a40c5 100644 --- a/svr-authpubkey.c +++ b/svr-authpubkey.c @@ -182,6 +182,16 @@ void svr_auth_pubkey(int valid_user) { goto out; } +#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 + key->sk_flags_mask = SSH_SK_USER_PRESENCE_REQD; + if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->no_touch_required_flag) { + key->sk_flags_mask &= ~SSH_SK_USER_PRESENCE_REQD; + } + if (ses.authstate.pubkey_options && ses.authstate.pubkey_options->verify_required_flag) { + key->sk_flags_mask |= SSH_SK_USER_VERIFICATION_REQD; + } +#endif + /* create the data which has been signed - this a string containing * session_id, concatenated with the payload packet up to the signature */ assert(ses.payload_beginning <= ses.payload->pos); diff --git a/svr-authpubkeyoptions.c b/svr-authpubkeyoptions.c index 447f4b7..dfffe8c 100644 --- a/svr-authpubkeyoptions.c +++ b/svr-authpubkeyoptions.c @@ -205,6 +205,20 @@ int svr_add_pubkey_options(buffer *options_buf, int line_num, const char* filena dropbear_log(LOG_WARNING, "Badly formatted command= authorized_keys option"); goto bad_option; } + if (match_option(options_buf, "no-touch-required") == DROPBEAR_SUCCESS) { +#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 + dropbear_log(LOG_WARNING, "No user presence check required for U2F/FIDO key."); + ses.authstate.pubkey_options->no_touch_required_flag = 1; +#endif + goto next_option; + } + if (match_option(options_buf, "verify-required") == DROPBEAR_SUCCESS) { +#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 + dropbear_log(LOG_WARNING, "User verification required for U2F/FIDO key."); + ses.authstate.pubkey_options->verify_required_flag = 1; +#endif + goto next_option; + } next_option: /*