summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--authfile.c6
-rw-r--r--cipher.c55
-rw-r--r--cipher.h13
-rw-r--r--kex.c86
-rw-r--r--kex.h16
-rw-r--r--kexecdh.c20
-rw-r--r--kexecdhc.c7
-rw-r--r--kexecdhs.c7
-rw-r--r--key.c230
-rw-r--r--key.h7
-rw-r--r--mac.c62
-rw-r--r--mac.h3
-rw-r--r--packet.c6
-rw-r--r--ssh.121
-rw-r--r--ssh.c20
16 files changed, 314 insertions, 251 deletions
diff --git a/ChangeLog b/ChangeLog
index 0966a11bb..3d2950e8c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -69,6 +69,12 @@
69 reintroduce 1.262 without the connection-killing bug: 69 reintroduce 1.262 without the connection-killing bug:
70 fatal() when ChrootDirectory specified by running without root privileges; 70 fatal() when ChrootDirectory specified by running without root privileges;
71 ok markus@ 71 ok markus@
72 - djm@cvs.openbsd.org 2013/04/19 01:06:50
73 [authfile.c cipher.c cipher.h kex.c kex.h kexecdh.c kexecdhc.c kexecdhs.c]
74 [key.c key.h mac.c mac.h packet.c ssh.1 ssh.c]
75 add the ability to query supported ciphers, MACs, key type and KEX
76 algorithms to ssh. Includes some refactoring of KEX and key type handling
77 to be table-driven; ok markus@
72 78
7320130418 7920130418
74 - (djm) [config.guess config.sub] Update to last versions before they switch 80 - (djm) [config.guess config.sub] Update to last versions before they switch
diff --git a/authfile.c b/authfile.c
index 3544d170b..91812bf87 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfile.c,v 1.95 2013/01/08 18:49:04 markus Exp $ */ 1/* $OpenBSD: authfile.c,v 1.96 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * 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,
89 u_char buf[100], *cp; 89 u_char buf[100], *cp;
90 int i, cipher_num; 90 int i, cipher_num;
91 CipherContext ciphercontext; 91 CipherContext ciphercontext;
92 Cipher *cipher; 92 const Cipher *cipher;
93 u_int32_t rnd; 93 u_int32_t rnd;
94 94
95 /* 95 /*
@@ -421,7 +421,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
421 Buffer decrypted; 421 Buffer decrypted;
422 u_char *cp; 422 u_char *cp;
423 CipherContext ciphercontext; 423 CipherContext ciphercontext;
424 Cipher *cipher; 424 const Cipher *cipher;
425 Key *prv = NULL; 425 Key *prv = NULL;
426 Buffer copy; 426 Buffer copy;
427 427
diff --git a/cipher.c b/cipher.c
index 9ca1d0065..5e3652135 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher.c,v 1.87 2013/01/26 06:11:05 djm Exp $ */ 1/* $OpenBSD: cipher.c,v 1.88 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -65,7 +65,9 @@ struct Cipher {
65 u_int discard_len; 65 u_int discard_len;
66 u_int cbc_mode; 66 u_int cbc_mode;
67 const EVP_CIPHER *(*evptype)(void); 67 const EVP_CIPHER *(*evptype)(void);
68} ciphers[] = { 68};
69
70static const struct Cipher ciphers[] = {
69 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, 71 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
70 { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, 72 { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
71 { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, 73 { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
@@ -98,6 +100,27 @@ struct Cipher {
98 100
99/*--*/ 101/*--*/
100 102
103/* Returns a comma-separated list of supported ciphers. */
104char *
105cipher_alg_list(void)
106{
107 char *ret = NULL;
108 size_t nlen, rlen = 0;
109 const Cipher *c;
110
111 for (c = ciphers; c->name != NULL; c++) {
112 if (c->number != SSH_CIPHER_SSH2)
113 continue;
114 if (ret != NULL)
115 ret[rlen++] = '\n';
116 nlen = strlen(c->name);
117 ret = xrealloc(ret, 1, rlen + nlen + 2);
118 memcpy(ret + rlen, c->name, nlen + 1);
119 rlen += nlen;
120 }
121 return ret;
122}
123
101u_int 124u_int
102cipher_blocksize(const Cipher *c) 125cipher_blocksize(const Cipher *c)
103{ 126{
@@ -146,20 +169,20 @@ cipher_mask_ssh1(int client)
146 return mask; 169 return mask;
147} 170}
148 171
149Cipher * 172const Cipher *
150cipher_by_name(const char *name) 173cipher_by_name(const char *name)
151{ 174{
152 Cipher *c; 175 const Cipher *c;
153 for (c = ciphers; c->name != NULL; c++) 176 for (c = ciphers; c->name != NULL; c++)
154 if (strcmp(c->name, name) == 0) 177 if (strcmp(c->name, name) == 0)
155 return c; 178 return c;
156 return NULL; 179 return NULL;
157} 180}
158 181
159Cipher * 182const Cipher *
160cipher_by_number(int id) 183cipher_by_number(int id)
161{ 184{
162 Cipher *c; 185 const Cipher *c;
163 for (c = ciphers; c->name != NULL; c++) 186 for (c = ciphers; c->name != NULL; c++)
164 if (c->number == id) 187 if (c->number == id)
165 return c; 188 return c;
@@ -170,7 +193,7 @@ cipher_by_number(int id)
170int 193int
171ciphers_valid(const char *names) 194ciphers_valid(const char *names)
172{ 195{
173 Cipher *c; 196 const Cipher *c;
174 char *cipher_list, *cp; 197 char *cipher_list, *cp;
175 char *p; 198 char *p;
176 199
@@ -201,7 +224,7 @@ ciphers_valid(const char *names)
201int 224int
202cipher_number(const char *name) 225cipher_number(const char *name)
203{ 226{
204 Cipher *c; 227 const Cipher *c;
205 if (name == NULL) 228 if (name == NULL)
206 return -1; 229 return -1;
207 for (c = ciphers; c->name != NULL; c++) 230 for (c = ciphers; c->name != NULL; c++)
@@ -213,12 +236,12 @@ cipher_number(const char *name)
213char * 236char *
214cipher_name(int id) 237cipher_name(int id)
215{ 238{
216 Cipher *c = cipher_by_number(id); 239 const Cipher *c = cipher_by_number(id);
217 return (c==NULL) ? "<unknown>" : c->name; 240 return (c==NULL) ? "<unknown>" : c->name;
218} 241}
219 242
220void 243void
221cipher_init(CipherContext *cc, Cipher *cipher, 244cipher_init(CipherContext *cc, const Cipher *cipher,
222 const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, 245 const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
223 int do_encrypt) 246 int do_encrypt)
224{ 247{
@@ -364,7 +387,7 @@ cipher_cleanup(CipherContext *cc)
364 */ 387 */
365 388
366void 389void
367cipher_set_key_string(CipherContext *cc, Cipher *cipher, 390cipher_set_key_string(CipherContext *cc, const Cipher *cipher,
368 const char *passphrase, int do_encrypt) 391 const char *passphrase, int do_encrypt)
369{ 392{
370 MD5_CTX md; 393 MD5_CTX md;
@@ -389,7 +412,7 @@ cipher_set_key_string(CipherContext *cc, Cipher *cipher,
389int 412int
390cipher_get_keyiv_len(const CipherContext *cc) 413cipher_get_keyiv_len(const CipherContext *cc)
391{ 414{
392 Cipher *c = cc->cipher; 415 const Cipher *c = cc->cipher;
393 int ivlen; 416 int ivlen;
394 417
395 if (c->number == SSH_CIPHER_3DES) 418 if (c->number == SSH_CIPHER_3DES)
@@ -402,7 +425,7 @@ cipher_get_keyiv_len(const CipherContext *cc)
402void 425void
403cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) 426cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
404{ 427{
405 Cipher *c = cc->cipher; 428 const Cipher *c = cc->cipher;
406 int evplen; 429 int evplen;
407 430
408 switch (c->number) { 431 switch (c->number) {
@@ -438,7 +461,7 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
438void 461void
439cipher_set_keyiv(CipherContext *cc, u_char *iv) 462cipher_set_keyiv(CipherContext *cc, u_char *iv)
440{ 463{
441 Cipher *c = cc->cipher; 464 const Cipher *c = cc->cipher;
442 int evplen = 0; 465 int evplen = 0;
443 466
444 switch (c->number) { 467 switch (c->number) {
@@ -471,7 +494,7 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv)
471int 494int
472cipher_get_keycontext(const CipherContext *cc, u_char *dat) 495cipher_get_keycontext(const CipherContext *cc, u_char *dat)
473{ 496{
474 Cipher *c = cc->cipher; 497 const Cipher *c = cc->cipher;
475 int plen = 0; 498 int plen = 0;
476 499
477 if (c->evptype == EVP_rc4) { 500 if (c->evptype == EVP_rc4) {
@@ -486,7 +509,7 @@ cipher_get_keycontext(const CipherContext *cc, u_char *dat)
486void 509void
487cipher_set_keycontext(CipherContext *cc, u_char *dat) 510cipher_set_keycontext(CipherContext *cc, u_char *dat)
488{ 511{
489 Cipher *c = cc->cipher; 512 const Cipher *c = cc->cipher;
490 int plen; 513 int plen;
491 514
492 if (c->evptype == EVP_rc4) { 515 if (c->evptype == EVP_rc4) {
diff --git a/cipher.h b/cipher.h
index 8cb57c3e5..b878d50f4 100644
--- a/cipher.h
+++ b/cipher.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: cipher.h,v 1.39 2013/01/08 18:49:04 markus Exp $ */ 1/* $OpenBSD: cipher.h,v 1.40 2013/04/19 01:06:50 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -66,21 +66,22 @@ struct CipherContext {
66 int plaintext; 66 int plaintext;
67 int encrypt; 67 int encrypt;
68 EVP_CIPHER_CTX evp; 68 EVP_CIPHER_CTX evp;
69 Cipher *cipher; 69 const Cipher *cipher;
70}; 70};
71 71
72u_int cipher_mask_ssh1(int); 72u_int cipher_mask_ssh1(int);
73Cipher *cipher_by_name(const char *); 73const Cipher *cipher_by_name(const char *);
74Cipher *cipher_by_number(int); 74const Cipher *cipher_by_number(int);
75int cipher_number(const char *); 75int cipher_number(const char *);
76char *cipher_name(int); 76char *cipher_name(int);
77int ciphers_valid(const char *); 77int ciphers_valid(const char *);
78void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, 78char *cipher_alg_list(void);
79void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int,
79 const u_char *, u_int, int); 80 const u_char *, u_int, int);
80void cipher_crypt(CipherContext *, u_char *, const u_char *, 81void cipher_crypt(CipherContext *, u_char *, const u_char *,
81 u_int, u_int, u_int); 82 u_int, u_int, u_int);
82void cipher_cleanup(CipherContext *); 83void cipher_cleanup(CipherContext *);
83void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); 84void cipher_set_key_string(CipherContext *, const Cipher *, const char *, int);
84u_int cipher_blocksize(const Cipher *); 85u_int cipher_blocksize(const Cipher *);
85u_int cipher_keylen(const Cipher *); 86u_int cipher_keylen(const Cipher *);
86u_int cipher_authlen(const Cipher *); 87u_int cipher_authlen(const Cipher *);
diff --git a/kex.c b/kex.c
index 57a79dd9e..65a227bc1 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.c,v 1.88 2013/01/08 18:49:04 markus Exp $ */ 1/* $OpenBSD: kex.c,v 1.89 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -62,6 +62,55 @@ extern const EVP_MD *evp_ssh_sha256(void);
62static void kex_kexinit_finish(Kex *); 62static void kex_kexinit_finish(Kex *);
63static void kex_choose_conf(Kex *); 63static void kex_choose_conf(Kex *);
64 64
65struct kexalg {
66 char *name;
67 int type;
68 int ec_nid;
69 const EVP_MD *(*mdfunc)(void);
70};
71static const struct kexalg kexalgs[] = {
72 { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 },
73 { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 },
74 { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 },
75#if OPENSSL_VERSION_NUMBER >= 0x00907000L
76 { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 },
77 { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 },
78 { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 },
79 { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 },
80#endif
81 { NULL, -1, -1, NULL},
82};
83
84char *
85kex_alg_list(void)
86{
87 char *ret = NULL;
88 size_t nlen, rlen = 0;
89 const struct kexalg *k;
90
91 for (k = kexalgs; k->name != NULL; k++) {
92 if (ret != NULL)
93 ret[rlen++] = '\n';
94 nlen = strlen(k->name);
95 ret = xrealloc(ret, 1, rlen + nlen + 2);
96 memcpy(ret + rlen, k->name, nlen + 1);
97 rlen += nlen;
98 }
99 return ret;
100}
101
102static const struct kexalg *
103kex_alg_by_name(const char *name)
104{
105 const struct kexalg *k;
106
107 for (k = kexalgs; k->name != NULL; k++) {
108 if (strcmp(k->name, name) == 0)
109 return k;
110 }
111 return NULL;
112}
113
65/* Validate KEX method name list */ 114/* Validate KEX method name list */
66int 115int
67kex_names_valid(const char *names) 116kex_names_valid(const char *names)
@@ -73,13 +122,7 @@ kex_names_valid(const char *names)
73 s = cp = xstrdup(names); 122 s = cp = xstrdup(names);
74 for ((p = strsep(&cp, ",")); p && *p != '\0'; 123 for ((p = strsep(&cp, ",")); p && *p != '\0';
75 (p = strsep(&cp, ","))) { 124 (p = strsep(&cp, ","))) {
76 if (strcmp(p, KEX_DHGEX_SHA256) != 0 && 125 if (kex_alg_by_name(p) == NULL) {
77 strcmp(p, KEX_DHGEX_SHA1) != 0 &&
78 strcmp(p, KEX_DH14) != 0 &&
79 strcmp(p, KEX_DH1) != 0 &&
80 (strncmp(p, KEX_ECDH_SHA2_STEM,
81 sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 ||
82 kex_ecdh_name_to_nid(p) == -1)) {
83 error("Unsupported KEX algorithm \"%.100s\"", p); 126 error("Unsupported KEX algorithm \"%.100s\"", p);
84 xfree(s); 127 xfree(s);
85 return 0; 128 return 0;
@@ -348,29 +391,16 @@ choose_comp(Comp *comp, char *client, char *server)
348static void 391static void
349choose_kex(Kex *k, char *client, char *server) 392choose_kex(Kex *k, char *client, char *server)
350{ 393{
394 const struct kexalg *kexalg;
395
351 k->name = match_list(client, server, NULL); 396 k->name = match_list(client, server, NULL);
352 if (k->name == NULL) 397 if (k->name == NULL)
353 fatal("Unable to negotiate a key exchange method"); 398 fatal("Unable to negotiate a key exchange method");
354 if (strcmp(k->name, KEX_DH1) == 0) { 399 if ((kexalg = kex_alg_by_name(k->name)) == NULL)
355 k->kex_type = KEX_DH_GRP1_SHA1; 400 fatal("unsupported kex alg %s", k->name);
356 k->evp_md = EVP_sha1(); 401 k->kex_type = kexalg->type;
357 } else if (strcmp(k->name, KEX_DH14) == 0) { 402 k->evp_md = kexalg->mdfunc();
358 k->kex_type = KEX_DH_GRP14_SHA1; 403 k->ec_nid = kexalg->ec_nid;
359 k->evp_md = EVP_sha1();
360 } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) {
361 k->kex_type = KEX_DH_GEX_SHA1;
362 k->evp_md = EVP_sha1();
363#if OPENSSL_VERSION_NUMBER >= 0x00907000L
364 } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) {
365 k->kex_type = KEX_DH_GEX_SHA256;
366 k->evp_md = evp_ssh_sha256();
367 } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM,
368 sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) {
369 k->kex_type = KEX_ECDH_SHA2;
370 k->evp_md = kex_ecdh_name_to_evpmd(k->name);
371#endif
372 } else
373 fatal("bad kex alg %s", k->name);
374} 404}
375 405
376static void 406static void
diff --git a/kex.h b/kex.h
index 46731fa45..680264af2 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.h,v 1.54 2013/01/08 18:49:04 markus Exp $ */ 1/* $OpenBSD: kex.h,v 1.55 2013/04/19 01:06:50 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -40,8 +40,9 @@
40#define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1" 40#define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1"
41#define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256" 41#define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256"
42#define KEX_RESUME "resume@appgate.com" 42#define KEX_RESUME "resume@appgate.com"
43/* The following represents the family of ECDH methods */ 43#define KEX_ECDH_SHA2_NISTP256 "ecdh-sha2-nistp256"
44#define KEX_ECDH_SHA2_STEM "ecdh-sha2-" 44#define KEX_ECDH_SHA2_NISTP384 "ecdh-sha2-nistp384"
45#define KEX_ECDH_SHA2_NISTP521 "ecdh-sha2-nistp521"
45 46
46#define COMP_NONE 0 47#define COMP_NONE 0
47#define COMP_ZLIB 1 48#define COMP_ZLIB 1
@@ -86,7 +87,7 @@ typedef struct Newkeys Newkeys;
86 87
87struct Enc { 88struct Enc {
88 char *name; 89 char *name;
89 Cipher *cipher; 90 const Cipher *cipher;
90 int enabled; 91 int enabled;
91 u_int key_len; 92 u_int key_len;
92 u_int iv_len; 93 u_int iv_len;
@@ -131,6 +132,7 @@ struct Kex {
131 sig_atomic_t done; 132 sig_atomic_t done;
132 int flags; 133 int flags;
133 const EVP_MD *evp_md; 134 const EVP_MD *evp_md;
135 int ec_nid;
134 char *client_version_string; 136 char *client_version_string;
135 char *server_version_string; 137 char *server_version_string;
136 int (*verify_host_key)(Key *); 138 int (*verify_host_key)(Key *);
@@ -141,6 +143,7 @@ struct Kex {
141}; 143};
142 144
143int kex_names_valid(const char *); 145int kex_names_valid(const char *);
146char *kex_alg_list(void);
144 147
145Kex *kex_setup(char *[PROPOSAL_MAX]); 148Kex *kex_setup(char *[PROPOSAL_MAX]);
146void kex_finish(Kex *); 149void kex_finish(Kex *);
@@ -170,11 +173,6 @@ void
170kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int, 173kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int,
171 char *, int, u_char *, int, const EC_POINT *, const EC_POINT *, 174 char *, int, u_char *, int, const EC_POINT *, const EC_POINT *,
172 const BIGNUM *, u_char **, u_int *); 175 const BIGNUM *, u_char **, u_int *);
173int kex_ecdh_name_to_nid(const char *);
174const EVP_MD *kex_ecdh_name_to_evpmd(const char *);
175#else
176# define kex_ecdh_name_to_nid(x) (-1)
177# define kex_ecdh_name_to_evpmd(x) (NULL)
178#endif 176#endif
179 177
180void 178void
diff --git a/kexecdh.c b/kexecdh.c
index f13f69d3b..c948fe20a 100644
--- a/kexecdh.c
+++ b/kexecdh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexecdh.c,v 1.3 2010/09/22 05:01:29 djm Exp $ */ 1/* $OpenBSD: kexecdh.c,v 1.4 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -45,24 +45,6 @@
45#include "kex.h" 45#include "kex.h"
46#include "log.h" 46#include "log.h"
47 47
48int
49kex_ecdh_name_to_nid(const char *kexname)
50{
51 if (strlen(kexname) < sizeof(KEX_ECDH_SHA2_STEM) - 1)
52 fatal("%s: kexname too short \"%s\"", __func__, kexname);
53 return key_curve_name_to_nid(kexname + sizeof(KEX_ECDH_SHA2_STEM) - 1);
54}
55
56const EVP_MD *
57kex_ecdh_name_to_evpmd(const char *kexname)
58{
59 int nid = kex_ecdh_name_to_nid(kexname);
60
61 if (nid == -1)
62 fatal("%s: unsupported ECDH curve \"%s\"", __func__, kexname);
63 return key_ec_nid_to_evpmd(nid);
64}
65
66void 48void
67kex_ecdh_hash( 49kex_ecdh_hash(
68 const EVP_MD *evp_md, 50 const EVP_MD *evp_md,
diff --git a/kexecdhc.c b/kexecdhc.c
index 115d4bf83..04239a471 100644
--- a/kexecdhc.c
+++ b/kexecdhc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexecdhc.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */ 1/* $OpenBSD: kexecdhc.c,v 1.3 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -57,11 +57,8 @@ kexecdh_client(Kex *kex)
57 u_char *server_host_key_blob = NULL, *signature = NULL; 57 u_char *server_host_key_blob = NULL, *signature = NULL;
58 u_char *kbuf, *hash; 58 u_char *kbuf, *hash;
59 u_int klen, slen, sbloblen, hashlen; 59 u_int klen, slen, sbloblen, hashlen;
60 int curve_nid;
61 60
62 if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) 61 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
63 fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
64 if ((client_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
65 fatal("%s: EC_KEY_new_by_curve_name failed", __func__); 62 fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
66 if (EC_KEY_generate_key(client_key) != 1) 63 if (EC_KEY_generate_key(client_key) != 1)
67 fatal("%s: EC_KEY_generate_key failed", __func__); 64 fatal("%s: EC_KEY_generate_key failed", __func__);
diff --git a/kexecdhs.c b/kexecdhs.c
index 8c515dfa6..6519abbef 100644
--- a/kexecdhs.c
+++ b/kexecdhs.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexecdhs.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */ 1/* $OpenBSD: kexecdhs.c,v 1.3 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -59,11 +59,8 @@ kexecdh_server(Kex *kex)
59 u_char *server_host_key_blob = NULL, *signature = NULL; 59 u_char *server_host_key_blob = NULL, *signature = NULL;
60 u_char *kbuf, *hash; 60 u_char *kbuf, *hash;
61 u_int klen, slen, sbloblen, hashlen; 61 u_int klen, slen, sbloblen, hashlen;
62 int curve_nid;
63 62
64 if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) 63 if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL)
65 fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
66 if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
67 fatal("%s: EC_KEY_new_by_curve_name failed", __func__); 64 fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
68 if (EC_KEY_generate_key(server_key) != 1) 65 if (EC_KEY_generate_key(server_key) != 1)
69 fatal("%s: EC_KEY_generate_key failed", __func__); 66 fatal("%s: EC_KEY_generate_key failed", __func__);
diff --git a/key.c b/key.c
index 4cc5c5d35..471cd1fcc 100644
--- a/key.c
+++ b/key.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: key.c,v 1.100 2013/01/17 23:00:01 djm Exp $ */ 1/* $OpenBSD: key.c,v 1.101 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * read_bignum(): 3 * read_bignum():
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -892,36 +892,6 @@ key_write(const Key *key, FILE *f)
892} 892}
893 893
894const char * 894const char *
895key_type(const Key *k)
896{
897 switch (k->type) {
898 case KEY_RSA1:
899 return "RSA1";
900 case KEY_RSA:
901 return "RSA";
902 case KEY_DSA:
903 return "DSA";
904#ifdef OPENSSL_HAS_ECC
905 case KEY_ECDSA:
906 return "ECDSA";
907#endif
908 case KEY_RSA_CERT_V00:
909 return "RSA-CERT-V00";
910 case KEY_DSA_CERT_V00:
911 return "DSA-CERT-V00";
912 case KEY_RSA_CERT:
913 return "RSA-CERT";
914 case KEY_DSA_CERT:
915 return "DSA-CERT";
916#ifdef OPENSSL_HAS_ECC
917 case KEY_ECDSA_CERT:
918 return "ECDSA-CERT";
919#endif
920 }
921 return "unknown";
922}
923
924const char *
925key_cert_type(const Key *k) 895key_cert_type(const Key *k)
926{ 896{
927 switch (k->cert->type) { 897 switch (k->cert->type) {
@@ -934,48 +904,59 @@ key_cert_type(const Key *k)
934 } 904 }
935} 905}
936 906
907struct keytype {
908 char *name;
909 char *shortname;
910 int type;
911 int nid;
912 int cert;
913};
914static const struct keytype keytypes[] = {
915 { NULL, "RSA1", KEY_RSA1, 0, 0 },
916 { "ssh-rsa", "RSA", KEY_RSA, 0, 0 },
917 { "ssh-dss", "DSA", KEY_DSA, 0, 0 },
918#ifdef OPENSSL_HAS_ECC
919 { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0 },
920 { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0 },
921 { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0 },
922#endif /* OPENSSL_HAS_ECC */
923 { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1 },
924 { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1 },
925#ifdef OPENSSL_HAS_ECC
926 { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT",
927 KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1 },
928 { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT",
929 KEY_ECDSA_CERT, NID_secp384r1, 1 },
930 { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT",
931 KEY_ECDSA_CERT, NID_secp521r1, 1 },
932#endif /* OPENSSL_HAS_ECC */
933 { "ssh-rsa-cert-v00@openssh.com", "RSA-CERT-V00",
934 KEY_RSA_CERT_V00, 0, 1 },
935 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
936 KEY_DSA_CERT_V00, 0, 1 },
937 { NULL, NULL, -1, -1, 0 }
938};
939
940const char *
941key_type(const Key *k)
942{
943 const struct keytype *kt;
944
945 for (kt = keytypes; kt->type != -1; kt++) {
946 if (kt->type == k->type)
947 return kt->shortname;
948 }
949 return "unknown";
950}
951
937static const char * 952static const char *
938key_ssh_name_from_type_nid(int type, int nid) 953key_ssh_name_from_type_nid(int type, int nid)
939{ 954{
940 switch (type) { 955 const struct keytype *kt;
941 case KEY_RSA: 956
942 return "ssh-rsa"; 957 for (kt = keytypes; kt->type != -1; kt++) {
943 case KEY_DSA: 958 if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
944 return "ssh-dss"; 959 return kt->name;
945 case KEY_RSA_CERT_V00:
946 return "ssh-rsa-cert-v00@openssh.com";
947 case KEY_DSA_CERT_V00:
948 return "ssh-dss-cert-v00@openssh.com";
949 case KEY_RSA_CERT:
950 return "ssh-rsa-cert-v01@openssh.com";
951 case KEY_DSA_CERT:
952 return "ssh-dss-cert-v01@openssh.com";
953#ifdef OPENSSL_HAS_ECC
954 case KEY_ECDSA:
955 switch (nid) {
956 case NID_X9_62_prime256v1:
957 return "ecdsa-sha2-nistp256";
958 case NID_secp384r1:
959 return "ecdsa-sha2-nistp384";
960 case NID_secp521r1:
961 return "ecdsa-sha2-nistp521";
962 default:
963 break;
964 }
965 break;
966 case KEY_ECDSA_CERT:
967 switch (nid) {
968 case NID_X9_62_prime256v1:
969 return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
970 case NID_secp384r1:
971 return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
972 case NID_secp521r1:
973 return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
974 default:
975 break;
976 }
977 break;
978#endif /* OPENSSL_HAS_ECC */
979 } 960 }
980 return "ssh-unknown"; 961 return "ssh-unknown";
981} 962}
@@ -993,6 +974,56 @@ key_ssh_name_plain(const Key *k)
993 k->ecdsa_nid); 974 k->ecdsa_nid);
994} 975}
995 976
977int
978key_type_from_name(char *name)
979{
980 const struct keytype *kt;
981
982 for (kt = keytypes; kt->type != -1; kt++) {
983 /* Only allow shortname matches for plain key types */
984 if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
985 (!kt->cert && strcasecmp(kt->shortname, name) == 0))
986 return kt->type;
987 }
988 debug2("key_type_from_name: unknown key type '%s'", name);
989 return KEY_UNSPEC;
990}
991
992int
993key_ecdsa_nid_from_name(const char *name)
994{
995 const struct keytype *kt;
996
997 for (kt = keytypes; kt->type != -1; kt++) {
998 if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
999 continue;
1000 if (kt->name != NULL && strcmp(name, kt->name) == 0)
1001 return kt->nid;
1002 }
1003 debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
1004 return -1;
1005}
1006
1007char *
1008key_alg_list(void)
1009{
1010 char *ret = NULL;
1011 size_t nlen, rlen = 0;
1012 const struct keytype *kt;
1013
1014 for (kt = keytypes; kt->type != -1; kt++) {
1015 if (kt->name == NULL)
1016 continue;
1017 if (ret != NULL)
1018 ret[rlen++] = '\n';
1019 nlen = strlen(kt->name);
1020 ret = xrealloc(ret, 1, rlen + nlen + 2);
1021 memcpy(ret + rlen, kt->name, nlen + 1);
1022 rlen += nlen;
1023 }
1024 return ret;
1025}
1026
996u_int 1027u_int
997key_size(const Key *k) 1028key_size(const Key *k)
998{ 1029{
@@ -1248,65 +1279,6 @@ key_from_private(const Key *k)
1248} 1279}
1249 1280
1250int 1281int
1251key_type_from_name(char *name)
1252{
1253 if (strcmp(name, "rsa1") == 0) {
1254 return KEY_RSA1;
1255 } else if (strcmp(name, "rsa") == 0) {
1256 return KEY_RSA;
1257 } else if (strcmp(name, "dsa") == 0) {
1258 return KEY_DSA;
1259 } else if (strcmp(name, "ssh-rsa") == 0) {
1260 return KEY_RSA;
1261 } else if (strcmp(name, "ssh-dss") == 0) {
1262 return KEY_DSA;
1263#ifdef OPENSSL_HAS_ECC
1264 } else if (strcmp(name, "ecdsa") == 0 ||
1265 strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
1266 strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
1267 strcmp(name, "ecdsa-sha2-nistp521") == 0) {
1268 return KEY_ECDSA;
1269#endif
1270 } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) {
1271 return KEY_RSA_CERT_V00;
1272 } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) {
1273 return KEY_DSA_CERT_V00;
1274 } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
1275 return KEY_RSA_CERT;
1276 } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) {
1277 return KEY_DSA_CERT;
1278#ifdef OPENSSL_HAS_ECC
1279 } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0 ||
1280 strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0 ||
1281 strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
1282 return KEY_ECDSA_CERT;
1283#endif
1284 }
1285
1286 debug2("key_type_from_name: unknown key type '%s'", name);
1287 return KEY_UNSPEC;
1288}
1289
1290int
1291key_ecdsa_nid_from_name(const char *name)
1292{
1293#ifdef OPENSSL_HAS_ECC
1294 if (strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
1295 strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0)
1296 return NID_X9_62_prime256v1;
1297 if (strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
1298 strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0)
1299 return NID_secp384r1;
1300 if (strcmp(name, "ecdsa-sha2-nistp521") == 0 ||
1301 strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0)
1302 return NID_secp521r1;
1303#endif /* OPENSSL_HAS_ECC */
1304
1305 debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
1306 return -1;
1307}
1308
1309int
1310key_names_valid2(const char *names) 1282key_names_valid2(const char *names)
1311{ 1283{
1312 char *s, *cp, *p; 1284 char *s, *cp, *p;
diff --git a/key.h b/key.h
index ebdf45677..f2e058e9e 100644
--- a/key.h
+++ b/key.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: key.h,v 1.35 2013/01/17 23:00:01 djm Exp $ */ 1/* $OpenBSD: key.h,v 1.36 2013/04/19 01:06:50 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -118,15 +118,16 @@ int key_cert_is_legacy(const Key *);
118 118
119int key_ecdsa_nid_from_name(const char *); 119int key_ecdsa_nid_from_name(const char *);
120int key_curve_name_to_nid(const char *); 120int key_curve_name_to_nid(const char *);
121const char * key_curve_nid_to_name(int); 121const char *key_curve_nid_to_name(int);
122u_int key_curve_nid_to_bits(int); 122u_int key_curve_nid_to_bits(int);
123int key_ecdsa_bits_to_nid(int); 123int key_ecdsa_bits_to_nid(int);
124#ifdef OPENSSL_HAS_ECC 124#ifdef OPENSSL_HAS_ECC
125int key_ecdsa_key_to_nid(EC_KEY *); 125int key_ecdsa_key_to_nid(EC_KEY *);
126const EVP_MD * key_ec_nid_to_evpmd(int nid); 126const EVP_MD *key_ec_nid_to_evpmd(int nid);
127int key_ec_validate_public(const EC_GROUP *, const EC_POINT *); 127int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
128int key_ec_validate_private(const EC_KEY *); 128int key_ec_validate_private(const EC_KEY *);
129#endif 129#endif
130char *key_alg_list(void);
130 131
131Key *key_from_blob(const u_char *, u_int); 132Key *key_from_blob(const u_char *, u_int);
132int key_to_blob(const Key *, u_char **, u_int *); 133int key_to_blob(const Key *, u_char **, u_int *);
diff --git a/mac.c b/mac.c
index 3f2dc6f2a..da68803f5 100644
--- a/mac.c
+++ b/mac.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mac.c,v 1.21 2012/12/11 22:51:45 sthen Exp $ */ 1/* $OpenBSD: mac.c,v 1.22 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -50,7 +50,7 @@
50#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ 50#define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */
51#define SSH_UMAC128 3 51#define SSH_UMAC128 3
52 52
53struct { 53struct macalg {
54 char *name; 54 char *name;
55 int type; 55 int type;
56 const EVP_MD * (*mdfunc)(void); 56 const EVP_MD * (*mdfunc)(void);
@@ -58,7 +58,9 @@ struct {
58 int key_len; /* just for UMAC */ 58 int key_len; /* just for UMAC */
59 int len; /* just for UMAC */ 59 int len; /* just for UMAC */
60 int etm; /* Encrypt-then-MAC */ 60 int etm; /* Encrypt-then-MAC */
61} macs[] = { 61};
62
63static const struct macalg macs[] = {
62 /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ 64 /* Encrypt-and-MAC (encrypt-and-authenticate) variants */
63 { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 }, 65 { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 },
64 { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 }, 66 { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 },
@@ -89,38 +91,58 @@ struct {
89 { NULL, 0, NULL, 0, 0, 0, 0 } 91 { NULL, 0, NULL, 0, 0, 0, 0 }
90}; 92};
91 93
94/* Returns a comma-separated list of supported MACs. */
95char *
96mac_alg_list(void)
97{
98 char *ret = NULL;
99 size_t nlen, rlen = 0;
100 const struct macalg *m;
101
102 for (m = macs; m->name != NULL; m++) {
103 if (ret != NULL)
104 ret[rlen++] = '\n';
105 nlen = strlen(m->name);
106 ret = xrealloc(ret, 1, rlen + nlen + 2);
107 memcpy(ret + rlen, m->name, nlen + 1);
108 rlen += nlen;
109 }
110 return ret;
111}
112
92static void 113static void
93mac_setup_by_id(Mac *mac, int which) 114mac_setup_by_alg(Mac *mac, const struct macalg *macalg)
94{ 115{
95 int evp_len; 116 int evp_len;
96 mac->type = macs[which].type; 117
118 mac->type = macalg->type;
97 if (mac->type == SSH_EVP) { 119 if (mac->type == SSH_EVP) {
98 mac->evp_md = (*macs[which].mdfunc)(); 120 mac->evp_md = macalg->mdfunc();
99 if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0) 121 if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
100 fatal("mac %s len %d", mac->name, evp_len); 122 fatal("mac %s len %d", mac->name, evp_len);
101 mac->key_len = mac->mac_len = (u_int)evp_len; 123 mac->key_len = mac->mac_len = (u_int)evp_len;
102 } else { 124 } else {
103 mac->mac_len = macs[which].len / 8; 125 mac->mac_len = macalg->len / 8;
104 mac->key_len = macs[which].key_len / 8; 126 mac->key_len = macalg->key_len / 8;
105 mac->umac_ctx = NULL; 127 mac->umac_ctx = NULL;
106 } 128 }
107 if (macs[which].truncatebits != 0) 129 if (macalg->truncatebits != 0)
108 mac->mac_len = macs[which].truncatebits / 8; 130 mac->mac_len = macalg->truncatebits / 8;
109 mac->etm = macs[which].etm; 131 mac->etm = macalg->etm;
110} 132}
111 133
112int 134int
113mac_setup(Mac *mac, char *name) 135mac_setup(Mac *mac, char *name)
114{ 136{
115 int i; 137 const struct macalg *m;
116 138
117 for (i = 0; macs[i].name; i++) { 139 for (m = macs; m->name != NULL; m++) {
118 if (strcmp(name, macs[i].name) == 0) { 140 if (strcmp(name, m->name) != 0)
119 if (mac != NULL) 141 continue;
120 mac_setup_by_id(mac, i); 142 if (mac != NULL)
121 debug2("mac_setup: found %s", name); 143 mac_setup_by_alg(mac, m);
122 return (0); 144 debug2("mac_setup: found %s", name);
123 } 145 return (0);
124 } 146 }
125 debug2("mac_setup: unknown %s", name); 147 debug2("mac_setup: unknown %s", name);
126 return (-1); 148 return (-1);
diff --git a/mac.h b/mac.h
index 39f564dd3..260798ab3 100644
--- a/mac.h
+++ b/mac.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: mac.h,v 1.6 2007/06/07 19:37:34 pvalchev Exp $ */ 1/* $OpenBSD: mac.h,v 1.7 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -24,6 +24,7 @@
24 */ 24 */
25 25
26int mac_valid(const char *); 26int mac_valid(const char *);
27char *mac_alg_list(void);
27int mac_setup(Mac *, char *); 28int mac_setup(Mac *, char *);
28int mac_init(Mac *); 29int mac_init(Mac *);
29u_char *mac_compute(Mac *, u_int32_t, u_char *, int); 30u_char *mac_compute(Mac *, u_int32_t, u_char *, int);
diff --git a/packet.c b/packet.c
index 3e835d360..3c97383ec 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.c,v 1.182 2013/04/11 02:27:50 djm Exp $ */ 1/* $OpenBSD: packet.c,v 1.183 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -215,7 +215,7 @@ alloc_session_state(void)
215void 215void
216packet_set_connection(int fd_in, int fd_out) 216packet_set_connection(int fd_in, int fd_out)
217{ 217{
218 Cipher *none = cipher_by_name("none"); 218 const Cipher *none = cipher_by_name("none");
219 219
220 if (none == NULL) 220 if (none == NULL)
221 fatal("packet_set_connection: cannot load cipher 'none'"); 221 fatal("packet_set_connection: cannot load cipher 'none'");
@@ -545,7 +545,7 @@ packet_start_compression(int level)
545void 545void
546packet_set_encryption_key(const u_char *key, u_int keylen, int number) 546packet_set_encryption_key(const u_char *key, u_int keylen, int number)
547{ 547{
548 Cipher *cipher = cipher_by_number(number); 548 const Cipher *cipher = cipher_by_number(number);
549 549
550 if (cipher == NULL) 550 if (cipher == NULL)
551 fatal("packet_set_encryption_key: unknown cipher number %d", number); 551 fatal("packet_set_encryption_key: unknown cipher number %d", number);
diff --git a/ssh.1 b/ssh.1
index d77494b83..dc7af4864 100644
--- a/ssh.1
+++ b/ssh.1
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: ssh.1,v 1.331 2013/04/07 02:10:33 dtucker Exp $ 36.\" $OpenBSD: ssh.1,v 1.332 2013/04/19 01:06:50 djm Exp $
37.Dd $Mdocdate: April 7 2013 $ 37.Dd $Mdocdate: April 19 2013 $
38.Dt SSH 1 38.Dt SSH 1
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -65,6 +65,8 @@
65.Oo Ar user Ns @ Oc Ns Ar hostname 65.Oo Ar user Ns @ Oc Ns Ar hostname
66.Op Ar command 66.Op Ar command
67.Ek 67.Ek
68.Nm
69.Fl Q Ar protocol_feature
68.Sh DESCRIPTION 70.Sh DESCRIPTION
69.Nm 71.Nm
70(SSH client) is a program for logging into a remote machine and for 72(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
487Port to connect to on the remote host. 489Port to connect to on the remote host.
488This can be specified on a 490This can be specified on a
489per-host basis in the configuration file. 491per-host basis in the configuration file.
492.It Fl Q Ar protocol_feature
493Queries
494.Nm
495for the algorithms supported for the specified version 2
496.Ar protocol_feature .
497The queriable features are:
498.Dq cipher
499(supported symmetric ciphers),
500.Dq MAC
501(supported message integrity codes),
502.Dq KEX
503(key exchange algorithms),
504.Dq key
505(key types).
506Protocol features are treated case-insensitively.
490.It Fl q 507.It Fl q
491Quiet mode. 508Quiet mode.
492Causes most warning and diagnostic messages to be suppressed. 509Causes most warning and diagnostic messages to be suppressed.
diff --git a/ssh.c b/ssh.c
index cd56f8a74..b077dc828 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.375 2013/04/07 02:10:33 dtucker Exp $ */ 1/* $OpenBSD: ssh.c,v 1.376 2013/04/19 01:06:50 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -327,7 +327,7 @@ main(int ac, char **av)
327 327
328 again: 328 again:
329 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" 329 while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
330 "ACD:E:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { 330 "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
331 switch (opt) { 331 switch (opt) {
332 case '1': 332 case '1':
333 options.protocol = SSH_PROTO_1; 333 options.protocol = SSH_PROTO_1;
@@ -389,6 +389,22 @@ main(int ac, char **av)
389 case 'P': /* deprecated */ 389 case 'P': /* deprecated */
390 options.use_privileged_port = 0; 390 options.use_privileged_port = 0;
391 break; 391 break;
392 case 'Q': /* deprecated */
393 cp = NULL;
394 if (strcasecmp(optarg, "cipher") == 0)
395 cp = cipher_alg_list();
396 else if (strcasecmp(optarg, "mac") == 0)
397 cp = mac_alg_list();
398 else if (strcasecmp(optarg, "kex") == 0)
399 cp = kex_alg_list();
400 else if (strcasecmp(optarg, "key") == 0)
401 cp = key_alg_list();
402 if (cp == NULL)
403 fatal("Unsupported query \"%s\"", optarg);
404 printf("%s\n", cp);
405 free(cp);
406 exit(0);
407 break;
392 case 'a': 408 case 'a':
393 options.forward_agent = 0; 409 options.forward_agent = 0;
394 break; 410 break;