- 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@
This commit is contained in:
Damien Miller 2013-04-23 19:24:32 +10:00
parent a56086b990
commit ea11119eee
16 changed files with 313 additions and 250 deletions

View File

@ -69,6 +69,12 @@
reintroduce 1.262 without the connection-killing bug: reintroduce 1.262 without the connection-killing bug:
fatal() when ChrootDirectory specified by running without root privileges; fatal() when ChrootDirectory specified by running without root privileges;
ok markus@ 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 20130418
- (djm) [config.guess config.sub] Update to last versions before they switch - (djm) [config.guess config.sub] Update to last versions before they switch

View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * 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; u_char buf[100], *cp;
int i, cipher_num; int i, cipher_num;
CipherContext ciphercontext; CipherContext ciphercontext;
Cipher *cipher; const Cipher *cipher;
u_int32_t rnd; u_int32_t rnd;
/* /*
@ -421,7 +421,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
Buffer decrypted; Buffer decrypted;
u_char *cp; u_char *cp;
CipherContext ciphercontext; CipherContext ciphercontext;
Cipher *cipher; const Cipher *cipher;
Key *prv = NULL; Key *prv = NULL;
Buffer copy; Buffer copy;

View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -65,7 +65,9 @@ struct Cipher {
u_int discard_len; u_int discard_len;
u_int cbc_mode; u_int cbc_mode;
const EVP_CIPHER *(*evptype)(void); const EVP_CIPHER *(*evptype)(void);
} ciphers[] = { };
static const struct Cipher ciphers[] = {
{ "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, { "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 }, { "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 }, { "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 u_int
cipher_blocksize(const Cipher *c) cipher_blocksize(const Cipher *c)
{ {
@ -146,20 +169,20 @@ cipher_mask_ssh1(int client)
return mask; return mask;
} }
Cipher * const Cipher *
cipher_by_name(const char *name) cipher_by_name(const char *name)
{ {
Cipher *c; const Cipher *c;
for (c = ciphers; c->name != NULL; c++) for (c = ciphers; c->name != NULL; c++)
if (strcmp(c->name, name) == 0) if (strcmp(c->name, name) == 0)
return c; return c;
return NULL; return NULL;
} }
Cipher * const Cipher *
cipher_by_number(int id) cipher_by_number(int id)
{ {
Cipher *c; const Cipher *c;
for (c = ciphers; c->name != NULL; c++) for (c = ciphers; c->name != NULL; c++)
if (c->number == id) if (c->number == id)
return c; return c;
@ -170,7 +193,7 @@ cipher_by_number(int id)
int int
ciphers_valid(const char *names) ciphers_valid(const char *names)
{ {
Cipher *c; const Cipher *c;
char *cipher_list, *cp; char *cipher_list, *cp;
char *p; char *p;
@ -201,7 +224,7 @@ ciphers_valid(const char *names)
int int
cipher_number(const char *name) cipher_number(const char *name)
{ {
Cipher *c; const Cipher *c;
if (name == NULL) if (name == NULL)
return -1; return -1;
for (c = ciphers; c->name != NULL; c++) for (c = ciphers; c->name != NULL; c++)
@ -213,12 +236,12 @@ cipher_number(const char *name)
char * char *
cipher_name(int id) cipher_name(int id)
{ {
Cipher *c = cipher_by_number(id); const Cipher *c = cipher_by_number(id);
return (c==NULL) ? "<unknown>" : c->name; return (c==NULL) ? "<unknown>" : c->name;
} }
void 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, const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
int do_encrypt) int do_encrypt)
{ {
@ -364,7 +387,7 @@ cipher_cleanup(CipherContext *cc)
*/ */
void void
cipher_set_key_string(CipherContext *cc, Cipher *cipher, cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
const char *passphrase, int do_encrypt) const char *passphrase, int do_encrypt)
{ {
MD5_CTX md; MD5_CTX md;
@ -389,7 +412,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
int int
cipher_get_keyiv_len(const CipherContext *cc) cipher_get_keyiv_len(const CipherContext *cc)
{ {
Cipher *c = cc->cipher; const Cipher *c = cc->cipher;
int ivlen; int ivlen;
if (c->number == SSH_CIPHER_3DES) if (c->number == SSH_CIPHER_3DES)
@ -402,7 +425,7 @@ cipher_get_keyiv_len(const CipherContext *cc)
void void
cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
{ {
Cipher *c = cc->cipher; const Cipher *c = cc->cipher;
int evplen; int evplen;
switch (c->number) { switch (c->number) {
@ -438,7 +461,7 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
void void
cipher_set_keyiv(CipherContext *cc, u_char *iv) cipher_set_keyiv(CipherContext *cc, u_char *iv)
{ {
Cipher *c = cc->cipher; const Cipher *c = cc->cipher;
int evplen = 0; int evplen = 0;
switch (c->number) { switch (c->number) {
@ -471,7 +494,7 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv)
int int
cipher_get_keycontext(const CipherContext *cc, u_char *dat) cipher_get_keycontext(const CipherContext *cc, u_char *dat)
{ {
Cipher *c = cc->cipher; const Cipher *c = cc->cipher;
int plen = 0; int plen = 0;
if (c->evptype == EVP_rc4) { if (c->evptype == EVP_rc4) {
@ -486,7 +509,7 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat)
void void
cipher_set_keycontext(CipherContext *cc, u_char *dat) cipher_set_keycontext(CipherContext *cc, u_char *dat)
{ {
Cipher *c = cc->cipher; const Cipher *c = cc->cipher;
int plen; int plen;
if (c->evptype == EVP_rc4) { if (c->evptype == EVP_rc4) {

View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -66,21 +66,22 @@ struct CipherContext {
int plaintext; int plaintext;
int encrypt; int encrypt;
EVP_CIPHER_CTX evp; EVP_CIPHER_CTX evp;
Cipher *cipher; const Cipher *cipher;
}; };
u_int cipher_mask_ssh1(int); u_int cipher_mask_ssh1(int);
Cipher *cipher_by_name(const char *); const Cipher *cipher_by_name(const char *);
Cipher *cipher_by_number(int); const Cipher *cipher_by_number(int);
int cipher_number(const char *); int cipher_number(const char *);
char *cipher_name(int); char *cipher_name(int);
int ciphers_valid(const char *); 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); const u_char *, u_int, int);
void cipher_crypt(CipherContext *, u_char *, const u_char *, void cipher_crypt(CipherContext *, u_char *, const u_char *,
u_int, u_int, u_int); u_int, u_int, u_int);
void cipher_cleanup(CipherContext *); 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_blocksize(const Cipher *);
u_int cipher_keylen(const Cipher *); u_int cipher_keylen(const Cipher *);
u_int cipher_authlen(const Cipher *); u_int cipher_authlen(const Cipher *);

86
kex.c
View File

@ -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. * 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_kexinit_finish(Kex *);
static void kex_choose_conf(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 */ /* Validate KEX method name list */
int int
kex_names_valid(const char *names) kex_names_valid(const char *names)
@ -73,13 +122,7 @@ kex_names_valid(const char *names)
s = cp = xstrdup(names); s = cp = xstrdup(names);
for ((p = strsep(&cp, ",")); p && *p != '\0'; for ((p = strsep(&cp, ",")); p && *p != '\0';
(p = strsep(&cp, ","))) { (p = strsep(&cp, ","))) {
if (strcmp(p, KEX_DHGEX_SHA256) != 0 && if (kex_alg_by_name(p) == NULL) {
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)) {
error("Unsupported KEX algorithm \"%.100s\"", p); error("Unsupported KEX algorithm \"%.100s\"", p);
xfree(s); xfree(s);
return 0; return 0;
@ -348,29 +391,16 @@ choose_comp(Comp *comp, char *client, char *server)
static void static void
choose_kex(Kex *k, char *client, char *server) choose_kex(Kex *k, char *client, char *server)
{ {
const struct kexalg *kexalg;
k->name = match_list(client, server, NULL); k->name = match_list(client, server, NULL);
if (k->name == NULL) if (k->name == NULL)
fatal("Unable to negotiate a key exchange method"); fatal("Unable to negotiate a key exchange method");
if (strcmp(k->name, KEX_DH1) == 0) { if ((kexalg = kex_alg_by_name(k->name)) == NULL)
k->kex_type = KEX_DH_GRP1_SHA1; fatal("unsupported kex alg %s", k->name);
k->evp_md = EVP_sha1(); k->kex_type = kexalg->type;
} else if (strcmp(k->name, KEX_DH14) == 0) { k->evp_md = kexalg->mdfunc();
k->kex_type = KEX_DH_GRP14_SHA1; k->ec_nid = kexalg->ec_nid;
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);
} }
static void static void

16
kex.h
View File

@ -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. * 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_SHA1 "diffie-hellman-group-exchange-sha1"
#define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256" #define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256"
#define KEX_RESUME "resume@appgate.com" #define KEX_RESUME "resume@appgate.com"
/* The following represents the family of ECDH methods */ #define KEX_ECDH_SHA2_NISTP256 "ecdh-sha2-nistp256"
#define KEX_ECDH_SHA2_STEM "ecdh-sha2-" #define KEX_ECDH_SHA2_NISTP384 "ecdh-sha2-nistp384"
#define KEX_ECDH_SHA2_NISTP521 "ecdh-sha2-nistp521"
#define COMP_NONE 0 #define COMP_NONE 0
#define COMP_ZLIB 1 #define COMP_ZLIB 1
@ -86,7 +87,7 @@ typedef struct Newkeys Newkeys;
struct Enc { struct Enc {
char *name; char *name;
Cipher *cipher; const Cipher *cipher;
int enabled; int enabled;
u_int key_len; u_int key_len;
u_int iv_len; u_int iv_len;
@ -131,6 +132,7 @@ struct Kex {
sig_atomic_t done; sig_atomic_t done;
int flags; int flags;
const EVP_MD *evp_md; const EVP_MD *evp_md;
int ec_nid;
char *client_version_string; char *client_version_string;
char *server_version_string; char *server_version_string;
int (*verify_host_key)(Key *); int (*verify_host_key)(Key *);
@ -141,6 +143,7 @@ struct Kex {
}; };
int kex_names_valid(const char *); int kex_names_valid(const char *);
char *kex_alg_list(void);
Kex *kex_setup(char *[PROPOSAL_MAX]); Kex *kex_setup(char *[PROPOSAL_MAX]);
void kex_finish(Kex *); void kex_finish(Kex *);
@ -170,11 +173,6 @@ void
kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int, kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int,
char *, int, u_char *, int, const EC_POINT *, const EC_POINT *, char *, int, u_char *, int, const EC_POINT *, const EC_POINT *,
const BIGNUM *, u_char **, u_int *); 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 #endif
void void

View File

@ -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) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved.
@ -45,24 +45,6 @@
#include "kex.h" #include "kex.h"
#include "log.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 void
kex_ecdh_hash( kex_ecdh_hash(
const EVP_MD *evp_md, const EVP_MD *evp_md,

View File

@ -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) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. 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 *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash; u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen; u_int klen, slen, sbloblen, hashlen;
int curve_nid;
if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
if ((client_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__); fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(client_key) != 1) if (EC_KEY_generate_key(client_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__); fatal("%s: EC_KEY_generate_key failed", __func__);

View File

@ -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) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2010 Damien Miller. 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 *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf, *hash; u_char *kbuf, *hash;
u_int klen, slen, sbloblen, hashlen; u_int klen, slen, sbloblen, hashlen;
int curve_nid;
if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
fatal("%s: EC_KEY_new_by_curve_name failed", __func__); fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
if (EC_KEY_generate_key(server_key) != 1) if (EC_KEY_generate_key(server_key) != 1)
fatal("%s: EC_KEY_generate_key failed", __func__); fatal("%s: EC_KEY_generate_key failed", __func__);

230
key.c
View File

@ -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(): * read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -891,36 +891,6 @@ key_write(const Key *key, FILE *f)
return success; return success;
} }
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 * const char *
key_cert_type(const Key *k) key_cert_type(const Key *k)
{ {
@ -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 * static const char *
key_ssh_name_from_type_nid(int type, int nid) key_ssh_name_from_type_nid(int type, int nid)
{ {
switch (type) { const struct keytype *kt;
case KEY_RSA:
return "ssh-rsa"; for (kt = keytypes; kt->type != -1; kt++) {
case KEY_DSA: if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
return "ssh-dss"; return kt->name;
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 */
} }
return "ssh-unknown"; return "ssh-unknown";
} }
@ -993,6 +974,56 @@ key_ssh_name_plain(const Key *k)
k->ecdsa_nid); 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 u_int
key_size(const Key *k) key_size(const Key *k)
{ {
@ -1247,65 +1278,6 @@ key_from_private(const Key *k)
return n; return n;
} }
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 int
key_names_valid2(const char *names) key_names_valid2(const char *names)
{ {

7
key.h
View File

@ -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. * 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_ecdsa_nid_from_name(const char *);
int key_curve_name_to_nid(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); u_int key_curve_nid_to_bits(int);
int key_ecdsa_bits_to_nid(int); int key_ecdsa_bits_to_nid(int);
#ifdef OPENSSL_HAS_ECC #ifdef OPENSSL_HAS_ECC
int key_ecdsa_key_to_nid(EC_KEY *); 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_public(const EC_GROUP *, const EC_POINT *);
int key_ec_validate_private(const EC_KEY *); int key_ec_validate_private(const EC_KEY *);
#endif #endif
char *key_alg_list(void);
Key *key_from_blob(const u_char *, u_int); Key *key_from_blob(const u_char *, u_int);
int key_to_blob(const Key *, u_char **, u_int *); int key_to_blob(const Key *, u_char **, u_int *);

60
mac.c
View File

@ -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. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* *
@ -50,7 +50,7 @@
#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ #define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */
#define SSH_UMAC128 3 #define SSH_UMAC128 3
struct { struct macalg {
char *name; char *name;
int type; int type;
const EVP_MD * (*mdfunc)(void); const EVP_MD * (*mdfunc)(void);
@ -58,7 +58,9 @@ struct {
int key_len; /* just for UMAC */ int key_len; /* just for UMAC */
int len; /* just for UMAC */ int len; /* just for UMAC */
int etm; /* Encrypt-then-MAC */ int etm; /* Encrypt-then-MAC */
} macs[] = { };
static const struct macalg macs[] = {
/* Encrypt-and-MAC (encrypt-and-authenticate) variants */ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */
{ "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 }, { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 },
{ "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 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 } { 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 static void
mac_setup_by_id(Mac *mac, int which) mac_setup_by_alg(Mac *mac, const struct macalg *macalg)
{ {
int evp_len; int evp_len;
mac->type = macs[which].type;
mac->type = macalg->type;
if (mac->type == SSH_EVP) { 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) if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
fatal("mac %s len %d", mac->name, evp_len); fatal("mac %s len %d", mac->name, evp_len);
mac->key_len = mac->mac_len = (u_int)evp_len; mac->key_len = mac->mac_len = (u_int)evp_len;
} else { } else {
mac->mac_len = macs[which].len / 8; mac->mac_len = macalg->len / 8;
mac->key_len = macs[which].key_len / 8; mac->key_len = macalg->key_len / 8;
mac->umac_ctx = NULL; mac->umac_ctx = NULL;
} }
if (macs[which].truncatebits != 0) if (macalg->truncatebits != 0)
mac->mac_len = macs[which].truncatebits / 8; mac->mac_len = macalg->truncatebits / 8;
mac->etm = macs[which].etm; mac->etm = macalg->etm;
} }
int int
mac_setup(Mac *mac, char *name) mac_setup(Mac *mac, char *name)
{ {
int i; const struct macalg *m;
for (i = 0; macs[i].name; i++) { for (m = macs; m->name != NULL; m++) {
if (strcmp(name, macs[i].name) == 0) { if (strcmp(name, m->name) != 0)
if (mac != NULL) continue;
mac_setup_by_id(mac, i); if (mac != NULL)
debug2("mac_setup: found %s", name); mac_setup_by_alg(mac, m);
return (0); debug2("mac_setup: found %s", name);
} return (0);
} }
debug2("mac_setup: unknown %s", name); debug2("mac_setup: unknown %s", name);
return (-1); return (-1);

3
mac.h
View File

@ -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. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* *
@ -24,6 +24,7 @@
*/ */
int mac_valid(const char *); int mac_valid(const char *);
char *mac_alg_list(void);
int mac_setup(Mac *, char *); int mac_setup(Mac *, char *);
int mac_init(Mac *); int mac_init(Mac *);
u_char *mac_compute(Mac *, u_int32_t, u_char *, int); u_char *mac_compute(Mac *, u_int32_t, u_char *, int);

View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -215,7 +215,7 @@ alloc_session_state(void)
void void
packet_set_connection(int fd_in, int fd_out) 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) if (none == NULL)
fatal("packet_set_connection: cannot load cipher 'none'"); fatal("packet_set_connection: cannot load cipher 'none'");
@ -545,7 +545,7 @@ packet_start_compression(int level)
void void
packet_set_encryption_key(const u_char *key, u_int keylen, int number) 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) if (cipher == NULL)
fatal("packet_set_encryption_key: unknown cipher number %d", number); fatal("packet_set_encryption_key: unknown cipher number %d", number);

21
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" 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 $ .\" $OpenBSD: ssh.1,v 1.332 2013/04/19 01:06:50 djm Exp $
.Dd $Mdocdate: April 7 2013 $ .Dd $Mdocdate: April 19 2013 $
.Dt SSH 1 .Dt SSH 1
.Os .Os
.Sh NAME .Sh NAME
@ -65,6 +65,8 @@
.Oo Ar user Ns @ Oc Ns Ar hostname .Oo Ar user Ns @ Oc Ns Ar hostname
.Op Ar command .Op Ar command
.Ek .Ek
.Nm
.Fl Q Ar protocol_feature
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
(SSH client) is a program for logging into a remote machine and for (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. Port to connect to on the remote host.
This can be specified on a This can be specified on a
per-host basis in the configuration file. 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 .It Fl q
Quiet mode. Quiet mode.
Causes most warning and diagnostic messages to be suppressed. Causes most warning and diagnostic messages to be suppressed.

20
ssh.c
View File

@ -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> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -327,7 +327,7 @@ main(int ac, char **av)
again: again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 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) { switch (opt) {
case '1': case '1':
options.protocol = SSH_PROTO_1; options.protocol = SSH_PROTO_1;
@ -389,6 +389,22 @@ main(int ac, char **av)
case 'P': /* deprecated */ case 'P': /* deprecated */
options.use_privileged_port = 0; options.use_privileged_port = 0;
break; 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': case 'a':
options.forward_agent = 0; options.forward_agent = 0;
break; break;