summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--common-algo.c6
-rw-r--r--default_options.h2
-rw-r--r--ecdsa.c23
-rw-r--r--ed25519.c17
-rw-r--r--ed25519.h4
-rw-r--r--signkey.c69
-rw-r--r--signkey.h19
-rw-r--r--sk-ecdsa.c47
-rw-r--r--sk-ecdsa.h15
-rw-r--r--sk-ed25519.c61
-rw-r--r--sk-ed25519.h15
-rw-r--r--svr-runopts.c6
-rw-r--r--sysoptions.h1
14 files changed, 271 insertions, 18 deletions
diff --git a/Makefile.in b/Makefile.in
index 8239d25..f53e9c1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -35,8 +35,8 @@ COMMONOBJS=dbutil.o buffer.o dbhelpers.o \
signkey.o rsa.o dbrandom.o \
queue.o \
atomicio.o compat.o fake-rfc2553.o \
- ltc_prng.o ecc.o ecdsa.o crypto_desc.o \
- curve25519.o ed25519.o \
+ ltc_prng.o ecc.o ecdsa.o sk-ecdsa.o crypto_desc.o \
+ curve25519.o ed25519.o sk-ed25519.o \
dbmalloc.o \
gensignkey.o gendss.o genrsa.o gened25519.o
diff --git a/common-algo.c b/common-algo.c
index f3961c2..2d27893 100644
--- a/common-algo.c
+++ b/common-algo.c
@@ -239,6 +239,9 @@ algo_type ssh_nocompress[] = {
algo_type sigalgs[] = {
#if DROPBEAR_ED25519
{"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
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
@@ -250,6 +253,9 @@ algo_type sigalgs[] = {
#if DROPBEAR_ECC_521
{"ecdsa-sha2-nistp521", DROPBEAR_SIGNATURE_ECDSA_NISTP521, NULL, 1, NULL},
#endif
+#if DROPBEAR_SK_ECDSA
+ {"sk-ecdsa-sha2-nistp256@openssh.com", DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256, NULL, 1, NULL},
+#endif
#endif
#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
diff --git a/default_options.h b/default_options.h
index 5cbffce..62f2a39 100644
--- a/default_options.h
+++ b/default_options.h
@@ -126,9 +126,11 @@ IMPORTANT: Some options will require "make clean" after changes */
* code (either ECDSA or ECDH) increases binary size - around 30kB
* on x86-64 */
#define DROPBEAR_ECDSA 1
+#define DROPBEAR_SK_ECDSA 1
/* Ed25519 is faster than ECDSA. Compiling in Ed25519 code increases
binary size - around 7,5kB on x86-64 */
#define DROPBEAR_ED25519 1
+#define DROPBEAR_SK_ED25519 1
/* RSA must be >=1024 */
#define DROPBEAR_DEFAULT_RSA_SIZE 2048
diff --git a/ecdsa.c b/ecdsa.c
index 56e5355..5ac4e7b 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -81,18 +81,25 @@ ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
struct dropbear_ecc_curve **curve;
ecc_key *new_key = NULL;
- /* string "ecdsa-sha2-[identifier]" */
+ /* string "ecdsa-sha2-[identifier]" or "sk-ecdsa-sha2-nistp256@openssh.com" */
key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
/* string "[identifier]" */
identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
- if (key_ident_len != identifier_len + strlen("ecdsa-sha2-")) {
- TRACE(("Bad identifier lengths"))
- goto out;
- }
- if (memcmp(&key_ident[strlen("ecdsa-sha2-")], identifier, identifier_len) != 0) {
- TRACE(("mismatching identifiers"))
- goto out;
+ if (strcmp (key_ident, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
+ if (strcmp (identifier, "nistp256") != 0) {
+ TRACE(("mismatching identifiers"))
+ goto out;
+ }
+ } else {
+ if (key_ident_len != identifier_len + strlen ("ecdsa-sha2-")) {
+ TRACE(("Bad identifier lengths"))
+ goto out;
+ }
+ if (memcmp(&key_ident[strlen ("ecdsa-sha2-")], identifier, identifier_len) != 0) {
+ TRACE(("mismatching identifiers"))
+ goto out;
+ }
}
for (curve = dropbear_ecc_curves; *curve; curve++) {
diff --git a/ed25519.c b/ed25519.c
index 58cce1d..f200e13 100644
--- a/ed25519.c
+++ b/ed25519.c
@@ -38,14 +38,25 @@
* The key will have the same format as buf_put_ed25519_key.
* These should be freed with ed25519_key_free.
* 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,
+ enum signkey_type expect_keytype) {
- unsigned int len;
+
+ unsigned int len, typelen;
+ char *keytype = NULL;
+ enum signkey_type buf_keytype;
TRACE(("enter buf_get_ed25519_pub_key"))
dropbear_assert(key != NULL);
- buf_incrpos(buf, 4+SSH_SIGNKEY_ED25519_LEN); /* int + "ssh-ed25519" */
+ /* consume and check the key string */
+ keytype = buf_getstring(buf, &typelen);
+ buf_keytype = signkey_type_from_name(keytype, typelen);
+ m_free(keytype);
+ if (buf_keytype != expect_keytype) {
+ TRACE(("leave buf_get_ed25519_pub_key: mismatch key type"))
+ return DROPBEAR_FAILURE;
+ }
len = buf_getint(buf);
if (len != CURVE25519_LEN || buf->len - buf->pos < len) {
diff --git a/ed25519.h b/ed25519.h
index 622111a..1da9fbd 100644
--- a/ed25519.h
+++ b/ed25519.h
@@ -27,6 +27,7 @@
#include "includes.h"
#include "buffer.h"
+#include "signkey.h"
#if DROPBEAR_ED25519
@@ -43,7 +44,8 @@ void buf_put_ed25519_sign(buffer* buf, const dropbear_ed25519_key *key, const bu
#if DROPBEAR_SIGNKEY_VERIFY
int buf_ed25519_verify(buffer * buf, const dropbear_ed25519_key *key, const buffer *data_buf);
#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,
+ enum signkey_type expect_keytype);
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_priv_key(buffer* buf, const dropbear_ed25519_key *key);
diff --git a/signkey.c b/signkey.c
index 96446c8..597ba65 100644
--- a/signkey.c
+++ b/signkey.c
@@ -28,6 +28,8 @@
#include "buffer.h"
#include "ssh.h"
#include "ecdsa.h"
+#include "sk-ecdsa.h"
+#include "sk-ed25519.h"
#include "rsa.h"
#include "dss.h"
#include "ed25519.h"
@@ -43,9 +45,15 @@ static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
"ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521",
+#if DROPBEAR_SK_ECDSA
+ "sk-ecdsa-sha2-nistp256@openssh.com",
+#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
"ssh-ed25519",
+#if DROPBEAR_SK_ED25519
+ "sk-ssh-ed25519@openssh.com",
+#endif /* DROPBEAR_SK_ED25519 */
#endif /* DROPBEAR_ED25519 */
/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
};
@@ -180,11 +188,17 @@ signkey_key_ptr(sign_key *key, enum signkey_type type) {
switch (type) {
#if DROPBEAR_ED25519
case DROPBEAR_SIGNKEY_ED25519:
+#if DROPBEAR_SK_ED25519
+ case DROPBEAR_SIGNKEY_SK_ED25519:
+#endif
return (void**)&key->ed25519key;
#endif
#if DROPBEAR_ECDSA
#if DROPBEAR_ECC_256
case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
+#if DROPBEAR_SK_ECDSA
+ case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256:
+#endif
return (void**)&key->ecckey256;
#endif
#if DROPBEAR_ECC_384
@@ -260,7 +274,11 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
#if DROPBEAR_ECDSA
- if (signkey_is_ecdsa(keytype)) {
+ if (signkey_is_ecdsa(keytype)
+#if DROPBEAR_SK_ECDSA
+ || keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
+#endif
+ ) {
ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
if (eck) {
if (*eck) {
@@ -276,10 +294,14 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
#if DROPBEAR_ED25519
- if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+ if (keytype == DROPBEAR_SIGNKEY_ED25519
+#if DROPBEAR_SK_ED25519
+ || keytype == DROPBEAR_SIGNKEY_SK_ED25519
+#endif
+ ) {
ed25519_key_free(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, keytype);
if (ret == DROPBEAR_FAILURE) {
m_free(key->ed25519key);
key->ed25519key = NULL;
@@ -287,6 +309,19 @@ int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
}
#endif
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+ if (0
+#if DROPBEAR_SK_ED25519
+ || keytype == DROPBEAR_SIGNKEY_SK_ED25519
+#endif
+#if DROPBEAR_SK_ECDSA
+ || keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256
+#endif
+ ) {
+ key->sk_app = buf_getstring(buf, &key->sk_applen);
+ }
+#endif
+
TRACE2(("leave buf_get_pub_key"))
return ret;
@@ -401,7 +436,11 @@ void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
}
#endif
#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);
}
#endif
@@ -495,6 +534,11 @@ void sign_key_free(sign_key *key) {
#endif
m_free(key->filename);
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+ if (key->sk_app) {
+ m_free(key->sk_app);
+ }
+#endif
m_free(key);
TRACE2(("leave sign_key_free"))
@@ -639,6 +683,7 @@ void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype,
}
#if DROPBEAR_SIGNKEY_VERIFY
+
/* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
* If FAILURE is returned, the position of
* buf is undefined. If SUCCESS is returned, buf will be positioned after the
@@ -695,6 +740,22 @@ int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype,
return buf_ed25519_verify(buf, key->ed25519key, data_buf);
}
#endif
+#if DROPBEAR_SK_ECDSA
+ 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);
+ }
+ }
+#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, key->sk_app, key->sk_applen);
+ }
+ }
+#endif
dropbear_exit("Non-matching signing type");
return DROPBEAR_FAILURE;
diff --git a/signkey.h b/signkey.h
index 2640171..cc7fd8b 100644
--- a/signkey.h
+++ b/signkey.h
@@ -44,9 +44,15 @@ enum signkey_type {
DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNKEY_ECDSA_NISTP521,
+#if DROPBEAR_SK_ECDSA
+ DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
+#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
DROPBEAR_SIGNKEY_ED25519,
+#if DROPBEAR_SK_ED25519
+ DROPBEAR_SIGNKEY_SK_ED25519,
+#endif
#endif
DROPBEAR_SIGNKEY_NUM_NAMED,
DROPBEAR_SIGNKEY_ECDSA_KEYGEN = 70, /* just "ecdsa" for keygen */
@@ -63,9 +69,15 @@ enum signature_type {
DROPBEAR_SIGNATURE_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_ECDSA_NISTP256,
DROPBEAR_SIGNATURE_ECDSA_NISTP384 = DROPBEAR_SIGNKEY_ECDSA_NISTP384,
DROPBEAR_SIGNATURE_ECDSA_NISTP521 = DROPBEAR_SIGNKEY_ECDSA_NISTP521,
+#if DROPBEAR_SK_ECDSA
+ DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256 = DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256,
+#endif /* DROPBEAR_SK_ECDSA */
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
DROPBEAR_SIGNATURE_ED25519 = DROPBEAR_SIGNKEY_ED25519,
+#if DROPBEAR_SK_ED25519
+ DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
+#endif
#endif
#if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
@@ -110,6 +122,12 @@ struct SIGN_key {
#if DROPBEAR_ED25519
struct dropbear_ED25519_Key * ed25519key;
#endif
+
+#if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519
+ /* application ID for U2F/FIDO key types, a malloced string */
+ char * sk_app;
+ unsigned int sk_applen;
+#endif
};
typedef struct SIGN_key sign_key;
@@ -130,6 +148,7 @@ void sign_key_free(sign_key *key);
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
int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
diff --git a/sk-ecdsa.c b/sk-ecdsa.c
new file mode 100644
index 0000000..2d4a0ff
--- /dev/null
+++ b/sk-ecdsa.c
@@ -0,0 +1,47 @@
+#include "includes.h"
+
+#if DROPBEAR_SK_ECDSA
+
+#include "dbutil.h"
+#include "ecc.h"
+#include "ecdsa.h"
+#include "sk-ecdsa.h"
+
+int buf_sk_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf, const char* app, unsigned int applen) {
+ hash_state hs;
+ unsigned char subhash[SHA256_HASH_SIZE];
+ buffer *sk_buffer = NULL, *sig_buffer = NULL;
+ unsigned char flags;
+ unsigned int counter;
+ int ret;
+
+ TRACE(("buf_sk_ecdsa_verify"))
+
+ /* from https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.u2f */
+ /* ecdsa signature to verify (r, s) */
+ sig_buffer = buf_getbuf(buf);
+
+ flags = buf_getbyte (buf);
+ counter = buf_getint (buf);
+ /* create the message to be signed */
+ sk_buffer = buf_new (2*SHA256_HASH_SIZE+5);
+ sha256_init (&hs);
+ sha256_process (&hs, app, applen);
+ sha256_done (&hs, subhash);
+ buf_putbytes (sk_buffer, subhash, sizeof (subhash));
+ 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, subhash);
+ buf_putbytes (sk_buffer, subhash, sizeof (subhash));
+
+ ret = buf_ecdsa_verify(sig_buffer, key, sk_buffer);
+ buf_free(sk_buffer);
+ buf_free(sig_buffer);
+
+ TRACE(("leave buf_sk_ecdsa_verify, ret=%d", ret))
+ return ret;
+}
+
+#endif /* DROPBEAR_SK_ECDSA */
diff --git a/sk-ecdsa.h b/sk-ecdsa.h
new file mode 100644
index 0000000..7a01305
--- /dev/null
+++ b/sk-ecdsa.h
@@ -0,0 +1,15 @@
+#ifndef DROPBEAR_SK_ECDSA_H_
+#define DROPBEAR_SK_ECDSA_H_
+
+#include "includes.h"
+
+#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);
+
+#endif
+
+#endif /* DROPBEAR_SK_ECDSA_H_ */
diff --git a/sk-ed25519.c b/sk-ed25519.c
new file mode 100644
index 0000000..9da9606
--- /dev/null
+++ b/sk-ed25519.c
@@ -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 */
diff --git a/sk-ed25519.h b/sk-ed25519.h
new file mode 100644
index 0000000..ad8561e
--- /dev/null
+++ b/sk-ed25519.h
@@ -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_ */
diff --git a/svr-runopts.c b/svr-runopts.c
index 02ec2d4..e1ec394 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -668,6 +668,12 @@ void load_all_hostkeys() {
any_keys = 1;
}
#endif
+#if DROPBEAR_SK_ECDSA
+ disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
+#endif
+#if DROPBEAR_SK_ED25519
+ disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
+#endif
if (!any_keys) {
dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
diff --git a/sysoptions.h b/sysoptions.h
index 51c4bc9..10c485b 100644
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -95,6 +95,7 @@
#define DROPBEAR_MAX_PASSWORD_LEN 100
#define SHA1_HASH_SIZE 20
+#define SHA256_HASH_SIZE 32
#define MD5_HASH_SIZE 16
#define MAX_HASH_SIZE 64 /* sha512 */