summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2020-02-21 11:57:14 +0000
committerColin Watson <cjwatson@debian.org>2020-02-21 14:27:02 +0000
commit886e47e745586c34e81cfd5c5fb9b5dbc8e84d04 (patch)
treedd6c3b4dc64a17c520af7aaf213163f8a0a63e56 /sshconnect2.c
parentac2b4c0697fcac554041ab95f81736887eadf6ec (diff)
parenta2dabf35ce0228c86a288d11cc847a9d9801604f (diff)
New upstream release (8.2p1)
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c174
1 files changed, 125 insertions, 49 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index a4ec75ca1..03bc87eb4 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.308 2019/08/05 11:50:33 dtucker Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.320 2020/02/06 22:48:23 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.
@@ -36,9 +36,9 @@
36#include <netdb.h> 36#include <netdb.h>
37#include <pwd.h> 37#include <pwd.h>
38#include <signal.h> 38#include <signal.h>
39#include <stdarg.h>
40#include <stdio.h> 39#include <stdio.h>
41#include <string.h> 40#include <string.h>
41#include <stdarg.h>
42#include <unistd.h> 42#include <unistd.h>
43#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) 43#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
44#include <vis.h> 44#include <vis.h>
@@ -72,6 +72,8 @@
72#include "hostfile.h" 72#include "hostfile.h"
73#include "ssherr.h" 73#include "ssherr.h"
74#include "utf8.h" 74#include "utf8.h"
75#include "ssh-sk.h"
76#include "sk-api.h"
75 77
76#ifdef GSSAPI 78#ifdef GSSAPI
77#include "ssh-gss.h" 79#include "ssh-gss.h"
@@ -115,7 +117,7 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
115 for (i = 0; i < options.num_system_hostfiles; i++) 117 for (i = 0; i < options.num_system_hostfiles; i++)
116 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); 118 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]);
117 119
118 oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG); 120 oavail = avail = xstrdup(options.hostkeyalgorithms);
119 maxlen = strlen(avail) + 1; 121 maxlen = strlen(avail) + 1;
120 first = xmalloc(maxlen); 122 first = xmalloc(maxlen);
121 last = xmalloc(maxlen); 123 last = xmalloc(maxlen);
@@ -157,7 +159,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
157{ 159{
158 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 160 char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
159 char *s, *all_key; 161 char *s, *all_key;
160 int r; 162 int r, use_known_hosts_order = 0;
161 163
162#if defined(GSSAPI) && defined(WITH_OPENSSL) 164#if defined(GSSAPI) && defined(WITH_OPENSSL)
163 char *orig = NULL, *gss = NULL; 165 char *orig = NULL, *gss = NULL;
@@ -167,6 +169,23 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
167 xxx_host = host; 169 xxx_host = host;
168 xxx_hostaddr = hostaddr; 170 xxx_hostaddr = hostaddr;
169 171
172 /*
173 * If the user has not specified HostkeyAlgorithms, or has only
174 * appended or removed algorithms from that list then prefer algorithms
175 * that are in the list that are supported by known_hosts keys.
176 */
177 if (options.hostkeyalgorithms == NULL ||
178 options.hostkeyalgorithms[0] == '-' ||
179 options.hostkeyalgorithms[0] == '+')
180 use_known_hosts_order = 1;
181
182 /* Expand or fill in HostkeyAlgorithms */
183 all_key = sshkey_alg_list(0, 0, 1, ',');
184 if (kex_assemble_names(&options.hostkeyalgorithms,
185 kex_default_pk_alg(), all_key) != 0)
186 fatal("%s: kex_assemble_namelist", __func__);
187 free(all_key);
188
170 if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) 189 if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
171 fatal("%s: kex_names_cat", __func__); 190 fatal("%s: kex_names_cat", __func__);
172 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); 191 myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
@@ -175,25 +194,19 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
175 myproposal[PROPOSAL_ENC_ALGS_STOC] = 194 myproposal[PROPOSAL_ENC_ALGS_STOC] =
176 compat_cipher_proposal(options.ciphers); 195 compat_cipher_proposal(options.ciphers);
177 myproposal[PROPOSAL_COMP_ALGS_CTOS] = 196 myproposal[PROPOSAL_COMP_ALGS_CTOS] =
178 myproposal[PROPOSAL_COMP_ALGS_STOC] = options.compression ? 197 myproposal[PROPOSAL_COMP_ALGS_STOC] =
179 "zlib@openssh.com,zlib,none" : "none,zlib@openssh.com,zlib"; 198 (char *)compression_alg_list(options.compression);
180 myproposal[PROPOSAL_MAC_ALGS_CTOS] = 199 myproposal[PROPOSAL_MAC_ALGS_CTOS] =
181 myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 200 myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
182 if (options.hostkeyalgorithms != NULL) { 201 if (use_known_hosts_order) {
183 all_key = sshkey_alg_list(0, 0, 1, ','); 202 /* Query known_hosts and prefer algorithms that appear there */
184 if (kex_assemble_names(&options.hostkeyalgorithms,
185 KEX_DEFAULT_PK_ALG, all_key) != 0)
186 fatal("%s: kex_assemble_namelist", __func__);
187 free(all_key);
188 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
189 compat_pkalg_proposal(options.hostkeyalgorithms);
190 } else {
191 /* Enforce default */
192 options.hostkeyalgorithms = xstrdup(KEX_DEFAULT_PK_ALG);
193 /* Prefer algorithms that we already have keys for */
194 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 203 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
195 compat_pkalg_proposal( 204 compat_pkalg_proposal(
196 order_hostkeyalgs(host, hostaddr, port)); 205 order_hostkeyalgs(host, hostaddr, port));
206 } else {
207 /* Use specified HostkeyAlgorithms exactly */
208 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
209 compat_pkalg_proposal(options.hostkeyalgorithms);
197 } 210 }
198 211
199#if defined(GSSAPI) && defined(WITH_OPENSSL) 212#if defined(GSSAPI) && defined(WITH_OPENSSL)
@@ -254,7 +267,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port)
254 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client; 267 ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client;
255 } 268 }
256# endif 269# endif
257#endif 270#endif /* WITH_OPENSSL */
258 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 271 ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
259 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 272 ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client;
260 ssh->kex->verify_host_key=&verify_host_key_callback; 273 ssh->kex->verify_host_key=&verify_host_key_callback;
@@ -669,17 +682,23 @@ static char *
669format_identity(Identity *id) 682format_identity(Identity *id)
670{ 683{
671 char *fp = NULL, *ret = NULL; 684 char *fp = NULL, *ret = NULL;
685 const char *note = "";
672 686
673 if (id->key != NULL) { 687 if (id->key != NULL) {
674 fp = sshkey_fingerprint(id->key, options.fingerprint_hash, 688 fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
675 SSH_FP_DEFAULT); 689 SSH_FP_DEFAULT);
676 } 690 }
691 if (id->key) {
692 if ((id->key->flags & SSHKEY_FLAG_EXT) != 0)
693 note = " token";
694 else if (sshkey_is_sk(id->key))
695 note = " authenticator";
696 }
677 xasprintf(&ret, "%s %s%s%s%s%s%s", 697 xasprintf(&ret, "%s %s%s%s%s%s%s",
678 id->filename, 698 id->filename,
679 id->key ? sshkey_type(id->key) : "", id->key ? " " : "", 699 id->key ? sshkey_type(id->key) : "", id->key ? " " : "",
680 fp ? fp : "", 700 fp ? fp : "",
681 id->userprovided ? " explicit" : "", 701 id->userprovided ? " explicit" : "", note,
682 (id->key && (id->key->flags & SSHKEY_FLAG_EXT)) ? " token" : "",
683 id->agent_fd != -1 ? " agent" : ""); 702 id->agent_fd != -1 ? " agent" : "");
684 free(fp); 703 free(fp);
685 return ret; 704 return ret;
@@ -1272,8 +1291,13 @@ static int
1272identity_sign(struct identity *id, u_char **sigp, size_t *lenp, 1291identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1273 const u_char *data, size_t datalen, u_int compat, const char *alg) 1292 const u_char *data, size_t datalen, u_int compat, const char *alg)
1274{ 1293{
1275 struct sshkey *prv; 1294 struct sshkey *sign_key = NULL, *prv = NULL;
1276 int r; 1295 int r = SSH_ERR_INTERNAL_ERROR;
1296 struct notifier_ctx *notifier = NULL;
1297 char *fp = NULL;
1298
1299 *sigp = NULL;
1300 *lenp = 0;
1277 1301
1278 /* The agent supports this key. */ 1302 /* The agent supports this key. */
1279 if (id->key != NULL && id->agent_fd != -1) { 1303 if (id->key != NULL && id->agent_fd != -1) {
@@ -1287,27 +1311,47 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1287 */ 1311 */
1288 if (id->key != NULL && 1312 if (id->key != NULL &&
1289 (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { 1313 (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) {
1290 if ((r = sshkey_sign(id->key, sigp, lenp, data, datalen, 1314 sign_key = id->key;
1291 alg, compat)) != 0) 1315 } else {
1292 return r; 1316 /* Load the private key from the file. */
1293 /* 1317 if ((prv = load_identity_file(id)) == NULL)
1294 * PKCS#11 tokens may not support all signature algorithms, 1318 return SSH_ERR_KEY_NOT_FOUND;
1295 * so check what we get back. 1319 if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
1296 */ 1320 error("%s: private key %s contents do not match public",
1297 if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) 1321 __func__, id->filename);
1298 return r; 1322 r = SSH_ERR_KEY_NOT_FOUND;
1299 return 0; 1323 goto out;
1324 }
1325 sign_key = prv;
1326 if (sshkey_is_sk(sign_key) &&
1327 (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
1328 /* XXX match batch mode should just skip these keys? */
1329 if ((fp = sshkey_fingerprint(sign_key,
1330 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
1331 fatal("%s: sshkey_fingerprint", __func__);
1332 notifier = notify_start(options.batch_mode,
1333 "Confirm user presence for key %s %s",
1334 sshkey_type(sign_key), fp);
1335 free(fp);
1336 }
1300 } 1337 }
1301 1338 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
1302 /* Load the private key from the file. */ 1339 alg, options.sk_provider, compat)) != 0) {
1303 if ((prv = load_identity_file(id)) == NULL) 1340 debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1304 return SSH_ERR_KEY_NOT_FOUND; 1341 goto out;
1305 if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
1306 error("%s: private key %s contents do not match public",
1307 __func__, id->filename);
1308 return SSH_ERR_KEY_NOT_FOUND;
1309 } 1342 }
1310 r = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); 1343 /*
1344 * PKCS#11 tokens may not support all signature algorithms,
1345 * so check what we get back.
1346 */
1347 if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) {
1348 debug("%s: sshkey_check_sigtype: %s", __func__, ssh_err(r));
1349 goto out;
1350 }
1351 /* success */
1352 r = 0;
1353 out:
1354 notify_complete(notifier);
1311 sshkey_free(prv); 1355 sshkey_free(prv);
1312 return r; 1356 return r;
1313} 1357}
@@ -1410,7 +1454,7 @@ sign_and_send_pubkey(struct ssh *ssh, Identity *id)
1410 error("%s: no mutual signature supported", __func__); 1454 error("%s: no mutual signature supported", __func__);
1411 goto out; 1455 goto out;
1412 } 1456 }
1413 debug3("%s: signing using %s", __func__, alg); 1457 debug3("%s: signing using %s %s", __func__, alg, fp);
1414 1458
1415 sshbuf_free(b); 1459 sshbuf_free(b);
1416 if ((b = sshbuf_new()) == NULL) 1460 if ((b = sshbuf_new()) == NULL)
@@ -1457,7 +1501,9 @@ sign_and_send_pubkey(struct ssh *ssh, Identity *id)
1457 loc, sshkey_type(id->key), fp); 1501 loc, sshkey_type(id->key), fp);
1458 continue; 1502 continue;
1459 } 1503 }
1460 error("%s: signing failed: %s", __func__, ssh_err(r)); 1504 error("%s: signing failed for %s \"%s\"%s: %s", __func__,
1505 sshkey_type(sign_id->key), sign_id->filename,
1506 id->agent_fd != -1 ? " from agent" : "", ssh_err(r));
1461 goto out; 1507 goto out;
1462 } 1508 }
1463 if (slen == 0 || signature == NULL) /* shouldn't happen */ 1509 if (slen == 0 || signature == NULL) /* shouldn't happen */
@@ -1582,6 +1628,14 @@ load_identity_file(Identity *id)
1582 quit = 1; 1628 quit = 1;
1583 break; 1629 break;
1584 } 1630 }
1631 if (private != NULL && sshkey_is_sk(private) &&
1632 options.sk_provider == NULL) {
1633 debug("key \"%s\" is an authenticator-hosted key, "
1634 "but no provider specified", id->filename);
1635 sshkey_free(private);
1636 private = NULL;
1637 quit = 1;
1638 }
1585 if (!quit && private != NULL && id->agent_fd == -1 && 1639 if (!quit && private != NULL && id->agent_fd == -1 &&
1586 !(id->key && id->isprivate)) 1640 !(id->key && id->isprivate))
1587 maybe_add_key_to_agent(id->filename, private, comment, 1641 maybe_add_key_to_agent(id->filename, private, comment,
@@ -1652,8 +1706,19 @@ pubkey_prepare(Authctxt *authctxt)
1652 /* list of keys stored in the filesystem and PKCS#11 */ 1706 /* list of keys stored in the filesystem and PKCS#11 */
1653 for (i = 0; i < options.num_identity_files; i++) { 1707 for (i = 0; i < options.num_identity_files; i++) {
1654 key = options.identity_keys[i]; 1708 key = options.identity_keys[i];
1655 if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) 1709 if (key && key->cert &&
1710 key->cert->type != SSH2_CERT_TYPE_USER) {
1711 debug("%s: ignoring certificate %s: not a user "
1712 "certificate", __func__,
1713 options.identity_files[i]);
1714 continue;
1715 }
1716 if (key && sshkey_is_sk(key) && options.sk_provider == NULL) {
1717 debug("%s: ignoring authenticator-hosted key %s as no "
1718 "SecurityKeyProvider has been specified",
1719 __func__, options.identity_files[i]);
1656 continue; 1720 continue;
1721 }
1657 options.identity_keys[i] = NULL; 1722 options.identity_keys[i] = NULL;
1658 id = xcalloc(1, sizeof(*id)); 1723 id = xcalloc(1, sizeof(*id));
1659 id->agent_fd = -1; 1724 id->agent_fd = -1;
@@ -1666,8 +1731,19 @@ pubkey_prepare(Authctxt *authctxt)
1666 for (i = 0; i < options.num_certificate_files; i++) { 1731 for (i = 0; i < options.num_certificate_files; i++) {
1667 key = options.certificates[i]; 1732 key = options.certificates[i];
1668 if (!sshkey_is_cert(key) || key->cert == NULL || 1733 if (!sshkey_is_cert(key) || key->cert == NULL ||
1669 key->cert->type != SSH2_CERT_TYPE_USER) 1734 key->cert->type != SSH2_CERT_TYPE_USER) {
1735 debug("%s: ignoring certificate %s: not a user "
1736 "certificate", __func__,
1737 options.identity_files[i]);
1670 continue; 1738 continue;
1739 }
1740 if (key && sshkey_is_sk(key) && options.sk_provider == NULL) {
1741 debug("%s: ignoring authenticator-hosted key "
1742 "certificate %s as no "
1743 "SecurityKeyProvider has been specified",
1744 __func__, options.identity_files[i]);
1745 continue;
1746 }
1671 id = xcalloc(1, sizeof(*id)); 1747 id = xcalloc(1, sizeof(*id));
1672 id->agent_fd = -1; 1748 id->agent_fd = -1;
1673 id->key = key; 1749 id->key = key;
@@ -1992,7 +2068,7 @@ ssh_keysign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
1992 error("%s: fork: %s", __func__, strerror(errno)); 2068 error("%s: fork: %s", __func__, strerror(errno));
1993 return -1; 2069 return -1;
1994 } 2070 }
1995 osigchld = signal(SIGCHLD, SIG_DFL); 2071 osigchld = ssh_signal(SIGCHLD, SIG_DFL);
1996 if (pid == 0) { 2072 if (pid == 0) {
1997 close(from[0]); 2073 close(from[0]);
1998 if (dup2(from[1], STDOUT_FILENO) == -1) 2074 if (dup2(from[1], STDOUT_FILENO) == -1)
@@ -2064,11 +2140,11 @@ ssh_keysign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
2064 if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { 2140 if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) {
2065 error("%s: buffer error: %s", __func__, ssh_err(r)); 2141 error("%s: buffer error: %s", __func__, ssh_err(r));
2066 fail: 2142 fail:
2067 signal(SIGCHLD, osigchld); 2143 ssh_signal(SIGCHLD, osigchld);
2068 sshbuf_free(b); 2144 sshbuf_free(b);
2069 return -1; 2145 return -1;
2070 } 2146 }
2071 signal(SIGCHLD, osigchld); 2147 ssh_signal(SIGCHLD, osigchld);
2072 sshbuf_free(b); 2148 sshbuf_free(b);
2073 2149
2074 return 0; 2150 return 0;