diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-07-03 11:39:54 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-07-03 23:26:36 +1000 |
commit | 4ba0d54794814ec0de1ec87987d0c3b89379b436 (patch) | |
tree | b8d904880f8927374b377b2e4d5661213c1138b6 | |
parent | 95344c257412b51199ead18d54eaed5bafb75617 (diff) |
upstream: Improve strictness and control over RSA-SHA2 signature
In ssh, when an agent fails to return a RSA-SHA2 signature when
requested and falls back to RSA-SHA1 instead, retry the signature to
ensure that the public key algorithm sent in the SSH_MSG_USERAUTH
matches the one in the signature itself.
In sshd, strictly enforce that the public key algorithm sent in the
SSH_MSG_USERAUTH message matches what appears in the signature.
Make the sshd_config PubkeyAcceptedKeyTypes and
HostbasedAcceptedKeyTypes options control accepted signature algorithms
(previously they selected supported key types). This allows these
options to ban RSA-SHA1 in favour of RSA-SHA2.
Add new signature algorithms "rsa-sha2-256-cert-v01@openssh.com" and
"rsa-sha2-512-cert-v01@openssh.com" to force use of RSA-SHA2 signatures
with certificate keys.
feedback and ok markus@
OpenBSD-Commit-ID: c6e9f6d45eed8962ad502d315d7eaef32c419dde
-rw-r--r-- | PROTOCOL.certkeys | 20 | ||||
-rw-r--r-- | auth2-hostbased.c | 5 | ||||
-rw-r--r-- | auth2-pubkey.c | 13 | ||||
-rw-r--r-- | authfd.c | 24 | ||||
-rw-r--r-- | compat.c | 27 | ||||
-rw-r--r-- | compat.h | 4 | ||||
-rw-r--r-- | kex.c | 17 | ||||
-rw-r--r-- | kex.h | 4 | ||||
-rw-r--r-- | myproposal.h | 4 | ||||
-rw-r--r-- | ssh-rsa.c | 60 | ||||
-rw-r--r-- | ssh_config.5 | 13 | ||||
-rw-r--r-- | sshconnect2.c | 345 | ||||
-rw-r--r-- | sshd.c | 63 | ||||
-rw-r--r-- | sshd_config.5 | 11 | ||||
-rw-r--r-- | ssherr.c | 4 | ||||
-rw-r--r-- | ssherr.h | 3 | ||||
-rw-r--r-- | sshkey.c | 104 | ||||
-rw-r--r-- | sshkey.h | 4 |
18 files changed, 469 insertions, 256 deletions
diff --git a/PROTOCOL.certkeys b/PROTOCOL.certkeys index 65f11f538..11363fdc3 100644 --- a/PROTOCOL.certkeys +++ b/PROTOCOL.certkeys | |||
@@ -25,6 +25,10 @@ raw user keys. The ssh client will support automatic verification of | |||
25 | acceptance of certified host keys, by adding a similar ability to | 25 | acceptance of certified host keys, by adding a similar ability to |
26 | specify CA keys in ~/.ssh/known_hosts. | 26 | specify CA keys in ~/.ssh/known_hosts. |
27 | 27 | ||
28 | All certificate types include certification information along with the | ||
29 | public key that is used to sign challenges. In OpenSSH, ssh-keygen | ||
30 | performs the CA signing operation. | ||
31 | |||
28 | Certified keys are represented using new key types: | 32 | Certified keys are represented using new key types: |
29 | 33 | ||
30 | ssh-rsa-cert-v01@openssh.com | 34 | ssh-rsa-cert-v01@openssh.com |
@@ -33,9 +37,17 @@ Certified keys are represented using new key types: | |||
33 | ecdsa-sha2-nistp384-cert-v01@openssh.com | 37 | ecdsa-sha2-nistp384-cert-v01@openssh.com |
34 | ecdsa-sha2-nistp521-cert-v01@openssh.com | 38 | ecdsa-sha2-nistp521-cert-v01@openssh.com |
35 | 39 | ||
36 | These include certification information along with the public key | 40 | Two additional types exist for RSA certificates to force use of |
37 | that is used to sign challenges. ssh-keygen performs the CA signing | 41 | SHA-2 signatures (SHA-256 and SHA-512 respectively): |
38 | operation. | 42 | |
43 | rsa-sha2-256-cert-v01@openssh.com | ||
44 | rsa-sha2-512-cert-v01@openssh.com | ||
45 | |||
46 | These RSA/SHA-2 types should not appear in keys at rest or transmitted | ||
47 | on their wire, but do appear in a SSH_MSG_KEXINIT's host-key algorithms | ||
48 | field or in the "public key algorithm name" field of a "publickey" | ||
49 | SSH_USERAUTH_REQUEST to indicate that the signature will use the | ||
50 | specified algorithm. | ||
39 | 51 | ||
40 | Protocol extensions | 52 | Protocol extensions |
41 | ------------------- | 53 | ------------------- |
@@ -291,4 +303,4 @@ permit-user-rc empty Flag indicating that execution of | |||
291 | of this script will not be permitted if | 303 | of this script will not be permitted if |
292 | this option is not present. | 304 | this option is not present. |
293 | 305 | ||
294 | $OpenBSD: PROTOCOL.certkeys,v 1.14 2018/04/10 00:10:49 djm Exp $ | 306 | $OpenBSD: PROTOCOL.certkeys,v 1.15 2018/07/03 11:39:54 djm Exp $ |
diff --git a/auth2-hostbased.c b/auth2-hostbased.c index 8996f7e05..f70609cb0 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-hostbased.c,v 1.33 2018/01/23 05:27:21 djm Exp $ */ | 1 | /* $OpenBSD: auth2-hostbased.c,v 1.34 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -111,8 +111,7 @@ userauth_hostbased(struct ssh *ssh) | |||
111 | "signature format"); | 111 | "signature format"); |
112 | goto done; | 112 | goto done; |
113 | } | 113 | } |
114 | if (match_pattern_list(sshkey_ssh_name(key), | 114 | if (match_pattern_list(pkalg, options.hostbased_key_types, 0) != 1) { |
115 | options.hostbased_key_types, 0) != 1) { | ||
116 | logit("%s: key type %s not in HostbasedAcceptedKeyTypes", | 115 | logit("%s: key type %s not in HostbasedAcceptedKeyTypes", |
117 | __func__, sshkey_type(key)); | 116 | __func__, sshkey_type(key)); |
118 | goto done; | 117 | goto done; |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 3ccc3a213..4feeae3e2 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.79 2018/06/06 18:29:18 markus Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.80 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -109,7 +109,7 @@ userauth_pubkey(struct ssh *ssh) | |||
109 | pktype = sshkey_type_from_name(pkalg); | 109 | pktype = sshkey_type_from_name(pkalg); |
110 | if (pktype == KEY_UNSPEC) { | 110 | if (pktype == KEY_UNSPEC) { |
111 | /* this is perfectly legal */ | 111 | /* this is perfectly legal */ |
112 | logit("%s: unsupported public key algorithm: %s", | 112 | verbose("%s: unsupported public key algorithm: %s", |
113 | __func__, pkalg); | 113 | __func__, pkalg); |
114 | goto done; | 114 | goto done; |
115 | } | 115 | } |
@@ -136,8 +136,7 @@ userauth_pubkey(struct ssh *ssh) | |||
136 | logit("refusing previously-used %s key", sshkey_type(key)); | 136 | logit("refusing previously-used %s key", sshkey_type(key)); |
137 | goto done; | 137 | goto done; |
138 | } | 138 | } |
139 | if (match_pattern_list(sshkey_ssh_name(key), | 139 | if (match_pattern_list(pkalg, options.pubkey_key_types, 0) != 1) { |
140 | options.pubkey_key_types, 0) != 1) { | ||
141 | logit("%s: key type %s not in PubkeyAcceptedKeyTypes", | 140 | logit("%s: key type %s not in PubkeyAcceptedKeyTypes", |
142 | __func__, sshkey_ssh_name(key)); | 141 | __func__, sshkey_ssh_name(key)); |
143 | goto done; | 142 | goto done; |
@@ -188,8 +187,10 @@ userauth_pubkey(struct ssh *ssh) | |||
188 | /* test for correct signature */ | 187 | /* test for correct signature */ |
189 | authenticated = 0; | 188 | authenticated = 0; |
190 | if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && | 189 | if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && |
191 | PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), | 190 | PRIVSEP(sshkey_verify(key, sig, slen, |
192 | sshbuf_len(b), NULL, ssh->compat)) == 0) { | 191 | sshbuf_ptr(b), sshbuf_len(b), |
192 | (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, | ||
193 | ssh->compat)) == 0) { | ||
193 | authenticated = 1; | 194 | authenticated = 1; |
194 | } | 195 | } |
195 | sshbuf_free(b); | 196 | sshbuf_free(b); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfd.c,v 1.109 2018/04/10 00:10:49 djm Exp $ */ | 1 | /* $OpenBSD: authfd.c,v 1.110 2018/07/03 11:39:54 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 |
@@ -343,8 +343,8 @@ ssh_agent_sign(int sock, const struct sshkey *key, | |||
343 | const u_char *data, size_t datalen, const char *alg, u_int compat) | 343 | const u_char *data, size_t datalen, const char *alg, u_int compat) |
344 | { | 344 | { |
345 | struct sshbuf *msg; | 345 | struct sshbuf *msg; |
346 | u_char *blob = NULL, type; | 346 | u_char *sig = NULL, type = 0; |
347 | size_t blen = 0, len = 0; | 347 | size_t len = 0; |
348 | u_int flags = 0; | 348 | u_int flags = 0; |
349 | int r = SSH_ERR_INTERNAL_ERROR; | 349 | int r = SSH_ERR_INTERNAL_ERROR; |
350 | 350 | ||
@@ -355,11 +355,9 @@ ssh_agent_sign(int sock, const struct sshkey *key, | |||
355 | return SSH_ERR_INVALID_ARGUMENT; | 355 | return SSH_ERR_INVALID_ARGUMENT; |
356 | if ((msg = sshbuf_new()) == NULL) | 356 | if ((msg = sshbuf_new()) == NULL) |
357 | return SSH_ERR_ALLOC_FAIL; | 357 | return SSH_ERR_ALLOC_FAIL; |
358 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) | ||
359 | goto out; | ||
360 | flags |= agent_encode_alg(key, alg); | 358 | flags |= agent_encode_alg(key, alg); |
361 | if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || | 359 | if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || |
362 | (r = sshbuf_put_string(msg, blob, blen)) != 0 || | 360 | (r = sshkey_puts(key, msg)) != 0 || |
363 | (r = sshbuf_put_string(msg, data, datalen)) != 0 || | 361 | (r = sshbuf_put_string(msg, data, datalen)) != 0 || |
364 | (r = sshbuf_put_u32(msg, flags)) != 0) | 362 | (r = sshbuf_put_u32(msg, flags)) != 0) |
365 | goto out; | 363 | goto out; |
@@ -374,15 +372,19 @@ ssh_agent_sign(int sock, const struct sshkey *key, | |||
374 | r = SSH_ERR_INVALID_FORMAT; | 372 | r = SSH_ERR_INVALID_FORMAT; |
375 | goto out; | 373 | goto out; |
376 | } | 374 | } |
377 | if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) | 375 | if ((r = sshbuf_get_string(msg, &sig, &len)) != 0) |
376 | goto out; | ||
377 | /* Check what we actually got back from the agent. */ | ||
378 | if ((r = sshkey_check_sigtype(sig, len, alg)) != 0) | ||
378 | goto out; | 379 | goto out; |
380 | /* success */ | ||
381 | *sigp = sig; | ||
379 | *lenp = len; | 382 | *lenp = len; |
383 | sig = NULL; | ||
384 | len = 0; | ||
380 | r = 0; | 385 | r = 0; |
381 | out: | 386 | out: |
382 | if (blob != NULL) { | 387 | freezero(sig, len); |
383 | explicit_bzero(blob, blen); | ||
384 | free(blob); | ||
385 | } | ||
386 | sshbuf_free(msg); | 388 | sshbuf_free(msg); |
387 | return r; | 389 | return r; |
388 | } | 390 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: compat.c,v 1.107 2018/04/16 22:50:44 djm Exp $ */ | 1 | /* $OpenBSD: compat.c,v 1.108 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -52,16 +52,27 @@ compat_datafellows(const char *version) | |||
52 | } check[] = { | 52 | } check[] = { |
53 | { "OpenSSH_2.*," | 53 | { "OpenSSH_2.*," |
54 | "OpenSSH_3.0*," | 54 | "OpenSSH_3.0*," |
55 | "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR}, | 55 | "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR| |
56 | { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR }, | 56 | SSH_BUG_SIGTYPE}, |
57 | { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, | 57 | { "OpenSSH_3.*", SSH_OLD_FORWARD_ADDR|SSH_BUG_SIGTYPE }, |
58 | { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF| | ||
59 | SSH_BUG_SIGTYPE}, | ||
58 | { "OpenSSH_2*," | 60 | { "OpenSSH_2*," |
59 | "OpenSSH_3*," | 61 | "OpenSSH_3*," |
60 | "OpenSSH_4*", 0 }, | 62 | "OpenSSH_4*", SSH_BUG_SIGTYPE }, |
61 | { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, | 63 | { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT| |
62 | { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, | 64 | SSH_BUG_SIGTYPE}, |
65 | { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE}, | ||
63 | { "OpenSSH_6.5*," | 66 | { "OpenSSH_6.5*," |
64 | "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, | 67 | "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD| |
68 | SSH_BUG_SIGTYPE}, | ||
69 | { "OpenSSH_7.0*," | ||
70 | "OpenSSH_7.1*," | ||
71 | "OpenSSH_7.2*," | ||
72 | "OpenSSH_7.3*," | ||
73 | "OpenSSH_7.4*," | ||
74 | "OpenSSH_7.5*," | ||
75 | "OpenSSH_7.6*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE}, | ||
65 | { "OpenSSH*", SSH_NEW_OPENSSH }, | 76 | { "OpenSSH*", SSH_NEW_OPENSSH }, |
66 | { "*MindTerm*", 0 }, | 77 | { "*MindTerm*", 0 }, |
67 | { "3.0.*", SSH_BUG_DEBUG }, | 78 | { "3.0.*", SSH_BUG_DEBUG }, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: compat.h,v 1.51 2018/02/16 04:43:11 dtucker Exp $ */ | 1 | /* $OpenBSD: compat.h,v 1.52 2018/07/03 11:39:54 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. |
@@ -33,7 +33,7 @@ | |||
33 | #define SSH_PROTO_2 0x04 | 33 | #define SSH_PROTO_2 0x04 |
34 | 34 | ||
35 | #define SSH_BUG_UTF8TTYMODE 0x00000001 | 35 | #define SSH_BUG_UTF8TTYMODE 0x00000001 |
36 | /* #define unused 0x00000002 */ | 36 | #define SSH_BUG_SIGTYPE 0x00000002 |
37 | /* #define unused 0x00000004 */ | 37 | /* #define unused 0x00000004 */ |
38 | /* #define unused 0x00000008 */ | 38 | /* #define unused 0x00000008 */ |
39 | #define SSH_OLD_SESSIONID 0x00000010 | 39 | #define SSH_OLD_SESSIONID 0x00000010 |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.136 2018/02/07 02:06:50 jsing Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.137 2018/07/03 11:39:54 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 | * |
@@ -342,6 +342,7 @@ kex_send_ext_info(struct ssh *ssh) | |||
342 | 342 | ||
343 | if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) | 343 | if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) |
344 | return SSH_ERR_ALLOC_FAIL; | 344 | return SSH_ERR_ALLOC_FAIL; |
345 | /* XXX filter algs list by allowed pubkey/hostbased types */ | ||
345 | if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || | 346 | if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || |
346 | (r = sshpkt_put_u32(ssh, 1)) != 0 || | 347 | (r = sshpkt_put_u32(ssh, 1)) != 0 || |
347 | (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || | 348 | (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || |
@@ -378,7 +379,7 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) | |||
378 | { | 379 | { |
379 | struct kex *kex = ssh->kex; | 380 | struct kex *kex = ssh->kex; |
380 | u_int32_t i, ninfo; | 381 | u_int32_t i, ninfo; |
381 | char *name, *found; | 382 | char *name; |
382 | u_char *val; | 383 | u_char *val; |
383 | size_t vlen; | 384 | size_t vlen; |
384 | int r; | 385 | int r; |
@@ -401,16 +402,8 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) | |||
401 | return SSH_ERR_INVALID_FORMAT; | 402 | return SSH_ERR_INVALID_FORMAT; |
402 | } | 403 | } |
403 | debug("%s: %s=<%s>", __func__, name, val); | 404 | debug("%s: %s=<%s>", __func__, name, val); |
404 | found = match_list("rsa-sha2-256", val, NULL); | 405 | kex->server_sig_algs = val; |
405 | if (found) { | 406 | val = NULL; |
406 | kex->rsa_sha2 = 256; | ||
407 | free(found); | ||
408 | } | ||
409 | found = match_list("rsa-sha2-512", val, NULL); | ||
410 | if (found) { | ||
411 | kex->rsa_sha2 = 512; | ||
412 | free(found); | ||
413 | } | ||
414 | } else | 407 | } else |
415 | debug("%s: %s (unrecognised)", __func__, name); | 408 | debug("%s: %s (unrecognised)", __func__, name); |
416 | free(name); | 409 | free(name); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.h,v 1.83 2017/05/30 14:23:52 markus Exp $ */ | 1 | /* $OpenBSD: kex.h,v 1.84 2018/07/03 11:39:54 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. |
@@ -139,7 +139,7 @@ struct kex { | |||
139 | int hostkey_type; | 139 | int hostkey_type; |
140 | int hostkey_nid; | 140 | int hostkey_nid; |
141 | u_int kex_type; | 141 | u_int kex_type; |
142 | int rsa_sha2; | 142 | char *server_sig_algs; |
143 | int ext_info_c; | 143 | int ext_info_c; |
144 | struct sshbuf *my; | 144 | struct sshbuf *my; |
145 | struct sshbuf *peer; | 145 | struct sshbuf *peer; |
diff --git a/myproposal.h b/myproposal.h index c255147aa..08782dd30 100644 --- a/myproposal.h +++ b/myproposal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: myproposal.h,v 1.55 2017/05/07 23:13:42 djm Exp $ */ | 1 | /* $OpenBSD: myproposal.h,v 1.56 2018/07/03 11:39:54 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -107,6 +107,8 @@ | |||
107 | #define KEX_DEFAULT_PK_ALG \ | 107 | #define KEX_DEFAULT_PK_ALG \ |
108 | HOSTKEY_ECDSA_CERT_METHODS \ | 108 | HOSTKEY_ECDSA_CERT_METHODS \ |
109 | "ssh-ed25519-cert-v01@openssh.com," \ | 109 | "ssh-ed25519-cert-v01@openssh.com," \ |
110 | "rsa-sha2-512-cert-v01@openssh.com," \ | ||
111 | "rsa-sha2-256-cert-v01@openssh.com," \ | ||
110 | "ssh-rsa-cert-v01@openssh.com," \ | 112 | "ssh-rsa-cert-v01@openssh.com," \ |
111 | HOSTKEY_ECDSA_METHODS \ | 113 | HOSTKEY_ECDSA_METHODS \ |
112 | "ssh-ed25519," \ | 114 | "ssh-ed25519," \ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-rsa.c,v 1.66 2018/02/14 16:27:24 jsing Exp $ */ | 1 | /* $OpenBSD: ssh-rsa.c,v 1.67 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> | 3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> |
4 | * | 4 | * |
@@ -51,11 +51,14 @@ rsa_hash_alg_ident(int hash_alg) | |||
51 | return NULL; | 51 | return NULL; |
52 | } | 52 | } |
53 | 53 | ||
54 | /* | ||
55 | * Returns the hash algorithm ID for a given algorithm identifier as used | ||
56 | * inside the signature blob, | ||
57 | */ | ||
54 | static int | 58 | static int |
55 | rsa_hash_alg_from_ident(const char *ident) | 59 | rsa_hash_id_from_ident(const char *ident) |
56 | { | 60 | { |
57 | if (strcmp(ident, "ssh-rsa") == 0 || | 61 | if (strcmp(ident, "ssh-rsa") == 0) |
58 | strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0) | ||
59 | return SSH_DIGEST_SHA1; | 62 | return SSH_DIGEST_SHA1; |
60 | if (strcmp(ident, "rsa-sha2-256") == 0) | 63 | if (strcmp(ident, "rsa-sha2-256") == 0) |
61 | return SSH_DIGEST_SHA256; | 64 | return SSH_DIGEST_SHA256; |
@@ -64,6 +67,27 @@ rsa_hash_alg_from_ident(const char *ident) | |||
64 | return -1; | 67 | return -1; |
65 | } | 68 | } |
66 | 69 | ||
70 | /* | ||
71 | * Return the hash algorithm ID for the specified key name. This includes | ||
72 | * all the cases of rsa_hash_id_from_ident() but also the certificate key | ||
73 | * types. | ||
74 | */ | ||
75 | static int | ||
76 | rsa_hash_id_from_keyname(const char *alg) | ||
77 | { | ||
78 | int r; | ||
79 | |||
80 | if ((r = rsa_hash_id_from_ident(alg)) != -1) | ||
81 | return r; | ||
82 | if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0) | ||
83 | return SSH_DIGEST_SHA1; | ||
84 | if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0) | ||
85 | return SSH_DIGEST_SHA256; | ||
86 | if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0) | ||
87 | return SSH_DIGEST_SHA512; | ||
88 | return -1; | ||
89 | } | ||
90 | |||
67 | static int | 91 | static int |
68 | rsa_hash_alg_nid(int type) | 92 | rsa_hash_alg_nid(int type) |
69 | { | 93 | { |
@@ -135,7 +159,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | |||
135 | if (alg_ident == NULL || strlen(alg_ident) == 0) | 159 | if (alg_ident == NULL || strlen(alg_ident) == 0) |
136 | hash_alg = SSH_DIGEST_SHA1; | 160 | hash_alg = SSH_DIGEST_SHA1; |
137 | else | 161 | else |
138 | hash_alg = rsa_hash_alg_from_ident(alg_ident); | 162 | hash_alg = rsa_hash_id_from_keyname(alg_ident); |
139 | if (key == NULL || key->rsa == NULL || hash_alg == -1 || | 163 | if (key == NULL || key->rsa == NULL || hash_alg == -1 || |
140 | sshkey_type_plain(key->type) != KEY_RSA) | 164 | sshkey_type_plain(key->type) != KEY_RSA) |
141 | return SSH_ERR_INVALID_ARGUMENT; | 165 | return SSH_ERR_INVALID_ARGUMENT; |
@@ -202,7 +226,7 @@ ssh_rsa_verify(const struct sshkey *key, | |||
202 | const char *alg) | 226 | const char *alg) |
203 | { | 227 | { |
204 | char *sigtype = NULL; | 228 | char *sigtype = NULL; |
205 | int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; | 229 | int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; |
206 | size_t len = 0, diff, modlen, dlen; | 230 | size_t len = 0, diff, modlen, dlen; |
207 | struct sshbuf *b = NULL; | 231 | struct sshbuf *b = NULL; |
208 | u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; | 232 | u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; |
@@ -220,18 +244,24 @@ ssh_rsa_verify(const struct sshkey *key, | |||
220 | ret = SSH_ERR_INVALID_FORMAT; | 244 | ret = SSH_ERR_INVALID_FORMAT; |
221 | goto out; | 245 | goto out; |
222 | } | 246 | } |
223 | /* XXX djm: need cert types that reliably yield SHA-2 signatures */ | 247 | if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) { |
224 | if (alg != NULL && strcmp(alg, sigtype) != 0 && | ||
225 | strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { | ||
226 | error("%s: RSA signature type mismatch: " | ||
227 | "expected %s received %s", __func__, alg, sigtype); | ||
228 | ret = SSH_ERR_SIGNATURE_INVALID; | ||
229 | goto out; | ||
230 | } | ||
231 | if ((hash_alg = rsa_hash_alg_from_ident(sigtype)) == -1) { | ||
232 | ret = SSH_ERR_KEY_TYPE_MISMATCH; | 248 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
233 | goto out; | 249 | goto out; |
234 | } | 250 | } |
251 | /* | ||
252 | * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for | ||
253 | * legacy reasons, but otherwise the signature type should match. | ||
254 | */ | ||
255 | if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { | ||
256 | if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { | ||
257 | ret = SSH_ERR_INVALID_ARGUMENT; | ||
258 | goto out; | ||
259 | } | ||
260 | if (hash_alg != want_alg) { | ||
261 | ret = SSH_ERR_SIGNATURE_INVALID; | ||
262 | goto out; | ||
263 | } | ||
264 | } | ||
235 | if (sshbuf_get_string(b, &sigblob, &len) != 0) { | 265 | if (sshbuf_get_string(b, &sigblob, &len) != 0) { |
236 | ret = SSH_ERR_INVALID_FORMAT; | 266 | ret = SSH_ERR_INVALID_FORMAT; |
237 | goto out; | 267 | goto out; |
diff --git a/ssh_config.5 b/ssh_config.5 index e5eadcaaf..eff9c5e61 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -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_config.5,v 1.277 2018/06/09 06:36:31 jmc Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.278 2018/07/03 11:39:54 djm Exp $ |
37 | .Dd $Mdocdate: June 9 2018 $ | 37 | .Dd $Mdocdate: July 3 2018 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -772,9 +772,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
772 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 772 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
773 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 773 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
774 | ssh-ed25519-cert-v01@openssh.com, | 774 | ssh-ed25519-cert-v01@openssh.com, |
775 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
775 | ssh-rsa-cert-v01@openssh.com, | 776 | ssh-rsa-cert-v01@openssh.com, |
776 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 777 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
777 | ssh-ed25519,ssh-rsa | 778 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
778 | .Ed | 779 | .Ed |
779 | .Pp | 780 | .Pp |
780 | The | 781 | The |
@@ -799,9 +800,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
799 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 800 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
800 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 801 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
801 | ssh-ed25519-cert-v01@openssh.com, | 802 | ssh-ed25519-cert-v01@openssh.com, |
803 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
802 | ssh-rsa-cert-v01@openssh.com, | 804 | ssh-rsa-cert-v01@openssh.com, |
803 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 805 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
804 | ssh-ed25519,ssh-rsa | 806 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
805 | .Ed | 807 | .Ed |
806 | .Pp | 808 | .Pp |
807 | If hostkeys are known for the destination host then this default is modified | 809 | If hostkeys are known for the destination host then this default is modified |
@@ -1255,9 +1257,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
1255 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 1257 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
1256 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 1258 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
1257 | ssh-ed25519-cert-v01@openssh.com, | 1259 | ssh-ed25519-cert-v01@openssh.com, |
1260 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
1258 | ssh-rsa-cert-v01@openssh.com, | 1261 | ssh-rsa-cert-v01@openssh.com, |
1259 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 1262 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
1260 | ssh-ed25519,ssh-rsa | 1263 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
1261 | .Ed | 1264 | .Ed |
1262 | .Pp | 1265 | .Pp |
1263 | The list of available key types may also be obtained using | 1266 | The list of available key types may also be obtained using |
diff --git a/sshconnect2.c b/sshconnect2.c index d8ae6eb3a..920376408 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.271 2018/06/26 02:02:36 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.272 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -315,7 +315,7 @@ int input_gssapi_errtok(int, u_int32_t, struct ssh *); | |||
315 | 315 | ||
316 | void userauth(Authctxt *, char *); | 316 | void userauth(Authctxt *, char *); |
317 | 317 | ||
318 | static int sign_and_send_pubkey(Authctxt *, Identity *); | 318 | static int sign_and_send_pubkey(struct ssh *ssh, Authctxt *, Identity *); |
319 | static void pubkey_prepare(Authctxt *); | 319 | static void pubkey_prepare(Authctxt *); |
320 | static void pubkey_cleanup(Authctxt *); | 320 | static void pubkey_cleanup(Authctxt *); |
321 | static void pubkey_reset(Authctxt *); | 321 | static void pubkey_reset(Authctxt *); |
@@ -619,7 +619,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) | |||
619 | */ | 619 | */ |
620 | TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { | 620 | TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { |
621 | if (key_equal(key, id->key)) { | 621 | if (key_equal(key, id->key)) { |
622 | sent = sign_and_send_pubkey(authctxt, id); | 622 | sent = sign_and_send_pubkey(ssh, authctxt, id); |
623 | break; | 623 | break; |
624 | } | 624 | } |
625 | } | 625 | } |
@@ -986,73 +986,80 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, struct ssh *ssh) | |||
986 | return 0; | 986 | return 0; |
987 | } | 987 | } |
988 | 988 | ||
989 | static const char * | ||
990 | key_sign_encode(const struct sshkey *key) | ||
991 | { | ||
992 | struct ssh *ssh = active_state; | ||
993 | |||
994 | if (key->type == KEY_RSA) { | ||
995 | switch (ssh->kex->rsa_sha2) { | ||
996 | case 256: | ||
997 | return "rsa-sha2-256"; | ||
998 | case 512: | ||
999 | return "rsa-sha2-512"; | ||
1000 | } | ||
1001 | } | ||
1002 | return key_ssh_name(key); | ||
1003 | } | ||
1004 | |||
1005 | /* | 989 | /* |
1006 | * Some agents will return ssh-rsa signatures when asked to make a | 990 | * Select an algorithm for publickey signatures. |
1007 | * rsa-sha2-* signature. Check what they actually gave back and warn the | 991 | * Returns algorithm (caller must free) or NULL if no mutual algorithm found. |
1008 | * user if the agent has returned an unexpected type. | 992 | * |
993 | * Call with ssh==NULL to ignore server-sig-algs extension list and | ||
994 | * only attempt with the key's base signature type. | ||
1009 | */ | 995 | */ |
1010 | static int | 996 | static char * |
1011 | check_sigtype(const struct sshkey *key, const u_char *sig, size_t len) | 997 | key_sig_algorithm(struct ssh *ssh, const struct sshkey *key) |
1012 | { | 998 | { |
1013 | int r; | 999 | char *allowed, *oallowed, *cp, *alg = NULL; |
1014 | char *sigtype = NULL; | ||
1015 | const char *alg = key_sign_encode(key); | ||
1016 | 1000 | ||
1017 | if (sshkey_is_cert(key)) | 1001 | /* |
1018 | return 0; | 1002 | * The signature algorithm will only differ from the key algorithm |
1019 | if ((r = sshkey_sigtype(sig, len, &sigtype)) != 0) | 1003 | * for RSA keys/certs and when the server advertises support for |
1020 | return r; | 1004 | * newer (SHA2) algorithms. |
1021 | if (strcmp(sigtype, alg) != 0) { | 1005 | */ |
1022 | logit("warning: agent returned different signature type %s " | 1006 | if (ssh == NULL || ssh->kex->server_sig_algs == NULL || |
1023 | "(expected %s)", sigtype, alg); | 1007 | (key->type != KEY_RSA && key->type != KEY_RSA_CERT)) { |
1024 | } | 1008 | /* Filter base key signature alg against our configuration */ |
1025 | free(sigtype); | 1009 | return match_list(key_ssh_name(key), |
1026 | /* Incorrect signature types aren't an error ... yet */ | 1010 | options.pubkey_key_types, NULL); |
1027 | return 0; | 1011 | } |
1012 | |||
1013 | /* | ||
1014 | * For RSA keys/certs, since these might have a different sig type: | ||
1015 | * find the first entry in PubkeyAcceptedKeyTypes of the right type | ||
1016 | * that also appears in the supported signature algorithms list from | ||
1017 | * the server. | ||
1018 | */ | ||
1019 | oallowed = allowed = xstrdup(options.pubkey_key_types); | ||
1020 | while ((cp = strsep(&allowed, ",")) != NULL) { | ||
1021 | if (sshkey_type_from_name(cp) != key->type) | ||
1022 | continue; | ||
1023 | alg = match_list(cp, ssh->kex->server_sig_algs, NULL); | ||
1024 | if (alg != NULL) | ||
1025 | break; | ||
1026 | } | ||
1027 | free(oallowed); | ||
1028 | return alg; | ||
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | static int | 1031 | static int |
1031 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | 1032 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
1032 | const u_char *data, size_t datalen, u_int compat) | 1033 | const u_char *data, size_t datalen, u_int compat, const char *alg) |
1033 | { | 1034 | { |
1034 | struct sshkey *prv; | 1035 | struct sshkey *prv; |
1035 | int r; | 1036 | int r; |
1036 | 1037 | ||
1037 | /* the agent supports this key */ | 1038 | /* The agent supports this key. */ |
1038 | if (id->key != NULL && id->agent_fd != -1) { | 1039 | if (id->key != NULL && id->agent_fd != -1) { |
1039 | if ((r = ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, | 1040 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, |
1040 | data, datalen, key_sign_encode(id->key), compat)) != 0 || | 1041 | data, datalen, alg, compat); |
1041 | (r = check_sigtype(id->key, *sigp, *lenp)) != 0) | ||
1042 | return r; | ||
1043 | return 0; | ||
1044 | } | 1042 | } |
1045 | 1043 | ||
1046 | /* | 1044 | /* |
1047 | * we have already loaded the private key or | 1045 | * We have already loaded the private key or the private key is |
1048 | * the private key is stored in external hardware | 1046 | * stored in external hardware. |
1049 | */ | 1047 | */ |
1050 | if (id->key != NULL && | 1048 | if (id->key != NULL && |
1051 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) | 1049 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { |
1052 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, | 1050 | if ((r = sshkey_sign(id->key, sigp, lenp, data, datalen, |
1053 | key_sign_encode(id->key), compat)); | 1051 | alg, compat)) != 0) |
1052 | return r; | ||
1053 | /* | ||
1054 | * PKCS#11 tokens may not support all signature algorithms, | ||
1055 | * so check what we get back. | ||
1056 | */ | ||
1057 | if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) | ||
1058 | return r; | ||
1059 | return 0; | ||
1060 | } | ||
1054 | 1061 | ||
1055 | /* load the private key from the file */ | 1062 | /* Load the private key from the file. */ |
1056 | if ((prv = load_identity_file(id)) == NULL) | 1063 | if ((prv = load_identity_file(id)) == NULL) |
1057 | return SSH_ERR_KEY_NOT_FOUND; | 1064 | return SSH_ERR_KEY_NOT_FOUND; |
1058 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { | 1065 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { |
@@ -1060,8 +1067,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | |||
1060 | __func__, id->filename); | 1067 | __func__, id->filename); |
1061 | return SSH_ERR_KEY_NOT_FOUND; | 1068 | return SSH_ERR_KEY_NOT_FOUND; |
1062 | } | 1069 | } |
1063 | r = sshkey_sign(prv, sigp, lenp, data, datalen, | 1070 | r = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); |
1064 | key_sign_encode(prv), compat); | ||
1065 | sshkey_free(prv); | 1071 | sshkey_free(prv); |
1066 | return r; | 1072 | return r; |
1067 | } | 1073 | } |
@@ -1086,57 +1092,35 @@ id_filename_matches(Identity *id, Identity *private_id) | |||
1086 | } | 1092 | } |
1087 | 1093 | ||
1088 | static int | 1094 | static int |
1089 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | 1095 | sign_and_send_pubkey(struct ssh *ssh, Authctxt *authctxt, Identity *id) |
1090 | { | 1096 | { |
1091 | Buffer b; | 1097 | struct sshbuf *b = NULL; |
1092 | Identity *private_id; | 1098 | Identity *private_id, *sign_id = NULL; |
1093 | u_char *blob, *signature; | 1099 | u_char *signature = NULL; |
1094 | size_t slen; | 1100 | size_t slen = 0, skip = 0; |
1095 | u_int bloblen, skip = 0; | 1101 | int r, fallback_sigtype, sent = 0; |
1096 | int matched, ret = -1, have_sig = 1; | 1102 | char *alg = NULL, *fp = NULL; |
1097 | char *fp; | 1103 | const char *loc = ""; |
1098 | 1104 | ||
1099 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, | 1105 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
1100 | SSH_FP_DEFAULT)) == NULL) | 1106 | SSH_FP_DEFAULT)) == NULL) |
1101 | return 0; | 1107 | return 0; |
1102 | debug3("%s: %s %s", __func__, key_type(id->key), fp); | ||
1103 | free(fp); | ||
1104 | 1108 | ||
1105 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { | 1109 | debug3("%s: %s %s", __func__, sshkey_type(id->key), fp); |
1106 | /* we cannot handle this key */ | ||
1107 | debug3("sign_and_send_pubkey: cannot handle key"); | ||
1108 | return 0; | ||
1109 | } | ||
1110 | /* data to be signed */ | ||
1111 | buffer_init(&b); | ||
1112 | if (datafellows & SSH_OLD_SESSIONID) { | ||
1113 | buffer_append(&b, session_id2, session_id2_len); | ||
1114 | skip = session_id2_len; | ||
1115 | } else { | ||
1116 | buffer_put_string(&b, session_id2, session_id2_len); | ||
1117 | skip = buffer_len(&b); | ||
1118 | } | ||
1119 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | ||
1120 | buffer_put_cstring(&b, authctxt->server_user); | ||
1121 | buffer_put_cstring(&b, authctxt->service); | ||
1122 | buffer_put_cstring(&b, authctxt->method->name); | ||
1123 | buffer_put_char(&b, have_sig); | ||
1124 | buffer_put_cstring(&b, key_sign_encode(id->key)); | ||
1125 | buffer_put_string(&b, blob, bloblen); | ||
1126 | 1110 | ||
1127 | /* | 1111 | /* |
1128 | * If the key is an certificate, try to find a matching private key | 1112 | * If the key is an certificate, try to find a matching private key |
1129 | * and use it to complete the signature. | 1113 | * and use it to complete the signature. |
1130 | * If no such private key exists, fall back to trying the certificate | 1114 | * If no such private key exists, fall back to trying the certificate |
1131 | * key itself in case it has a private half already loaded. | 1115 | * key itself in case it has a private half already loaded. |
1116 | * This will try to set sign_id to the private key that will perform | ||
1117 | * the signature. | ||
1132 | */ | 1118 | */ |
1133 | if (key_is_cert(id->key)) { | 1119 | if (sshkey_is_cert(id->key)) { |
1134 | matched = 0; | ||
1135 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { | 1120 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { |
1136 | if (sshkey_equal_public(id->key, private_id->key) && | 1121 | if (sshkey_equal_public(id->key, private_id->key) && |
1137 | id->key->type != private_id->key->type) { | 1122 | id->key->type != private_id->key->type) { |
1138 | id = private_id; | 1123 | sign_id = private_id; |
1139 | matched = 1; | ||
1140 | break; | 1124 | break; |
1141 | } | 1125 | } |
1142 | } | 1126 | } |
@@ -1147,18 +1131,18 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1147 | * of keeping just a private key file and public | 1131 | * of keeping just a private key file and public |
1148 | * certificate on disk. | 1132 | * certificate on disk. |
1149 | */ | 1133 | */ |
1150 | if (!matched && !id->isprivate && id->agent_fd == -1 && | 1134 | if (sign_id == NULL && |
1135 | !id->isprivate && id->agent_fd == -1 && | ||
1151 | (id->key->flags & SSHKEY_FLAG_EXT) == 0) { | 1136 | (id->key->flags & SSHKEY_FLAG_EXT) == 0) { |
1152 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { | 1137 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { |
1153 | if (private_id->key == NULL && | 1138 | if (private_id->key == NULL && |
1154 | id_filename_matches(id, private_id)) { | 1139 | id_filename_matches(id, private_id)) { |
1155 | id = private_id; | 1140 | sign_id = private_id; |
1156 | matched = 1; | ||
1157 | break; | 1141 | break; |
1158 | } | 1142 | } |
1159 | } | 1143 | } |
1160 | } | 1144 | } |
1161 | if (matched) { | 1145 | if (sign_id != NULL) { |
1162 | debug2("%s: using private key \"%s\"%s for " | 1146 | debug2("%s: using private key \"%s\"%s for " |
1163 | "certificate", __func__, id->filename, | 1147 | "certificate", __func__, id->filename, |
1164 | id->agent_fd != -1 ? " from agent" : ""); | 1148 | id->agent_fd != -1 ? " from agent" : ""); |
@@ -1168,51 +1152,121 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1168 | } | 1152 | } |
1169 | } | 1153 | } |
1170 | 1154 | ||
1171 | /* generate signature */ | 1155 | /* |
1172 | ret = identity_sign(id, &signature, &slen, | 1156 | * If the above didn't select another identity to do the signing |
1173 | buffer_ptr(&b), buffer_len(&b), datafellows); | 1157 | * then default to the one we started with. |
1174 | if (ret != 0) { | 1158 | */ |
1175 | if (ret != SSH_ERR_KEY_NOT_FOUND) | 1159 | if (sign_id == NULL) |
1176 | error("%s: signing failed: %s", __func__, ssh_err(ret)); | 1160 | sign_id = id; |
1177 | free(blob); | 1161 | |
1178 | buffer_free(&b); | 1162 | /* assemble and sign data */ |
1179 | return 0; | 1163 | for (fallback_sigtype = 0; fallback_sigtype <= 1; fallback_sigtype++) { |
1164 | free(alg); | ||
1165 | slen = 0; | ||
1166 | signature = NULL; | ||
1167 | if ((alg = key_sig_algorithm(fallback_sigtype ? NULL : ssh, | ||
1168 | id->key)) == NULL) { | ||
1169 | error("%s: no mutual signature supported", __func__); | ||
1170 | goto out; | ||
1171 | } | ||
1172 | debug3("%s: signing using %s", __func__, alg); | ||
1173 | |||
1174 | sshbuf_free(b); | ||
1175 | if ((b = sshbuf_new()) == NULL) | ||
1176 | fatal("%s: sshbuf_new failed", __func__); | ||
1177 | if (datafellows & SSH_OLD_SESSIONID) { | ||
1178 | if ((r = sshbuf_put(b, session_id2, | ||
1179 | session_id2_len)) != 0) { | ||
1180 | fatal("%s: sshbuf_put: %s", | ||
1181 | __func__, ssh_err(r)); | ||
1182 | } | ||
1183 | } else { | ||
1184 | if ((r = sshbuf_put_string(b, session_id2, | ||
1185 | session_id2_len)) != 0) { | ||
1186 | fatal("%s: sshbuf_put_string: %s", | ||
1187 | __func__, ssh_err(r)); | ||
1188 | } | ||
1189 | } | ||
1190 | skip = buffer_len(b); | ||
1191 | if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || | ||
1192 | (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || | ||
1193 | (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || | ||
1194 | (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || | ||
1195 | (r = sshbuf_put_u8(b, 1)) != 0 || | ||
1196 | (r = sshbuf_put_cstring(b, alg)) != 0 || | ||
1197 | (r = sshkey_puts(id->key, b)) != 0) { | ||
1198 | fatal("%s: assemble signed data: %s", | ||
1199 | __func__, ssh_err(r)); | ||
1200 | } | ||
1201 | |||
1202 | /* generate signature */ | ||
1203 | r = identity_sign(sign_id, &signature, &slen, | ||
1204 | sshbuf_ptr(b), sshbuf_len(b), datafellows, alg); | ||
1205 | if (r == 0) | ||
1206 | break; | ||
1207 | else if (r == SSH_ERR_KEY_NOT_FOUND) | ||
1208 | goto out; /* soft failure */ | ||
1209 | else if (r == SSH_ERR_SIGN_ALG_UNSUPPORTED && | ||
1210 | !fallback_sigtype) { | ||
1211 | if (sign_id->agent_fd != -1) | ||
1212 | loc = "agent "; | ||
1213 | else if ((sign_id->key->flags & SSHKEY_FLAG_EXT) != 0) | ||
1214 | loc = "token "; | ||
1215 | logit("%skey %s %s returned incorrect signature type", | ||
1216 | loc, sshkey_type(id->key), fp); | ||
1217 | continue; | ||
1218 | } | ||
1219 | error("%s: signing failed: %s", __func__, ssh_err(r)); | ||
1220 | goto out; | ||
1180 | } | 1221 | } |
1181 | #ifdef DEBUG_PK | 1222 | if (slen == 0 || signature == NULL) /* shouldn't happen */ |
1182 | buffer_dump(&b); | 1223 | fatal("%s: no signature", __func__); |
1183 | #endif | ||
1184 | free(blob); | ||
1185 | 1224 | ||
1186 | /* append signature */ | 1225 | /* append signature */ |
1187 | buffer_put_string(&b, signature, slen); | 1226 | if ((r = sshbuf_put_string(b, signature, slen)) != 0) |
1188 | free(signature); | 1227 | fatal("%s: append signature: %s", __func__, ssh_err(r)); |
1189 | 1228 | ||
1229 | #ifdef DEBUG_PK | ||
1230 | sshbuf_dump(b, stderr); | ||
1231 | #endif | ||
1190 | /* skip session id and packet type */ | 1232 | /* skip session id and packet type */ |
1191 | if (buffer_len(&b) < skip + 1) | 1233 | if ((r = sshbuf_consume(b, skip + 1)) != 0) |
1192 | fatal("userauth_pubkey: internal error"); | 1234 | fatal("%s: consume: %s", __func__, ssh_err(r)); |
1193 | buffer_consume(&b, skip + 1); | ||
1194 | 1235 | ||
1195 | /* put remaining data from buffer into packet */ | 1236 | /* put remaining data from buffer into packet */ |
1196 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 1237 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
1197 | packet_put_raw(buffer_ptr(&b), buffer_len(&b)); | 1238 | (r = sshpkt_putb(ssh, b)) != 0 || |
1198 | buffer_free(&b); | 1239 | (r = sshpkt_send(ssh)) != 0) |
1199 | packet_send(); | 1240 | fatal("%s: enqueue request: %s", __func__, ssh_err(r)); |
1200 | 1241 | ||
1201 | return 1; | 1242 | /* success */ |
1243 | sent = 1; | ||
1244 | |||
1245 | out: | ||
1246 | free(fp); | ||
1247 | free(alg); | ||
1248 | sshbuf_free(b); | ||
1249 | freezero(signature, slen); | ||
1250 | return sent; | ||
1202 | } | 1251 | } |
1203 | 1252 | ||
1204 | static int | 1253 | static int |
1205 | send_pubkey_test(Authctxt *authctxt, Identity *id) | 1254 | send_pubkey_test(struct ssh *ssh, Authctxt *authctxt, Identity *id) |
1206 | { | 1255 | { |
1207 | u_char *blob; | 1256 | u_char *blob = NULL; |
1208 | u_int bloblen, have_sig = 0; | 1257 | u_int bloblen, have_sig = 0; |
1258 | char *alg = NULL; | ||
1259 | int sent = 0; | ||
1209 | 1260 | ||
1210 | debug3("send_pubkey_test"); | 1261 | if ((alg = key_sig_algorithm(ssh, id->key)) == NULL) { |
1262 | debug("%s: no mutual signature algorithm", __func__); | ||
1263 | goto out; | ||
1264 | } | ||
1211 | 1265 | ||
1212 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { | 1266 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { |
1213 | /* we cannot handle this key */ | 1267 | /* we cannot handle this key */ |
1214 | debug3("send_pubkey_test: cannot handle key"); | 1268 | debug3("%s: cannot handle key", __func__); |
1215 | return 0; | 1269 | goto out; |
1216 | } | 1270 | } |
1217 | /* register callback for USERAUTH_PK_OK message */ | 1271 | /* register callback for USERAUTH_PK_OK message */ |
1218 | dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); | 1272 | dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); |
@@ -1222,11 +1276,15 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) | |||
1222 | packet_put_cstring(authctxt->service); | 1276 | packet_put_cstring(authctxt->service); |
1223 | packet_put_cstring(authctxt->method->name); | 1277 | packet_put_cstring(authctxt->method->name); |
1224 | packet_put_char(have_sig); | 1278 | packet_put_char(have_sig); |
1225 | packet_put_cstring(key_sign_encode(id->key)); | 1279 | packet_put_cstring(alg); |
1226 | packet_put_string(blob, bloblen); | 1280 | packet_put_string(blob, bloblen); |
1227 | free(blob); | ||
1228 | packet_send(); | 1281 | packet_send(); |
1229 | return 1; | 1282 | /* success */ |
1283 | sent = 1; | ||
1284 | out: | ||
1285 | free(alg); | ||
1286 | free(blob); | ||
1287 | return sent; | ||
1230 | } | 1288 | } |
1231 | 1289 | ||
1232 | static struct sshkey * | 1290 | static struct sshkey * |
@@ -1295,6 +1353,36 @@ load_identity_file(Identity *id) | |||
1295 | return private; | 1353 | return private; |
1296 | } | 1354 | } |
1297 | 1355 | ||
1356 | static int | ||
1357 | key_type_allowed_by_config(struct sshkey *key) | ||
1358 | { | ||
1359 | if (match_pattern_list(sshkey_ssh_name(key), | ||
1360 | options.pubkey_key_types, 0) == 1) | ||
1361 | return 1; | ||
1362 | |||
1363 | /* RSA keys/certs might be allowed by alternate signature types */ | ||
1364 | switch (key->type) { | ||
1365 | case KEY_RSA: | ||
1366 | if (match_pattern_list("rsa-sha2-512", | ||
1367 | options.pubkey_key_types, 0) == 1) | ||
1368 | return 1; | ||
1369 | if (match_pattern_list("rsa-sha2-256", | ||
1370 | options.pubkey_key_types, 0) == 1) | ||
1371 | return 1; | ||
1372 | break; | ||
1373 | case KEY_RSA_CERT: | ||
1374 | if (match_pattern_list("rsa-sha2-512-cert-v01@openssh.com", | ||
1375 | options.pubkey_key_types, 0) == 1) | ||
1376 | return 1; | ||
1377 | if (match_pattern_list("rsa-sha2-256-cert-v01@openssh.com", | ||
1378 | options.pubkey_key_types, 0) == 1) | ||
1379 | return 1; | ||
1380 | break; | ||
1381 | } | ||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | |||
1298 | /* | 1386 | /* |
1299 | * try keys in the following order: | 1387 | * try keys in the following order: |
1300 | * 1. certificates listed in the config file | 1388 | * 1. certificates listed in the config file |
@@ -1419,9 +1507,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1419 | } | 1507 | } |
1420 | /* finally, filter by PubkeyAcceptedKeyTypes */ | 1508 | /* finally, filter by PubkeyAcceptedKeyTypes */ |
1421 | TAILQ_FOREACH_SAFE(id, preferred, next, id2) { | 1509 | TAILQ_FOREACH_SAFE(id, preferred, next, id2) { |
1422 | if (id->key != NULL && | 1510 | if (id->key != NULL && !key_type_allowed_by_config(key)) { |
1423 | match_pattern_list(sshkey_ssh_name(id->key), | ||
1424 | options.pubkey_key_types, 0) != 1) { | ||
1425 | debug("Skipping %s key %s - " | 1511 | debug("Skipping %s key %s - " |
1426 | "not in PubkeyAcceptedKeyTypes", | 1512 | "not in PubkeyAcceptedKeyTypes", |
1427 | sshkey_ssh_name(id->key), id->filename); | 1513 | sshkey_ssh_name(id->key), id->filename); |
@@ -1479,6 +1565,7 @@ try_identity(Identity *id) | |||
1479 | int | 1565 | int |
1480 | userauth_pubkey(Authctxt *authctxt) | 1566 | userauth_pubkey(Authctxt *authctxt) |
1481 | { | 1567 | { |
1568 | struct ssh *ssh = active_state; /* XXX */ | ||
1482 | Identity *id; | 1569 | Identity *id; |
1483 | int sent = 0; | 1570 | int sent = 0; |
1484 | char *fp; | 1571 | char *fp; |
@@ -1506,7 +1593,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1506 | debug("Offering public key: %s %s %s", | 1593 | debug("Offering public key: %s %s %s", |
1507 | sshkey_type(id->key), fp, id->filename); | 1594 | sshkey_type(id->key), fp, id->filename); |
1508 | free(fp); | 1595 | free(fp); |
1509 | sent = send_pubkey_test(authctxt, id); | 1596 | sent = send_pubkey_test(ssh, authctxt, id); |
1510 | } | 1597 | } |
1511 | } else { | 1598 | } else { |
1512 | debug("Trying private key: %s", id->filename); | 1599 | debug("Trying private key: %s", id->filename); |
@@ -1514,7 +1601,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1514 | if (id->key != NULL) { | 1601 | if (id->key != NULL) { |
1515 | if (try_identity(id)) { | 1602 | if (try_identity(id)) { |
1516 | id->isprivate = 1; | 1603 | id->isprivate = 1; |
1517 | sent = sign_and_send_pubkey( | 1604 | sent = sign_and_send_pubkey(ssh, |
1518 | authctxt, id); | 1605 | authctxt, id); |
1519 | } | 1606 | } |
1520 | key_free(id->key); | 1607 | key_free(id->key); |
@@ -1735,7 +1822,7 @@ ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, | |||
1735 | int | 1822 | int |
1736 | userauth_hostbased(Authctxt *authctxt) | 1823 | userauth_hostbased(Authctxt *authctxt) |
1737 | { | 1824 | { |
1738 | struct ssh *ssh = active_state; | 1825 | struct ssh *ssh = active_state; /* XXX */ |
1739 | struct sshkey *private = NULL; | 1826 | struct sshkey *private = NULL; |
1740 | struct sshbuf *b = NULL; | 1827 | struct sshbuf *b = NULL; |
1741 | u_char *sig = NULL, *keyblob = NULL; | 1828 | u_char *sig = NULL, *keyblob = NULL; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.508 2018/04/13 03:57:26 dtucker Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.509 2018/07/03 11:39:54 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 |
@@ -681,45 +681,47 @@ privsep_postauth(Authctxt *authctxt) | |||
681 | packet_set_authenticated(); | 681 | packet_set_authenticated(); |
682 | } | 682 | } |
683 | 683 | ||
684 | static void | ||
685 | append_hostkey_type(struct sshbuf *b, const char *s) | ||
686 | { | ||
687 | int r; | ||
688 | |||
689 | if (match_pattern_list(s, options.hostkeyalgorithms, 0) != 1) { | ||
690 | debug3("%s: %s key not permitted by HostkeyAlgorithms", | ||
691 | __func__, s); | ||
692 | return; | ||
693 | } | ||
694 | if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) > 0 ? "," : "", s)) != 0) | ||
695 | fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r)); | ||
696 | } | ||
697 | |||
684 | static char * | 698 | static char * |
685 | list_hostkey_types(void) | 699 | list_hostkey_types(void) |
686 | { | 700 | { |
687 | Buffer b; | 701 | struct sshbuf *b; |
688 | const char *p; | 702 | struct sshkey *key; |
689 | char *ret; | 703 | char *ret; |
690 | u_int i; | 704 | u_int i; |
691 | struct sshkey *key; | ||
692 | 705 | ||
693 | buffer_init(&b); | 706 | if ((b = sshbuf_new()) == NULL) |
707 | fatal("%s: sshbuf_new failed", __func__); | ||
694 | for (i = 0; i < options.num_host_key_files; i++) { | 708 | for (i = 0; i < options.num_host_key_files; i++) { |
695 | key = sensitive_data.host_keys[i]; | 709 | key = sensitive_data.host_keys[i]; |
696 | if (key == NULL) | 710 | if (key == NULL) |
697 | key = sensitive_data.host_pubkeys[i]; | 711 | key = sensitive_data.host_pubkeys[i]; |
698 | if (key == NULL) | 712 | if (key == NULL) |
699 | continue; | 713 | continue; |
700 | /* Check that the key is accepted in HostkeyAlgorithms */ | ||
701 | if (match_pattern_list(sshkey_ssh_name(key), | ||
702 | options.hostkeyalgorithms, 0) != 1) { | ||
703 | debug3("%s: %s key not permitted by HostkeyAlgorithms", | ||
704 | __func__, sshkey_ssh_name(key)); | ||
705 | continue; | ||
706 | } | ||
707 | switch (key->type) { | 714 | switch (key->type) { |
708 | case KEY_RSA: | 715 | case KEY_RSA: |
716 | /* for RSA we also support SHA2 signatures */ | ||
717 | append_hostkey_type(b, "rsa-sha2-512"); | ||
718 | append_hostkey_type(b, "rsa-sha2-256"); | ||
719 | /* FALLTHROUGH */ | ||
709 | case KEY_DSA: | 720 | case KEY_DSA: |
710 | case KEY_ECDSA: | 721 | case KEY_ECDSA: |
711 | case KEY_ED25519: | 722 | case KEY_ED25519: |
712 | case KEY_XMSS: | 723 | case KEY_XMSS: |
713 | if (buffer_len(&b) > 0) | 724 | append_hostkey_type(b, sshkey_ssh_name(key)); |
714 | buffer_append(&b, ",", 1); | ||
715 | p = key_ssh_name(key); | ||
716 | buffer_append(&b, p, strlen(p)); | ||
717 | |||
718 | /* for RSA we also support SHA2 signatures */ | ||
719 | if (key->type == KEY_RSA) { | ||
720 | p = ",rsa-sha2-512,rsa-sha2-256"; | ||
721 | buffer_append(&b, p, strlen(p)); | ||
722 | } | ||
723 | break; | 725 | break; |
724 | } | 726 | } |
725 | /* If the private key has a cert peer, then list that too */ | 727 | /* If the private key has a cert peer, then list that too */ |
@@ -728,21 +730,24 @@ list_hostkey_types(void) | |||
728 | continue; | 730 | continue; |
729 | switch (key->type) { | 731 | switch (key->type) { |
730 | case KEY_RSA_CERT: | 732 | case KEY_RSA_CERT: |
733 | /* for RSA we also support SHA2 signatures */ | ||
734 | append_hostkey_type(b, | ||
735 | "rsa-sha2-512-cert-v01@openssh.com"); | ||
736 | append_hostkey_type(b, | ||
737 | "rsa-sha2-256-cert-v01@openssh.com"); | ||
738 | /* FALLTHROUGH */ | ||
731 | case KEY_DSA_CERT: | 739 | case KEY_DSA_CERT: |
732 | case KEY_ECDSA_CERT: | 740 | case KEY_ECDSA_CERT: |
733 | case KEY_ED25519_CERT: | 741 | case KEY_ED25519_CERT: |
734 | case KEY_XMSS_CERT: | 742 | case KEY_XMSS_CERT: |
735 | if (buffer_len(&b) > 0) | 743 | append_hostkey_type(b, sshkey_ssh_name(key)); |
736 | buffer_append(&b, ",", 1); | ||
737 | p = key_ssh_name(key); | ||
738 | buffer_append(&b, p, strlen(p)); | ||
739 | break; | 744 | break; |
740 | } | 745 | } |
741 | } | 746 | } |
742 | if ((ret = sshbuf_dup_string(&b)) == NULL) | 747 | if ((ret = sshbuf_dup_string(b)) == NULL) |
743 | fatal("%s: sshbuf_dup_string failed", __func__); | 748 | fatal("%s: sshbuf_dup_string failed", __func__); |
744 | buffer_free(&b); | 749 | sshbuf_free(b); |
745 | debug("list_hostkey_types: %s", ret); | 750 | debug("%s: %s", __func__, ret); |
746 | return ret; | 751 | return ret; |
747 | } | 752 | } |
748 | 753 | ||
diff --git a/sshd_config.5 b/sshd_config.5 index 60c5f4bd3..cc019ec7d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -33,7 +33,7 @@ | |||
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: sshd_config.5,v 1.278 2018/07/03 10:59:35 djm Exp $ | 36 | .\" $OpenBSD: sshd_config.5,v 1.279 2018/07/03 11:39:54 djm Exp $ |
37 | .Dd $Mdocdate: July 3 2018 $ | 37 | .Dd $Mdocdate: July 3 2018 $ |
38 | .Dt SSHD_CONFIG 5 | 38 | .Dt SSHD_CONFIG 5 |
39 | .Os | 39 | .Os |
@@ -674,9 +674,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
674 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 674 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
675 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 675 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
676 | ssh-ed25519-cert-v01@openssh.com, | 676 | ssh-ed25519-cert-v01@openssh.com, |
677 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
677 | ssh-rsa-cert-v01@openssh.com, | 678 | ssh-rsa-cert-v01@openssh.com, |
678 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 679 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
679 | ssh-ed25519,ssh-rsa | 680 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
680 | .Ed | 681 | .Ed |
681 | .Pp | 682 | .Pp |
682 | The list of available key types may also be obtained using | 683 | The list of available key types may also be obtained using |
@@ -751,9 +752,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
751 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 752 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
752 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 753 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
753 | ssh-ed25519-cert-v01@openssh.com, | 754 | ssh-ed25519-cert-v01@openssh.com, |
755 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
754 | ssh-rsa-cert-v01@openssh.com, | 756 | ssh-rsa-cert-v01@openssh.com, |
755 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 757 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
756 | ssh-ed25519,ssh-rsa | 758 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
757 | .Ed | 759 | .Ed |
758 | .Pp | 760 | .Pp |
759 | The list of available key types may also be obtained using | 761 | The list of available key types may also be obtained using |
@@ -1399,9 +1401,10 @@ ecdsa-sha2-nistp256-cert-v01@openssh.com, | |||
1399 | ecdsa-sha2-nistp384-cert-v01@openssh.com, | 1401 | ecdsa-sha2-nistp384-cert-v01@openssh.com, |
1400 | ecdsa-sha2-nistp521-cert-v01@openssh.com, | 1402 | ecdsa-sha2-nistp521-cert-v01@openssh.com, |
1401 | ssh-ed25519-cert-v01@openssh.com, | 1403 | ssh-ed25519-cert-v01@openssh.com, |
1404 | rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com, | ||
1402 | ssh-rsa-cert-v01@openssh.com, | 1405 | ssh-rsa-cert-v01@openssh.com, |
1403 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, | 1406 | ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, |
1404 | ssh-ed25519,ssh-rsa | 1407 | ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa |
1405 | .Ed | 1408 | .Ed |
1406 | .Pp | 1409 | .Pp |
1407 | The list of available key types may also be obtained using | 1410 | The list of available key types may also be obtained using |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssherr.c,v 1.7 2017/09/12 06:32:08 djm Exp $ */ | 1 | /* $OpenBSD: ssherr.c,v 1.8 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -139,6 +139,8 @@ ssh_err(int n) | |||
139 | return "Invalid key length"; | 139 | return "Invalid key length"; |
140 | case SSH_ERR_NUMBER_TOO_LARGE: | 140 | case SSH_ERR_NUMBER_TOO_LARGE: |
141 | return "number is too large"; | 141 | return "number is too large"; |
142 | case SSH_ERR_SIGN_ALG_UNSUPPORTED: | ||
143 | return "signature algorithm not supported"; | ||
142 | default: | 144 | default: |
143 | return "unknown error"; | 145 | return "unknown error"; |
144 | } | 146 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssherr.h,v 1.5 2017/09/12 06:32:08 djm Exp $ */ | 1 | /* $OpenBSD: ssherr.h,v 1.6 2018/07/03 11:39:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2011 Damien Miller | 3 | * Copyright (c) 2011 Damien Miller |
4 | * | 4 | * |
@@ -79,6 +79,7 @@ | |||
79 | #define SSH_ERR_PROTOCOL_ERROR -55 | 79 | #define SSH_ERR_PROTOCOL_ERROR -55 |
80 | #define SSH_ERR_KEY_LENGTH -56 | 80 | #define SSH_ERR_KEY_LENGTH -56 |
81 | #define SSH_ERR_NUMBER_TOO_LARGE -57 | 81 | #define SSH_ERR_NUMBER_TOO_LARGE -57 |
82 | #define SSH_ERR_SIGN_ALG_UNSUPPORTED -58 | ||
82 | 83 | ||
83 | /* Translate a numeric error code to a human-readable error string */ | 84 | /* Translate a numeric error code to a human-readable error string */ |
84 | const char *ssh_err(int n); | 85 | const char *ssh_err(int n); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.64 2018/03/22 07:05:48 markus Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.65 2018/07/03 11:39:54 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 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | 4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. |
@@ -83,46 +83,64 @@ static int sshkey_from_blob_internal(struct sshbuf *buf, | |||
83 | struct keytype { | 83 | struct keytype { |
84 | const char *name; | 84 | const char *name; |
85 | const char *shortname; | 85 | const char *shortname; |
86 | const char *sigalg; | ||
86 | int type; | 87 | int type; |
87 | int nid; | 88 | int nid; |
88 | int cert; | 89 | int cert; |
89 | int sigonly; | 90 | int sigonly; |
90 | }; | 91 | }; |
91 | static const struct keytype keytypes[] = { | 92 | static const struct keytype keytypes[] = { |
92 | { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 }, | 93 | { "ssh-ed25519", "ED25519", NULL, KEY_ED25519, 0, 0, 0 }, |
93 | { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", | 94 | { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", NULL, |
94 | KEY_ED25519_CERT, 0, 1, 0 }, | 95 | KEY_ED25519_CERT, 0, 1, 0 }, |
95 | #ifdef WITH_XMSS | 96 | #ifdef WITH_XMSS |
96 | { "ssh-xmss@openssh.com", "XMSS", KEY_XMSS, 0, 0, 0 }, | 97 | { "ssh-xmss@openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 }, |
97 | { "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", | 98 | { "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", NULL, |
98 | KEY_XMSS_CERT, 0, 1, 0 }, | 99 | KEY_XMSS_CERT, 0, 1, 0 }, |
99 | #endif /* WITH_XMSS */ | 100 | #endif /* WITH_XMSS */ |
100 | #ifdef WITH_OPENSSL | 101 | #ifdef WITH_OPENSSL |
101 | { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 }, | 102 | { "ssh-rsa", "RSA", NULL, KEY_RSA, 0, 0, 0 }, |
102 | { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 }, | 103 | { "rsa-sha2-256", "RSA", NULL, KEY_RSA, 0, 0, 1 }, |
103 | { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 }, | 104 | { "rsa-sha2-512", "RSA", NULL, KEY_RSA, 0, 0, 1 }, |
104 | { "ssh-dss", "DSA", KEY_DSA, 0, 0, 0 }, | 105 | { "ssh-dss", "DSA", NULL, KEY_DSA, 0, 0, 0 }, |
105 | # ifdef OPENSSL_HAS_ECC | 106 | # ifdef OPENSSL_HAS_ECC |
106 | { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 }, | 107 | { "ecdsa-sha2-nistp256", "ECDSA", NULL, |
107 | { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0, 0 }, | 108 | KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 }, |
109 | { "ecdsa-sha2-nistp384", "ECDSA", NULL, | ||
110 | KEY_ECDSA, NID_secp384r1, 0, 0 }, | ||
108 | # ifdef OPENSSL_HAS_NISTP521 | 111 | # ifdef OPENSSL_HAS_NISTP521 |
109 | { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0, 0 }, | 112 | { "ecdsa-sha2-nistp521", "ECDSA", NULL, |
113 | KEY_ECDSA, NID_secp521r1, 0, 0 }, | ||
110 | # endif /* OPENSSL_HAS_NISTP521 */ | 114 | # endif /* OPENSSL_HAS_NISTP521 */ |
111 | # endif /* OPENSSL_HAS_ECC */ | 115 | # endif /* OPENSSL_HAS_ECC */ |
112 | { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1, 0 }, | 116 | { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL, |
113 | { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1, 0 }, | 117 | KEY_RSA_CERT, 0, 1, 0 }, |
118 | { "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT", | ||
119 | "ssh-rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 }, | ||
120 | { "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT", | ||
121 | "ssh-rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 }, | ||
122 | { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL, | ||
123 | KEY_DSA_CERT, 0, 1, 0 }, | ||
124 | { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL, | ||
125 | KEY_RSA_CERT, 0, 1, 0 }, | ||
126 | { "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT", | ||
127 | "ssh-rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 }, | ||
128 | { "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT", | ||
129 | "ssh-rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 }, | ||
130 | { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL, | ||
131 | KEY_DSA_CERT, 0, 1, 0 }, | ||
114 | # ifdef OPENSSL_HAS_ECC | 132 | # ifdef OPENSSL_HAS_ECC |
115 | { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", | 133 | { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
116 | KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 }, | 134 | KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 }, |
117 | { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", | 135 | { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
118 | KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, | 136 | KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, |
119 | # ifdef OPENSSL_HAS_NISTP521 | 137 | # ifdef OPENSSL_HAS_NISTP521 |
120 | { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", | 138 | { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL, |
121 | KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, | 139 | KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, |
122 | # endif /* OPENSSL_HAS_NISTP521 */ | 140 | # endif /* OPENSSL_HAS_NISTP521 */ |
123 | # endif /* OPENSSL_HAS_ECC */ | 141 | # endif /* OPENSSL_HAS_ECC */ |
124 | #endif /* WITH_OPENSSL */ | 142 | #endif /* WITH_OPENSSL */ |
125 | { NULL, NULL, -1, -1, 0, 0 } | 143 | { NULL, NULL, NULL, -1, -1, 0, 0 } |
126 | }; | 144 | }; |
127 | 145 | ||
128 | const char * | 146 | const char * |
@@ -2198,8 +2216,8 @@ sshkey_froms(struct sshbuf *buf, struct sshkey **keyp) | |||
2198 | return r; | 2216 | return r; |
2199 | } | 2217 | } |
2200 | 2218 | ||
2201 | int | 2219 | static int |
2202 | sshkey_sigtype(const u_char *sig, size_t siglen, char **sigtypep) | 2220 | get_sigtype(const u_char *sig, size_t siglen, char **sigtypep) |
2203 | { | 2221 | { |
2204 | int r; | 2222 | int r; |
2205 | struct sshbuf *b = NULL; | 2223 | struct sshbuf *b = NULL; |
@@ -2223,6 +2241,50 @@ sshkey_sigtype(const u_char *sig, size_t siglen, char **sigtypep) | |||
2223 | return r; | 2241 | return r; |
2224 | } | 2242 | } |
2225 | 2243 | ||
2244 | /* | ||
2245 | * Returns the expected signature algorithm for a given public key algorithm. | ||
2246 | */ | ||
2247 | static const char * | ||
2248 | sigalg_by_name(const char *name) | ||
2249 | { | ||
2250 | const struct keytype *kt; | ||
2251 | |||
2252 | for (kt = keytypes; kt->type != -1; kt++) { | ||
2253 | if (strcmp(kt->name, name) != 0) | ||
2254 | continue; | ||
2255 | if (kt->sigalg != NULL) | ||
2256 | return kt->sigalg; | ||
2257 | if (!kt->cert) | ||
2258 | return kt->name; | ||
2259 | return sshkey_ssh_name_from_type_nid( | ||
2260 | sshkey_type_plain(kt->type), kt->nid); | ||
2261 | } | ||
2262 | return NULL; | ||
2263 | } | ||
2264 | |||
2265 | /* | ||
2266 | * Verifies that the signature algorithm appearing inside the signature blob | ||
2267 | * matches that which was requested. | ||
2268 | */ | ||
2269 | int | ||
2270 | sshkey_check_sigtype(const u_char *sig, size_t siglen, | ||
2271 | const char *requested_alg) | ||
2272 | { | ||
2273 | const char *expected_alg; | ||
2274 | char *sigtype = NULL; | ||
2275 | int r; | ||
2276 | |||
2277 | if (requested_alg == NULL) | ||
2278 | return 0; | ||
2279 | if ((expected_alg = sigalg_by_name(requested_alg)) == NULL) | ||
2280 | return SSH_ERR_INVALID_ARGUMENT; | ||
2281 | if ((r = get_sigtype(sig, siglen, &sigtype)) != 0) | ||
2282 | return r; | ||
2283 | r = strcmp(expected_alg, sigtype) == 0; | ||
2284 | free(sigtype); | ||
2285 | return r ? 0 : SSH_ERR_SIGN_ALG_UNSUPPORTED; | ||
2286 | } | ||
2287 | |||
2226 | int | 2288 | int |
2227 | sshkey_sign(const struct sshkey *key, | 2289 | sshkey_sign(const struct sshkey *key, |
2228 | u_char **sigp, size_t *lenp, | 2290 | u_char **sigp, size_t *lenp, |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.h,v 1.24 2018/02/23 15:58:38 markus Exp $ */ | 1 | /* $OpenBSD: sshkey.h,v 1.25 2018/07/03 11:39:54 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. |
@@ -191,11 +191,11 @@ int sshkey_puts_opts(const struct sshkey *, struct sshbuf *, | |||
191 | int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); | 191 | int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); |
192 | int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); | 192 | int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); |
193 | 193 | ||
194 | int sshkey_sigtype(const u_char *, size_t, char **); | ||
195 | int sshkey_sign(const struct sshkey *, u_char **, size_t *, | 194 | int sshkey_sign(const struct sshkey *, u_char **, size_t *, |
196 | const u_char *, size_t, const char *, u_int); | 195 | const u_char *, size_t, const char *, u_int); |
197 | int sshkey_verify(const struct sshkey *, const u_char *, size_t, | 196 | int sshkey_verify(const struct sshkey *, const u_char *, size_t, |
198 | const u_char *, size_t, const char *, u_int); | 197 | const u_char *, size_t, const char *, u_int); |
198 | int sshkey_check_sigtype(const u_char *, size_t, const char *); | ||
199 | 199 | ||
200 | /* for debug */ | 200 | /* for debug */ |
201 | void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *); | 201 | void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *); |