Implement server-side support for sk-ed25519 FIDO2-backed keys

This commit is contained in:
Egor Duda 2022-01-16 00:50:39 +03:00
parent 0c62c0db7f
commit 2ad020ff30
No known key found for this signature in database
GPG Key ID: 8610EBBBC18A37F1
12 changed files with 161 additions and 28 deletions

View File

@ -36,7 +36,7 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
queue.o \ queue.o \
atomicio.o compat.o fake-rfc2553.o \ atomicio.o compat.o fake-rfc2553.o \
ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \ ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \
curve25519.o ed25519.o \ curve25519.o ed25519.o sk-ed25519.o \
dbmalloc.o \ dbmalloc.o \
gensignkey.o gendss.o genrsa.o gened25519.o gensignkey.o gendss.o genrsa.o gened25519.o

View File

@ -239,6 +239,9 @@ algo_type ssh_nocompress[] = {
algo_type sigalgs[] = { algo_type sigalgs[] = {
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
{"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL}, {"ssh-ed25519", DROPBEAR_SIGNATURE_ED25519, NULL, 1, NULL},
#if DROPBEAR_SK_ED25519
{"sk-ssh-ed25519@openssh.com", DROPBEAR_SIGNATURE_SK_ED25519, NULL, 1, NULL},
#endif
#endif #endif
#if DROPBEAR_ECDSA #if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256 #if DROPBEAR_ECC_256

View File

@ -130,6 +130,7 @@ IMPORTANT: Some options will require "make clean" after changes */
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases /* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
binary size - around 7,5kB on x86-64 */ binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1 #define DROPBEAR_ED25519 1
#define DROPBEAR_SK_ED25519 1
/* RSA must be >=1024 */ /* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048 #define DROPBEAR_DEFAULT_RSA_SIZE 2048

View File

@ -38,14 +38,18 @@
* The key will have the same format as buf_put_ed25519_key. * The key will have the same format as buf_put_ed25519_key.
* These should be freed with ed25519_key_free. * These should be freed with ed25519_key_free.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key) { int buf_get_ed25519_pub_key(buffer *buf, dropbear_ed25519_key *key, int sk) {
unsigned int len; unsigned int len;
TRACE(("enter buf_get_ed25519_pub_key")) TRACE(("enter buf_get_ed25519_pub_key"))
dropbear_assert(key != NULL); dropbear_assert(key != NULL);
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */ if (sk) {
buf_incrpos(buf, 30); /* int + "sk-ssh-ed25519@openssh.com" */
} else {
buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
}
len = buf_getint(buf); len = buf_getint(buf);
if (len != CURVE25519_LEN || buf->len - buf->pos < len) { if (len != CURVE25519_LEN || buf->len - buf->pos < len) {

View File

@ -43,7 +43,7 @@ void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const bu
#if DROPBEAR_SIGNKEY_VERIFY #if DROPBEAR_SIGNKEY_VERIFY
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf); int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
#endif #endif
int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key); int buf_get_ed25519_pub_key(buffer* buf, dropbear_ed25519_key *key, int sk);
int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key); int buf_get_ed25519_priv_key(buffer* buf, dropbear_ed25519_key *key);
void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key); void buf_put_ed25519_pub_key(buffer* buf, const dropbear_ed25519_key *key);
void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key); void buf_put_ed25519_priv_key(buffer* buf, const dropbear_ed25519_key *key);

View File

@ -29,6 +29,7 @@
#include "ssh.h" #include "ssh.h"
#include "ecdsa.h" #include "ecdsa.h"
#include "sk-ecdsa.h" #include "sk-ecdsa.h"
#include "sk-ed25519.h"
#include "rsa.h" #include "rsa.h"
#include "dss.h" #include "dss.h"
#include "ed25519.h" #include "ed25519.h"
@ -44,10 +45,15 @@ static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
"ecdsa-sha2-nistp256", "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384", "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521", "ecdsa-sha2-nistp521",
#if DROPBEAR_SK_ECDSA
"sk-ecdsa-sha2-nistp256@openssh.com", "sk-ecdsa-sha2-nistp256@openssh.com",
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */ #endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
"ssh-ed25519", "ssh-ed25519",
#if DROPBEAR_SK_ED25519
"sk-ssh-ed25519@openssh.com",
#endif /* DROPBEAR_SK_ED25519 */
#endif /* DROPBEAR_ED25519 */ #endif /* DROPBEAR_ED25519 */
/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */ /* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
}; };
@ -182,12 +188,17 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
switch (type) { switch (type) {
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519: case DROPBEAR_SIGNKEY_ED25519:
#if DROPBEAR_SK_ED25519
case DROPBEAR_SIGNKEY_SK_ED25519:
#endif
return (void**)&key->ed25519key; return (void**)&key->ed25519key;
#endif #endif
#if DROPBEAR_ECDSA #if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256 #if DROPBEAR_ECC_256
case DROPBEAR_SIGNKEY_ECDSA_NISTP256: case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
#if DROPBEAR_SK_ECDSA
case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256: case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256:
#endif
return (void**)&key->ecckey256; return (void**)&key->ecckey256;
#endif #endif
#if DROPBEAR_ECC_384 #if DROPBEAR_ECC_384
@ -221,6 +232,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
unsigned int len; unsigned int len;
enum signkey_type keytype; enum signkey_type keytype;
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
int is_sk = 0;
TRACE2(("enter buf_get_pub_key")) TRACE2(("enter buf_get_pub_key"))
@ -265,7 +277,7 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
#if DROPBEAR_ECDSA #if DROPBEAR_ECDSA
if (signkey_is_ecdsa(keytype) if (signkey_is_ecdsa(keytype)
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA
|| signkey_is_sk_ecdsa(keytype) || keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
#endif #endif
) { ) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
@ -283,10 +295,19 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
} }
#endif #endif
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
if (keytype == DROPBEAR_SIGNKEY_ED25519) { if (keytype == DROPBEAR_SIGNKEY_ED25519
#if DROPBEAR_SK_ED25519
|| keytype == DROPBEAR_SIGNKEY_SK_ED25519
#endif
) {
#if DROPBEAR_SK_ED25519
if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) {
is_sk = 1;
}
#endif
ed25519_key_free(key->ed25519key); ed25519_key_free(key->ed25519key);
key->ed25519key = m_malloc(sizeof(*key->ed25519key)); key->ed25519key = m_malloc(sizeof(*key->ed25519key));
ret = buf_get_ed25519_pub_key(buf, key->ed25519key); ret = buf_get_ed25519_pub_key(buf, key->ed25519key, is_sk);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
m_free(key->ed25519key); m_free(key->ed25519key);
key->ed25519key = NULL; key->ed25519key = NULL;
@ -408,7 +429,11 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
} }
#endif #endif
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
if (type == DROPBEAR_SIGNKEY_ED25519) { if (type == DROPBEAR_SIGNKEY_ED25519
#if DROPBEAR_SK_ED25519
|| type == DROPBEAR_SIGNKEY_SK_ED25519
#endif
) {
buf_put_ed25519_pub_key(pubkeys, key->ed25519key); buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
} }
#endif #endif
@ -647,7 +672,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
#if DROPBEAR_SIGNKEY_VERIFY #if DROPBEAR_SIGNKEY_VERIFY
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen) { int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf, char* app, unsigned int applen) {
@ -669,12 +694,22 @@ int sk_buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtyp
keytype = signkey_type_from_signature(sigtype); keytype = signkey_type_from_signature(sigtype);
if (signkey_is_sk_ecdsa(keytype)) { #if DROPBEAR_SK_ECDSA
if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck && *eck) { if (eck && *eck) {
return buf_sk_ecdsa_verify(buf, *eck, data_buf, app, applen); return buf_sk_ecdsa_verify(buf, *eck, data_buf, app, applen);
} }
} }
#endif
#if DROPBEAR_SK_ED25519
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, app, applen);
}
}
#endif
dropbear_exit("Non-matching signing type"); dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }

View File

@ -44,10 +44,15 @@ enum signkey_type {
DROPBEAR_SIGNKEY_ECDSA_NISTP256, DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNKEY_ECDSA_NISTP384, DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNKEY_ECDSA_NISTP521, DROPBEAR_SIGNKEY_ECDSA_NISTP521,
#if DROPBEAR_SK_ECDSA
DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256, DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */ #endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
DROPBEAR_SIGNKEY_ED25519, DROPBEAR_SIGNKEY_ED25519,
#if DROPBEAR_SK_ED25519
DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif #endif
DROPBEAR_SIGNKEY_NUM_NAMED, DROPBEAR_SIGNKEY_NUM_NAMED,
DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */ DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
@ -64,10 +69,15 @@ enum signature_type {
DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256, DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384, DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521, DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521,
#if DROPBEAR_SK_ECDSA
DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256, DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */ #endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519 #if DROPBEAR_ED25519
DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519, DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519,
#if DROPBEAR_SK_ED25519
DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif #endif
#if DROPBEAR_RSA_SHA1 #if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */ DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */

View File

@ -1,16 +1,12 @@
#include "includes.h" #include "includes.h"
#if DROPBEAR_SK_ECDSA
#include "dbutil.h" #include "dbutil.h"
#include "ecc.h" #include "ecc.h"
#include "ecdsa.h" #include "ecdsa.h"
#include "sk-ecdsa.h" #include "sk-ecdsa.h"
#if DROPBEAR_SK_ECDSA
int signkey_is_sk_ecdsa(enum signkey_type type)
{
return type == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256;
}
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) {
/* Based on libtomcrypt's ecc_verify_hash but without the asn1 */ /* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;
@ -176,6 +172,4 @@ out:
return ret; return ret;
} }
#endif /* DROPBEAR_SK_ECDSA */ #endif /* DROPBEAR_SK_ECDSA */

View File

@ -2,13 +2,13 @@
#define DROPBEAR_SK_ECDSA_H_ #define DROPBEAR_SK_ECDSA_H_
#include "includes.h" #include "includes.h"
#include "buffer.h"
#include "signkey.h"
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA
#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);
int signkey_is_sk_ecdsa(enum signkey_type type);
#endif #endif

61
sk-ed25519.c Normal file
View File

@ -0,0 +1,61 @@
#include "includes.h"
#if DROPBEAR_SK_ED25519
#include "dbutil.h"
#include "buffer.h"
#include "curve25519.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 ret = DROPBEAR_FAILURE;
unsigned char *s;
unsigned long slen;
hash_state hs;
unsigned char hash[SHA256_HASH_SIZE];
buffer *sk_buffer = NULL;
unsigned char flags;
unsigned int counter;
TRACE(("enter buf_sk_ed25519_verify"))
dropbear_assert(key != NULL);
slen = buf_getint(buf);
if (slen != 64 || buf->len - buf->pos < slen) {
TRACE(("leave buf_sk_ed25519_verify: bad size"))
goto out;
}
s = buf_getptr(buf, slen);
buf_incrpos(buf, slen);
flags = buf_getbyte (buf);
counter = buf_getint (buf);
sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
sha256_init (&hs);
sha256_process (&hs, app, applen);
sha256_done (&hs, hash);
buf_putbytes (sk_buffer, hash, sizeof (hash));
buf_putbyte (sk_buffer, flags);
buf_putint (sk_buffer, counter);
sha256_init (&hs);
sha256_process (&hs, data_buf->data, data_buf->len);
sha256_done (&hs, hash);
buf_putbytes (sk_buffer, hash, sizeof (hash));
if (dropbear_ed25519_verify(sk_buffer->data, sk_buffer->len,
s, slen, key->pub) == 0) {
/* signature is valid */
TRACE(("leave buf_sk_ed25519_verify: success!"))
ret = DROPBEAR_SUCCESS;
}
out:
if (sk_buffer) {
buf_free(sk_buffer);
}
TRACE(("leave buf_sk_ed25519_verify: ret %d", ret))
return ret;
}
#endif /* DROPBEAR_SK_ED25519 */

15
sk-ed25519.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef DROPBEAR_SK_ED25519_H_
#define DROPBEAR_SK_ED25519_H_
#include "includes.h"
#if DROPBEAR_SK_ED25519
#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);
#endif
#endif /* DROPBEAR_SK_ED25519_H_ */

View File

@ -64,7 +64,6 @@
#include "ssh.h" #include "ssh.h"
#include "packet.h" #include "packet.h"
#include "algo.h" #include "algo.h"
#include "sk-ecdsa.h"
#if DROPBEAR_SVR_PUBKEY_AUTH #if DROPBEAR_SVR_PUBKEY_AUTH
@ -97,9 +96,10 @@ void svr_auth_pubkey(int valid_user) {
enum signkey_type keytype; enum signkey_type keytype;
int auth_failure = 1; int auth_failure = 1;
int verify_ret = DROPBEAR_FAILURE; int verify_ret = DROPBEAR_FAILURE;
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
char* app = NULL; char* app = NULL;
unsigned int applen; unsigned int applen;
int is_sk = 0;
#endif #endif
TRACE(("enter pubkeyauth")) TRACE(("enter pubkeyauth"))
@ -188,8 +188,18 @@ void svr_auth_pubkey(int valid_user) {
goto out; goto out;
} }
#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA
if (signkey_is_sk_ecdsa(keytype)) { if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) {
is_sk = 1;
}
#endif
#if DROPBEAR_SK_ED25519
if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) {
is_sk = 1;
}
#endif
if (is_sk) {
app = buf_getstring (ses.payload, &applen); app = buf_getstring (ses.payload, &applen);
} }
#endif #endif
@ -212,8 +222,8 @@ void svr_auth_pubkey(int valid_user) {
/* ... and finally verify the signature */ /* ... and finally verify the signature */
fp = sign_key_fingerprint(keyblob, keybloblen); fp = sign_key_fingerprint(keyblob, keybloblen);
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
if (signkey_is_sk_ecdsa(keytype)) { if (is_sk) {
verify_ret = sk_buf_verify(ses.payload, key, sigtype, signbuf, app, applen); verify_ret = sk_buf_verify(ses.payload, key, sigtype, signbuf, app, applen);
} else { } else {
verify_ret = buf_verify(ses.payload, key, sigtype, signbuf); verify_ret = buf_verify(ses.payload, key, sigtype, signbuf);
@ -253,7 +263,7 @@ out:
sign_key_free(key); sign_key_free(key);
key = NULL; key = NULL;
} }
#if DROPBEAR_SK_ECDSA #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
if (app) { if (app) {
m_free(app); m_free(app);
} }