summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordjm <djm@openbsd.org>2013-04-19 01:06:50 +0000
committerdjm <djm@openbsd.org>2013-04-19 01:06:50 +0000
commit0fdc47d7149ce00079e9d7466a5e689bdf8c2ca5 (patch)
treefdbc2fcabb35adcf5ccdd0829588d2bf5c27819e
parentreintroduce 1.262 without the connection-killing bug: (diff)
downloadwireguard-openbsd-0fdc47d7149ce00079e9d7466a5e689bdf8c2ca5.tar.xz
wireguard-openbsd-0fdc47d7149ce00079e9d7466a5e689bdf8c2ca5.zip
add the ability to query supported ciphers, MACs, key type and KEX
algorithms to ssh. Includes some refactoring of KEX and key type handling to be table-driven; ok markus@
-rw-r--r--usr.bin/ssh/authfile.c6
-rw-r--r--usr.bin/ssh/cipher.c55
-rw-r--r--usr.bin/ssh/cipher.h13
-rw-r--r--usr.bin/ssh/kex.c83
-rw-r--r--usr.bin/ssh/kex.h14
-rw-r--r--usr.bin/ssh/kexecdh.c20
-rw-r--r--usr.bin/ssh/kexecdhc.c7
-rw-r--r--usr.bin/ssh/kexecdhs.c7
-rw-r--r--usr.bin/ssh/key.c213
-rw-r--r--usr.bin/ssh/key.h7
-rw-r--r--usr.bin/ssh/mac.c62
-rw-r--r--usr.bin/ssh/mac.h3
-rw-r--r--usr.bin/ssh/packet.c6
-rw-r--r--usr.bin/ssh/ssh.121
-rw-r--r--usr.bin/ssh/ssh.c20
15 files changed, 303 insertions, 234 deletions
diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c
index 65dccabe916..474b4ab8587 100644
--- a/usr.bin/ssh/authfile.c
+++ b/usr.bin/ssh/authfile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfile.c,v 1.95 2013/01/08 18:49:04 markus Exp $ */
+/* $OpenBSD: authfile.c,v 1.96 2013/04/19 01:06:50 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -84,7 +84,7 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
u_char buf[100], *cp;
int i, cipher_num;
CipherContext ciphercontext;
- Cipher *cipher;
+ const Cipher *cipher;
u_int32_t rnd;
/*
@@ -410,7 +410,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
Buffer decrypted;
u_char *cp;
CipherContext ciphercontext;
- Cipher *cipher;
+ const Cipher *cipher;
Key *prv = NULL;
Buffer copy;
diff --git a/usr.bin/ssh/cipher.c b/usr.bin/ssh/cipher.c
index 3c3b123d7a7..e7ea118eaa6 100644
--- a/usr.bin/ssh/cipher.c
+++ b/usr.bin/ssh/cipher.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher.c,v 1.87 2013/01/26 06:11:05 djm Exp $ */
+/* $OpenBSD: cipher.c,v 1.88 2013/04/19 01:06:50 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -60,7 +60,9 @@ struct Cipher {
u_int discard_len;
u_int cbc_mode;
const EVP_CIPHER *(*evptype)(void);
-} ciphers[] = {
+};
+
+static const struct Cipher ciphers[] = {
{ "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
{ "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
{ "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
@@ -92,6 +94,27 @@ struct Cipher {
/*--*/
+/* Returns a comma-separated list of supported ciphers. */
+char *
+cipher_alg_list(void)
+{
+ char *ret = NULL;
+ size_t nlen, rlen = 0;
+ const Cipher *c;
+
+ for (c = ciphers; c->name != NULL; c++) {
+ if (c->number != SSH_CIPHER_SSH2)
+ continue;
+ if (ret != NULL)
+ ret[rlen++] = '\n';
+ nlen = strlen(c->name);
+ ret = xrealloc(ret, 1, rlen + nlen + 2);
+ memcpy(ret + rlen, c->name, nlen + 1);
+ rlen += nlen;
+ }
+ return ret;
+}
+
u_int
cipher_blocksize(const Cipher *c)
{
@@ -140,20 +163,20 @@ cipher_mask_ssh1(int client)
return mask;
}
-Cipher *
+const Cipher *
cipher_by_name(const char *name)
{
- Cipher *c;
+ const Cipher *c;
for (c = ciphers; c->name != NULL; c++)
if (strcmp(c->name, name) == 0)
return c;
return NULL;
}
-Cipher *
+const Cipher *
cipher_by_number(int id)
{
- Cipher *c;
+ const Cipher *c;
for (c = ciphers; c->name != NULL; c++)
if (c->number == id)
return c;
@@ -164,7 +187,7 @@ cipher_by_number(int id)
int
ciphers_valid(const char *names)
{
- Cipher *c;
+ const Cipher *c;
char *cipher_list, *cp;
char *p;
@@ -195,7 +218,7 @@ ciphers_valid(const char *names)
int
cipher_number(const char *name)
{
- Cipher *c;
+ const Cipher *c;
if (name == NULL)
return -1;
for (c = ciphers; c->name != NULL; c++)
@@ -207,12 +230,12 @@ cipher_number(const char *name)
char *
cipher_name(int id)
{
- Cipher *c = cipher_by_number(id);
+ const Cipher *c = cipher_by_number(id);
return (c==NULL) ? "<unknown>" : c->name;
}
void
-cipher_init(CipherContext *cc, Cipher *cipher,
+cipher_init(CipherContext *cc, const Cipher *cipher,
const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int do_encrypt)
{
@@ -344,7 +367,7 @@ cipher_cleanup(CipherContext *cc)
*/
void
-cipher_set_key_string(CipherContext *cc, Cipher *cipher,
+cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
const char *passphrase, int do_encrypt)
{
MD5_CTX md;
@@ -369,7 +392,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
int
cipher_get_keyiv_len(const CipherContext *cc)
{
- Cipher *c = cc->cipher;
+ const Cipher *c = cc->cipher;
int ivlen;
if (c->number == SSH_CIPHER_3DES)
@@ -382,7 +405,7 @@ cipher_get_keyiv_len(const CipherContext *cc)
void
cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
{
- Cipher *c = cc->cipher;
+ const Cipher *c = cc->cipher;
int evplen;
switch (c->number) {
@@ -413,7 +436,7 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
void
cipher_set_keyiv(CipherContext *cc, u_char *iv)
{
- Cipher *c = cc->cipher;
+ const Cipher *c = cc->cipher;
int evplen = 0;
switch (c->number) {
@@ -445,7 +468,7 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv)
int
cipher_get_keycontext(const CipherContext *cc, u_char *dat)
{
- Cipher *c = cc->cipher;
+ const Cipher *c = cc->cipher;
int plen = 0;
if (c->evptype == EVP_rc4) {
@@ -460,7 +483,7 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat)
void
cipher_set_keycontext(CipherContext *cc, u_char *dat)
{
- Cipher *c = cc->cipher;
+ const Cipher *c = cc->cipher;
int plen;
if (c->evptype == EVP_rc4) {
diff --git a/usr.bin/ssh/cipher.h b/usr.bin/ssh/cipher.h
index 8cb57c3e594..b878d50f4fc 100644
--- a/usr.bin/ssh/cipher.h
+++ b/usr.bin/ssh/cipher.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher.h,v 1.39 2013/01/08 18:49:04 markus Exp $ */
+/* $OpenBSD: cipher.h,v 1.40 2013/04/19 01:06:50 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -66,21 +66,22 @@ struct CipherContext {
int plaintext;
int encrypt;
EVP_CIPHER_CTX evp;
- Cipher *cipher;
+ const Cipher *cipher;
};
u_int cipher_mask_ssh1(int);
-Cipher *cipher_by_name(const char *);
-Cipher *cipher_by_number(int);
+const Cipher *cipher_by_name(const char *);
+const Cipher *cipher_by_number(int);
int cipher_number(const char *);
char *cipher_name(int);
int ciphers_valid(const char *);
-void cipher_init(CipherContext *, Cipher *, const u_char *, u_int,
+char *cipher_alg_list(void);
+void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int,
const u_char *, u_int, int);
void cipher_crypt(CipherContext *, u_char *, const u_char *,
u_int, u_int, u_int);
void cipher_cleanup(CipherContext *);
-void cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int);
u_int cipher_blocksize(const Cipher *);
u_int cipher_keylen(const Cipher *);
u_int cipher_authlen(const Cipher *);
diff --git a/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c
index 023ebf099dd..185ac1a67fd 100644
--- a/usr.bin/ssh/kex.c
+++ b/usr.bin/ssh/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.88 2013/01/08 18:49:04 markus Exp $ */
+/* $OpenBSD: kex.c,v 1.89 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -51,6 +51,54 @@
static void kex_kexinit_finish(Kex *);
static void kex_choose_conf(Kex *);
+struct kexalg {
+ char *name;
+ int type;
+ int ec_nid;
+ const EVP_MD *(*mdfunc)(void);
+};
+static const struct kexalg kexalgs[] = {
+ { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 },
+ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 },
+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 },
+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 },
+ { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 },
+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 },
+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 },
+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 },
+ { NULL, -1, -1, NULL},
+};
+
+char *
+kex_alg_list(void)
+{
+ char *ret = NULL;
+ size_t nlen, rlen = 0;
+ const struct kexalg *k;
+
+ for (k = kexalgs; k->name != NULL; k++) {
+ if (ret != NULL)
+ ret[rlen++] = '\n';
+ nlen = strlen(k->name);
+ ret = xrealloc(ret, 1, rlen + nlen + 2);
+ memcpy(ret + rlen, k->name, nlen + 1);
+ rlen += nlen;
+ }
+ return ret;
+}
+
+static const struct kexalg *
+kex_alg_by_name(const char *name)
+{
+ const struct kexalg *k;
+
+ for (k = kexalgs; k->name != NULL; k++) {
+ if (strcmp(k->name, name) == 0)
+ return k;
+ }
+ return NULL;
+}
+
/* Validate KEX method name list */
int
kex_names_valid(const char *names)
@@ -62,13 +110,7 @@ kex_names_valid(const char *names)
s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) {
- if (strcmp(p, KEX_DHGEX_SHA256) != 0 &&
- strcmp(p, KEX_DHGEX_SHA1) != 0 &&
- strcmp(p, KEX_DH14) != 0 &&
- strcmp(p, KEX_DH1) != 0 &&
- (strncmp(p, KEX_ECDH_SHA2_STEM,
- sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 ||
- kex_ecdh_name_to_nid(p) == -1)) {
+ if (kex_alg_by_name(p) == NULL) {
error("Unsupported KEX algorithm \"%.100s\"", p);
xfree(s);
return 0;
@@ -337,27 +379,16 @@ choose_comp(Comp *comp, char *client, char *server)
static void
choose_kex(Kex *k, char *client, char *server)
{
+ const struct kexalg *kexalg;
+
k->name = match_list(client, server, NULL);
if (k->name == NULL)
fatal("Unable to negotiate a key exchange method");
- if (strcmp(k->name, KEX_DH1) == 0) {
- k->kex_type = KEX_DH_GRP1_SHA1;
- k->evp_md = EVP_sha1();
- } else if (strcmp(k->name, KEX_DH14) == 0) {
- k->kex_type = KEX_DH_GRP14_SHA1;
- k->evp_md = EVP_sha1();
- } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) {
- k->kex_type = KEX_DH_GEX_SHA1;
- k->evp_md = EVP_sha1();
- } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) {
- k->kex_type = KEX_DH_GEX_SHA256;
- k->evp_md = EVP_sha256();
- } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM,
- sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) {
- k->kex_type = KEX_ECDH_SHA2;
- k->evp_md = kex_ecdh_name_to_evpmd(k->name);
- } else
- fatal("bad kex alg %s", k->name);
+ if ((kexalg = kex_alg_by_name(k->name)) == NULL)
+ fatal("unsupported kex alg %s", k->name);
+ k->kex_type = kexalg->type;
+ k->evp_md = kexalg->mdfunc();
+ k->ec_nid = kexalg->ec_nid;
}
static void
diff --git a/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h
index 0cb2269d8c2..28e15c8520b 100644
--- a/usr.bin/ssh/kex.h
+++ b/usr.bin/ssh/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.54 2013/01/08 18:49:04 markus Exp $ */
+/* $OpenBSD: kex.h,v 1.55 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -37,8 +37,9 @@
#define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1"
#define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256"
#define KEX_RESUME "resume@appgate.com"
-/* The following represents the family of ECDH methods */
-#define KEX_ECDH_SHA2_STEM "ecdh-sha2-"
+#define KEX_ECDH_SHA2_NISTP256 "ecdh-sha2-nistp256"
+#define KEX_ECDH_SHA2_NISTP384 "ecdh-sha2-nistp384"
+#define KEX_ECDH_SHA2_NISTP521 "ecdh-sha2-nistp521"
#define COMP_NONE 0
#define COMP_ZLIB 1
@@ -83,7 +84,7 @@ typedef struct Newkeys Newkeys;
struct Enc {
char *name;
- Cipher *cipher;
+ const Cipher *cipher;
int enabled;
u_int key_len;
u_int iv_len;
@@ -128,6 +129,7 @@ struct Kex {
sig_atomic_t done;
int flags;
const EVP_MD *evp_md;
+ int ec_nid;
char *client_version_string;
char *server_version_string;
int (*verify_host_key)(Key *);
@@ -138,6 +140,7 @@ struct Kex {
};
int kex_names_valid(const char *);
+char *kex_alg_list(void);
Kex *kex_setup(char *[PROPOSAL_MAX]);
void kex_finish(Kex *);
@@ -167,9 +170,6 @@ kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int,
char *, int, u_char *, int, const EC_POINT *, const EC_POINT *,
const BIGNUM *, u_char **, u_int *);
-int kex_ecdh_name_to_nid(const char *);
-const EVP_MD *kex_ecdh_name_to_evpmd(const char *);
-
void
derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
diff --git a/usr.bin/ssh/kexecdh.c b/usr.bin/ssh/kexecdh.c
index 7c1cb3e76f1..93d9b02c1ac 100644
--- a/usr.bin/ssh/kexecdh.c
+++ b/usr.bin/ssh/kexecdh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdh.c,v 1.3 2010/09/22 05:01:29 djm Exp $ */
+/* $OpenBSD: kexecdh.c,v 1.4 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -41,24 +41,6 @@
#include "kex.h"
#include "log.h"
-int
-kex_ecdh_name_to_nid(const char *kexname)
-{
- if (strlen(kexname) < sizeof(KEX_ECDH_SHA2_STEM) - 1)
- fatal("%s: kexname too short \"%s\"", __func__, kexname);
- return key_curve_name_to_nid(kexname + sizeof(KEX_ECDH_SHA2_STEM) - 1);
-}
-
-const EVP_MD *
-kex_ecdh_name_to_evpmd(const char *kexname)
-{
- int nid = kex_ecdh_name_to_nid(kexname);
-
- if (nid == -1)
- fatal("%s: unsupported ECDH curve \"%s\"", __func__, kexname);
- return key_ec_nid_to_evpmd(nid);
-}
-
void
kex_ecdh_hash(
const EVP_MD *evp_md,
diff --git a/usr.bin/ssh/kexecdhc.c b/usr.bin/ssh/kexecdhc.c
index 218768ba8ad..cb409d6c9d2 100644
--- a/usr.bin/ssh/kexecdhc.c
+++ b/usr.bin/ssh/kexecdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdhc.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */
+/* $OpenBSD: kexecdhc.c,v 1.3 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -53,11 +53,8 @@ kexecdh_client(Kex *kex)
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen;
- int curve_nid;
- if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1)
- fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
- if ((client_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
+ if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(client_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__);
diff --git a/usr.bin/ssh/kexecdhs.c b/usr.bin/ssh/kexecdhs.c
index 1dee1722d9b..a624cd01eec 100644
--- a/usr.bin/ssh/kexecdhs.c
+++ b/usr.bin/ssh/kexecdhs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdhs.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */
+/* $OpenBSD: kexecdhs.c,v 1.3 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -55,11 +55,8 @@ kexecdh_server(Kex *kex)
u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen;
- int curve_nid;
- if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1)
- fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
- if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
+ if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(server_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__);
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 126bd398298..e37ae965e4b 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.100 2013/01/17 23:00:01 djm Exp $ */
+/* $OpenBSD: key.c,v 1.101 2013/04/19 01:06:50 djm Exp $ */
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -867,32 +867,6 @@ key_write(const Key *key, FILE *f)
}
const char *
-key_type(const Key *k)
-{
- switch (k->type) {
- case KEY_RSA1:
- return "RSA1";
- case KEY_RSA:
- return "RSA";
- case KEY_DSA:
- return "DSA";
- case KEY_ECDSA:
- return "ECDSA";
- case KEY_RSA_CERT_V00:
- return "RSA-CERT-V00";
- case KEY_DSA_CERT_V00:
- return "DSA-CERT-V00";
- case KEY_RSA_CERT:
- return "RSA-CERT";
- case KEY_DSA_CERT:
- return "DSA-CERT";
- case KEY_ECDSA_CERT:
- return "ECDSA-CERT";
- }
- return "unknown";
-}
-
-const char *
key_cert_type(const Key *k)
{
switch (k->cert->type) {
@@ -905,46 +879,55 @@ key_cert_type(const Key *k)
}
}
+struct keytype {
+ char *name;
+ char *shortname;
+ int type;
+ int nid;
+ int cert;
+};
+static const struct keytype keytypes[] = {
+ { NULL, "RSA1", KEY_RSA1, 0, 0 },
+ { "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
+ { "ssh-dss", "DSA", KEY_DSA, 0, 0 },
+ { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
+ { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
+ { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
+ { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
+ { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
+ { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
+ { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_secp384r1, 1 },
+ { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
+ KEY_ECDSA_CERT, NID_secp521r1, 1 },
+ { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
+ KEY_RSA_CERT_V00, 0, 1 },
+ { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
+ KEY_DSA_CERT_V00, 0, 1 },
+ { NULL, NULL, -1, -1, 0 }
+};
+
+const char *
+key_type(const Key *k)
+{
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ if (kt->type == k->type)
+ return kt->shortname;
+ }
+ return "unknown";
+}
+
static const char *
key_ssh_name_from_type_nid(int type, int nid)
{
- switch (type) {
- case KEY_RSA:
- return "ssh-rsa";
- case KEY_DSA:
- return "ssh-dss";
- case KEY_RSA_CERT_V00:
- return "ssh-rsa-cert-v00@openssh.com";
- case KEY_DSA_CERT_V00:
- return "ssh-dss-cert-v00@openssh.com";
- case KEY_RSA_CERT:
- return "ssh-rsa-cert-v01@openssh.com";
- case KEY_DSA_CERT:
- return "ssh-dss-cert-v01@openssh.com";
- case KEY_ECDSA:
- switch (nid) {
- case NID_X9_62_prime256v1:
- return "ecdsa-sha2-nistp256";
- case NID_secp384r1:
- return "ecdsa-sha2-nistp384";
- case NID_secp521r1:
- return "ecdsa-sha2-nistp521";
- default:
- break;
- }
- break;
- case KEY_ECDSA_CERT:
- switch (nid) {
- case NID_X9_62_prime256v1:
- return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
- case NID_secp384r1:
- return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
- case NID_secp521r1:
- return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
- default:
- break;
- }
- break;
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
+ return kt->name;
}
return "ssh-unknown";
}
@@ -962,6 +945,56 @@ key_ssh_name_plain(const Key *k)
k->ecdsa_nid);
}
+int
+key_type_from_name(char *name)
+{
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ /* Only allow shortname matches for plain key types */
+ if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
+ (!kt->cert && strcasecmp(kt->shortname, name) == 0))
+ return kt->type;
+ }
+ debug2("key_type_from_name: unknown key type '%s'", name);
+ return KEY_UNSPEC;
+}
+
+int
+key_ecdsa_nid_from_name(const char *name)
+{
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
+ continue;
+ if (kt->name != NULL && strcmp(name, kt->name) == 0)
+ return kt->nid;
+ }
+ debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
+ return -1;
+}
+
+char *
+key_alg_list(void)
+{
+ char *ret = NULL;
+ size_t nlen, rlen = 0;
+ const struct keytype *kt;
+
+ for (kt = keytypes; kt->type != -1; kt++) {
+ if (kt->name == NULL)
+ continue;
+ if (ret != NULL)
+ ret[rlen++] = '\n';
+ nlen = strlen(kt->name);
+ ret = xrealloc(ret, 1, rlen + nlen + 2);
+ memcpy(ret + rlen, kt->name, nlen + 1);
+ rlen += nlen;
+ }
+ return ret;
+}
+
u_int
key_size(const Key *k)
{
@@ -1207,58 +1240,6 @@ key_from_private(const Key *k)
}
int
-key_type_from_name(char *name)
-{
- if (strcmp(name, "rsa1") == 0) {
- return KEY_RSA1;
- } else if (strcmp(name, "rsa") == 0) {
- return KEY_RSA;
- } else if (strcmp(name, "dsa") == 0) {
- return KEY_DSA;
- } else if (strcmp(name, "ssh-rsa") == 0) {
- return KEY_RSA;
- } else if (strcmp(name, "ssh-dss") == 0) {
- return KEY_DSA;
- } else if (strcmp(name, "ecdsa") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp521") == 0) {
- return KEY_ECDSA;
- } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) {
- return KEY_RSA_CERT_V00;
- } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) {
- return KEY_DSA_CERT_V00;
- } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
- return KEY_RSA_CERT;
- } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) {
- return KEY_DSA_CERT;
- } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0)
- return KEY_ECDSA_CERT;
-
- debug2("key_type_from_name: unknown key type '%s'", name);
- return KEY_UNSPEC;
-}
-
-int
-key_ecdsa_nid_from_name(const char *name)
-{
- if (strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0)
- return NID_X9_62_prime256v1;
- if (strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0)
- return NID_secp384r1;
- if (strcmp(name, "ecdsa-sha2-nistp521") == 0 ||
- strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0)
- return NID_secp521r1;
-
- debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
- return -1;
-}
-
-int
key_names_valid2(const char *names)
{
char *s, *cp, *p;
diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h
index 9f1b10b0835..9b24f384264 100644
--- a/usr.bin/ssh/key.h
+++ b/usr.bin/ssh/key.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.35 2013/01/17 23:00:01 djm Exp $ */
+/* $OpenBSD: key.h,v 1.36 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -112,13 +112,14 @@ int key_cert_is_legacy(const Key *);
int key_ecdsa_nid_from_name(const char *);
int key_curve_name_to_nid(const char *);
-const char * key_curve_nid_to_name(int);
+const char *key_curve_nid_to_name(int);
u_int key_curve_nid_to_bits(int);
int key_ecdsa_bits_to_nid(int);
int key_ecdsa_key_to_nid(EC_KEY *);
-const EVP_MD * key_ec_nid_to_evpmd(int nid);
+const EVP_MD *key_ec_nid_to_evpmd(int nid);
int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
int key_ec_validate_private(const EC_KEY *);
+char *key_alg_list(void);
Key *key_from_blob(const u_char *, u_int);
int key_to_blob(const Key *, u_char **, u_int *);
diff --git a/usr.bin/ssh/mac.c b/usr.bin/ssh/mac.c
index 621c6098189..111afe08b96 100644
--- a/usr.bin/ssh/mac.c
+++ b/usr.bin/ssh/mac.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mac.c,v 1.21 2012/12/11 22:51:45 sthen Exp $ */
+/* $OpenBSD: mac.c,v 1.22 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@@ -45,7 +45,7 @@
#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */
#define SSH_UMAC128 3
-struct {
+struct macalg {
char *name;
int type;
const EVP_MD * (*mdfunc)(void);
@@ -53,7 +53,9 @@ struct {
int key_len; /* just for UMAC */
int len; /* just for UMAC */
int etm; /* Encrypt-then-MAC */
-} macs[] = {
+};
+
+static const struct macalg macs[] = {
/* Encrypt-and-MAC (encrypt-and-authenticate) variants */
{ "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 },
{ "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 },
@@ -80,38 +82,58 @@ struct {
{ NULL, 0, NULL, 0, 0, 0, 0 }
};
+/* Returns a comma-separated list of supported MACs. */
+char *
+mac_alg_list(void)
+{
+ char *ret = NULL;
+ size_t nlen, rlen = 0;
+ const struct macalg *m;
+
+ for (m = macs; m->name != NULL; m++) {
+ if (ret != NULL)
+ ret[rlen++] = '\n';
+ nlen = strlen(m->name);
+ ret = xrealloc(ret, 1, rlen + nlen + 2);
+ memcpy(ret + rlen, m->name, nlen + 1);
+ rlen += nlen;
+ }
+ return ret;
+}
+
static void
-mac_setup_by_id(Mac *mac, int which)
+mac_setup_by_alg(Mac *mac, const struct macalg *macalg)
{
int evp_len;
- mac->type = macs[which].type;
+
+ mac->type = macalg->type;
if (mac->type == SSH_EVP) {
- mac->evp_md = (*macs[which].mdfunc)();
+ mac->evp_md = macalg->mdfunc();
if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
fatal("mac %s len %d", mac->name, evp_len);
mac->key_len = mac->mac_len = (u_int)evp_len;
} else {
- mac->mac_len = macs[which].len / 8;
- mac->key_len = macs[which].key_len / 8;
+ mac->mac_len = macalg->len / 8;
+ mac->key_len = macalg->key_len / 8;
mac->umac_ctx = NULL;
}
- if (macs[which].truncatebits != 0)
- mac->mac_len = macs[which].truncatebits / 8;
- mac->etm = macs[which].etm;
+ if (macalg->truncatebits != 0)
+ mac->mac_len = macalg->truncatebits / 8;
+ mac->etm = macalg->etm;
}
int
mac_setup(Mac *mac, char *name)
{
- int i;
-
- for (i = 0; macs[i].name; i++) {
- if (strcmp(name, macs[i].name) == 0) {
- if (mac != NULL)
- mac_setup_by_id(mac, i);
- debug2("mac_setup: found %s", name);
- return (0);
- }
+ const struct macalg *m;
+
+ for (m = macs; m->name != NULL; m++) {
+ if (strcmp(name, m->name) != 0)
+ continue;
+ if (mac != NULL)
+ mac_setup_by_alg(mac, m);
+ debug2("mac_setup: found %s", name);
+ return (0);
}
debug2("mac_setup: unknown %s", name);
return (-1);
diff --git a/usr.bin/ssh/mac.h b/usr.bin/ssh/mac.h
index 39f564dd300..260798ab3b0 100644
--- a/usr.bin/ssh/mac.h
+++ b/usr.bin/ssh/mac.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mac.h,v 1.6 2007/06/07 19:37:34 pvalchev Exp $ */
+/* $OpenBSD: mac.h,v 1.7 2013/04/19 01:06:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
@@ -24,6 +24,7 @@
*/
int mac_valid(const char *);
+char *mac_alg_list(void);
int mac_setup(Mac *, char *);
int mac_init(Mac *);
u_char *mac_compute(Mac *, u_int32_t, u_char *, int);
diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c
index 032485d537b..b8fb80ba5d2 100644
--- a/usr.bin/ssh/packet.c
+++ b/usr.bin/ssh/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.182 2013/04/11 02:27:50 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.183 2013/04/19 01:06:50 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -211,7 +211,7 @@ alloc_session_state(void)
void
packet_set_connection(int fd_in, int fd_out)
{
- Cipher *none = cipher_by_name("none");
+ const Cipher *none = cipher_by_name("none");
if (none == NULL)
fatal("packet_set_connection: cannot load cipher 'none'");
@@ -536,7 +536,7 @@ packet_start_compression(int level)
void
packet_set_encryption_key(const u_char *key, u_int keylen, int number)
{
- Cipher *cipher = cipher_by_number(number);
+ const Cipher *cipher = cipher_by_number(number);
if (cipher == NULL)
fatal("packet_set_encryption_key: unknown cipher number %d", number);
diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1
index d77494b8326..dc7af48642e 100644
--- a/usr.bin/ssh/ssh.1
+++ b/usr.bin/ssh/ssh.1
@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.\" $OpenBSD: ssh.1,v 1.331 2013/04/07 02:10:33 dtucker Exp $
-.Dd $Mdocdate: April 7 2013 $
+.\" $OpenBSD: ssh.1,v 1.332 2013/04/19 01:06:50 djm Exp $
+.Dd $Mdocdate: April 19 2013 $
.Dt SSH 1
.Os
.Sh NAME
@@ -65,6 +65,8 @@
.Oo Ar user Ns @ Oc Ns Ar hostname
.Op Ar command
.Ek
+.Nm
+.Fl Q Ar protocol_feature
.Sh DESCRIPTION
.Nm
(SSH client) is a program for logging into a remote machine and for
@@ -487,6 +489,21 @@ For full details of the options listed below, and their possible values, see
Port to connect to on the remote host.
This can be specified on a
per-host basis in the configuration file.
+.It Fl Q Ar protocol_feature
+Queries
+.Nm
+for the algorithms supported for the specified version 2
+.Ar protocol_feature .
+The queriable features are:
+.Dq cipher
+(supported symmetric ciphers),
+.Dq MAC
+(supported message integrity codes),
+.Dq KEX
+(key exchange algorithms),
+.Dq key
+(key types).
+Protocol features are treated case-insensitively.
.It Fl q
Quiet mode.
Causes most warning and diagnostic messages to be suppressed.
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index 022f7d351f7..74862804bdd 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.375 2013/04/07 02:10:33 dtucker Exp $ */
+/* $OpenBSD: ssh.c,v 1.376 2013/04/19 01:06:50 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -298,7 +298,7 @@ main(int ac, char **av)
again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
- "ACD:E:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) {
+ "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
@@ -360,6 +360,22 @@ main(int ac, char **av)
case 'P': /* deprecated */
options.use_privileged_port = 0;
break;
+ case 'Q': /* deprecated */
+ cp = NULL;
+ if (strcasecmp(optarg, "cipher") == 0)
+ cp = cipher_alg_list();
+ else if (strcasecmp(optarg, "mac") == 0)
+ cp = mac_alg_list();
+ else if (strcasecmp(optarg, "kex") == 0)
+ cp = kex_alg_list();
+ else if (strcasecmp(optarg, "key") == 0)
+ cp = key_alg_list();
+ if (cp == NULL)
+ fatal("Unsupported query \"%s\"", optarg);
+ printf("%s\n", cp);
+ free(cp);
+ exit(0);
+ break;
case 'a':
options.forward_agent = 0;
break;