diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | authfile.c | 6 | ||||
-rw-r--r-- | cipher.c | 55 | ||||
-rw-r--r-- | cipher.h | 13 | ||||
-rw-r--r-- | kex.c | 86 | ||||
-rw-r--r-- | kex.h | 16 | ||||
-rw-r--r-- | kexecdh.c | 20 | ||||
-rw-r--r-- | kexecdhc.c | 7 | ||||
-rw-r--r-- | kexecdhs.c | 7 | ||||
-rw-r--r-- | key.c | 230 | ||||
-rw-r--r-- | key.h | 7 | ||||
-rw-r--r-- | mac.c | 62 | ||||
-rw-r--r-- | mac.h | 3 | ||||
-rw-r--r-- | packet.c | 6 | ||||
-rw-r--r-- | ssh.1 | 21 | ||||
-rw-r--r-- | ssh.c | 20 |
16 files changed, 314 insertions, 251 deletions
@@ -69,6 +69,12 @@ reintroduce 1.262 without the connection-killing bug: fatal() when ChrootDirectory specified by running without root privileges; ok markus@ + - djm@cvs.openbsd.org 2013/04/19 01:06:50 + [authfile.c cipher.c cipher.h kex.c kex.h kexecdh.c kexecdhc.c kexecdhs.c] + [key.c key.h mac.c mac.h packet.c ssh.1 ssh.c] + 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@ 20130418 - (djm) [config.guess config.sub] Update to last versions before they switch @@ -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 @@ -89,7 +89,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; /* @@ -421,7 +421,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; @@ -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 @@ -65,7 +65,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 }, @@ -98,6 +100,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) { @@ -146,20 +169,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; @@ -170,7 +193,7 @@ cipher_by_number(int id) int ciphers_valid(const char *names) { - Cipher *c; + const Cipher *c; char *cipher_list, *cp; char *p; @@ -201,7 +224,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++) @@ -213,12 +236,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) { @@ -364,7 +387,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; @@ -389,7 +412,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) @@ -402,7 +425,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) { @@ -438,7 +461,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) { @@ -471,7 +494,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) { @@ -486,7 +509,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) { @@ -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 *); @@ -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. * @@ -62,6 +62,55 @@ extern const EVP_MD *evp_ssh_sha256(void); 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 }, +#if OPENSSL_VERSION_NUMBER >= 0x00907000L + { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, + { 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 }, +#endif + { 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) @@ -73,13 +122,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; @@ -348,29 +391,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(); -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { - k->kex_type = KEX_DH_GEX_SHA256; - k->evp_md = evp_ssh_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); -#endif - } 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 @@ -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. @@ -40,8 +40,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 @@ -86,7 +87,7 @@ typedef struct Newkeys Newkeys; struct Enc { char *name; - Cipher *cipher; + const Cipher *cipher; int enabled; u_int key_len; u_int iv_len; @@ -131,6 +132,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 *); @@ -141,6 +143,7 @@ struct Kex { }; int kex_names_valid(const char *); +char *kex_alg_list(void); Kex *kex_setup(char *[PROPOSAL_MAX]); void kex_finish(Kex *); @@ -170,11 +173,6 @@ void 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 *); -#else -# define kex_ecdh_name_to_nid(x) (-1) -# define kex_ecdh_name_to_evpmd(x) (NULL) #endif void @@ -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. @@ -45,24 +45,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, @@ -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. @@ -57,11 +57,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__); @@ -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. @@ -59,11 +59,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__); @@ -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 @@ -892,36 +892,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"; -#ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: - return "ECDSA"; -#endif - 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"; -#ifdef OPENSSL_HAS_ECC - case KEY_ECDSA_CERT: - return "ECDSA-CERT"; -#endif - } - return "unknown"; -} - -const char * key_cert_type(const Key *k) { switch (k->cert->type) { @@ -934,48 +904,59 @@ 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 }, +#ifdef OPENSSL_HAS_ECC + { "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 }, +#endif /* OPENSSL_HAS_ECC */ + { "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 }, +#ifdef OPENSSL_HAS_ECC + { "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 }, +#endif /* OPENSSL_HAS_ECC */ + { "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"; -#ifdef OPENSSL_HAS_ECC - 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; -#endif /* OPENSSL_HAS_ECC */ + 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"; } @@ -993,6 +974,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) { @@ -1248,65 +1279,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; -#ifdef OPENSSL_HAS_ECC - } 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; -#endif - } 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; -#ifdef OPENSSL_HAS_ECC - } 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; -#endif - } - - debug2("key_type_from_name: unknown key type '%s'", name); - return KEY_UNSPEC; -} - -int -key_ecdsa_nid_from_name(const char *name) -{ -#ifdef OPENSSL_HAS_ECC - 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; -#endif /* OPENSSL_HAS_ECC */ - - debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name); - return -1; -} - -int key_names_valid2(const char *names) { char *s, *cp, *p; @@ -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. @@ -118,15 +118,16 @@ 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); #ifdef OPENSSL_HAS_ECC 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 *); #endif +char *key_alg_list(void); Key *key_from_blob(const u_char *, u_int); int key_to_blob(const Key *, u_char **, u_int *); @@ -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. * @@ -50,7 +50,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); @@ -58,7 +58,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 }, @@ -89,38 +91,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); @@ -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); @@ -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 @@ -215,7 +215,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'"); @@ -545,7 +545,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); @@ -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. @@ -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 @@ -327,7 +327,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; @@ -389,6 +389,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; |