summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c107
1 files changed, 80 insertions, 27 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 79a22e600..c47fc31a6 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.321 2020/04/17 03:38:47 djm Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.326 2020/09/18 05:23:03 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.
@@ -100,12 +100,25 @@ verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
100 return 0; 100 return 0;
101} 101}
102 102
103/* Returns the first item from a comma-separated algorithm list */
104static char *
105first_alg(const char *algs)
106{
107 char *ret, *cp;
108
109 ret = xstrdup(algs);
110 if ((cp = strchr(ret, ',')) != NULL)
111 *cp = '\0';
112 return ret;
113}
114
103static char * 115static char *
104order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) 116order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
105{ 117{
106 char *oavail, *avail, *first, *last, *alg, *hostname, *ret; 118 char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL;
119 char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL;
107 size_t maxlen; 120 size_t maxlen;
108 struct hostkeys *hostkeys; 121 struct hostkeys *hostkeys = NULL;
109 int ktype; 122 int ktype;
110 u_int i; 123 u_int i;
111 124
@@ -117,6 +130,26 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
117 for (i = 0; i < options.num_system_hostfiles; i++) 130 for (i = 0; i < options.num_system_hostfiles; i++)
118 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); 131 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]);
119 132
133 /*
134 * If a plain public key exists that matches the type of the best
135 * preference HostkeyAlgorithms, then use the whole list as is.
136 * Note that we ignore whether the best preference algorithm is a
137 * certificate type, as sshconnect.c will downgrade certs to
138 * plain keys if necessary.
139 */
140 best = first_alg(options.hostkeyalgorithms);
141 if (lookup_key_in_hostkeys_by_type(hostkeys,
142 sshkey_type_plain(sshkey_type_from_name(best)), NULL)) {
143 debug3("%s: have matching best-preference key type %s, "
144 "using HostkeyAlgorithms verbatim", __func__, best);
145 ret = xstrdup(options.hostkeyalgorithms);
146 goto out;
147 }
148
149 /*
150 * Otherwise, prefer the host key algorithms that match known keys
151 * while keeping the ordering of HostkeyAlgorithms as much as possible.
152 */
120 oavail = avail = xstrdup(options.hostkeyalgorithms); 153 oavail = avail = xstrdup(options.hostkeyalgorithms);
121 maxlen = strlen(avail) + 1; 154 maxlen = strlen(avail) + 1;
122 first = xmalloc(maxlen); 155 first = xmalloc(maxlen);
@@ -133,11 +166,23 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
133 while ((alg = strsep(&avail, ",")) && *alg != '\0') { 166 while ((alg = strsep(&avail, ",")) && *alg != '\0') {
134 if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 167 if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
135 fatal("%s: unknown alg %s", __func__, alg); 168 fatal("%s: unknown alg %s", __func__, alg);
169 /*
170 * If we have a @cert-authority marker in known_hosts then
171 * prefer all certificate algorithms.
172 */
173 if (sshkey_type_is_cert(ktype) &&
174 lookup_marker_in_hostkeys(hostkeys, MRK_CA)) {
175 ALG_APPEND(first, alg);
176 continue;
177 }
178 /* If the key appears in known_hosts then prefer it */
136 if (lookup_key_in_hostkeys_by_type(hostkeys, 179 if (lookup_key_in_hostkeys_by_type(hostkeys,
137 sshkey_type_plain(ktype), NULL)) 180 sshkey_type_plain(ktype), NULL)) {
138 ALG_APPEND(first, alg); 181 ALG_APPEND(first, alg);
139 else 182 continue;
140 ALG_APPEND(last, alg); 183 }
184 /* Otherwise, put it last */
185 ALG_APPEND(last, alg);
141 } 186 }
142#undef ALG_APPEND 187#undef ALG_APPEND
143 xasprintf(&ret, "%s%s%s", first, 188 xasprintf(&ret, "%s%s%s", first,
@@ -145,6 +190,8 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
145 if (*first != '\0') 190 if (*first != '\0')
146 debug3("%s: prefer hostkeyalgs: %s", __func__, first); 191 debug3("%s: prefer hostkeyalgs: %s", __func__, first);
147 192
193 out:
194 free(best);
148 free(first); 195 free(first);
149 free(last); 196 free(last);
150 free(hostname); 197 free(hostname);
@@ -1288,7 +1335,8 @@ key_sig_algorithm(struct ssh *ssh, const struct sshkey *key)
1288 while ((cp = strsep(&allowed, ",")) != NULL) { 1335 while ((cp = strsep(&allowed, ",")) != NULL) {
1289 if (sshkey_type_from_name(cp) != key->type) 1336 if (sshkey_type_from_name(cp) != key->type)
1290 continue; 1337 continue;
1291 tmp = match_list(sshkey_sigalg_by_name(cp), ssh->kex->server_sig_algs, NULL); 1338 tmp = match_list(sshkey_sigalg_by_name(cp),
1339 ssh->kex->server_sig_algs, NULL);
1292 if (tmp != NULL) 1340 if (tmp != NULL)
1293 alg = xstrdup(cp); 1341 alg = xstrdup(cp);
1294 free(tmp); 1342 free(tmp);
@@ -1306,7 +1354,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1306 struct sshkey *sign_key = NULL, *prv = NULL; 1354 struct sshkey *sign_key = NULL, *prv = NULL;
1307 int r = SSH_ERR_INTERNAL_ERROR; 1355 int r = SSH_ERR_INTERNAL_ERROR;
1308 struct notifier_ctx *notifier = NULL; 1356 struct notifier_ctx *notifier = NULL;
1309 char *fp = NULL; 1357 char *fp = NULL, *pin = NULL, *prompt = NULL;
1310 1358
1311 *sigp = NULL; 1359 *sigp = NULL;
1312 *lenp = 0; 1360 *lenp = 0;
@@ -1335,20 +1383,28 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1335 goto out; 1383 goto out;
1336 } 1384 }
1337 sign_key = prv; 1385 sign_key = prv;
1338 if (sshkey_is_sk(sign_key) && 1386 if (sshkey_is_sk(sign_key)) {
1339 (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 1387 if ((sign_key->sk_flags &
1340 /* XXX match batch mode should just skip these keys? */ 1388 SSH_SK_USER_VERIFICATION_REQD)) {
1341 if ((fp = sshkey_fingerprint(sign_key, 1389 xasprintf(&prompt, "Enter PIN for %s key %s: ",
1342 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 1390 sshkey_type(sign_key), id->filename);
1343 fatal("%s: sshkey_fingerprint", __func__); 1391 pin = read_passphrase(prompt, 0);
1344 notifier = notify_start(options.batch_mode, 1392 }
1345 "Confirm user presence for key %s %s", 1393 if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
1346 sshkey_type(sign_key), fp); 1394 /* XXX should batch mode just skip these? */
1347 free(fp); 1395 if ((fp = sshkey_fingerprint(sign_key,
1396 options.fingerprint_hash,
1397 SSH_FP_DEFAULT)) == NULL)
1398 fatal("%s: fingerprint", __func__);
1399 notifier = notify_start(options.batch_mode,
1400 "Confirm user presence for key %s %s",
1401 sshkey_type(sign_key), fp);
1402 free(fp);
1403 }
1348 } 1404 }
1349 } 1405 }
1350 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, 1406 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
1351 alg, options.sk_provider, compat)) != 0) { 1407 alg, options.sk_provider, pin, compat)) != 0) {
1352 debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); 1408 debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1353 goto out; 1409 goto out;
1354 } 1410 }
@@ -1363,6 +1419,9 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1363 /* success */ 1419 /* success */
1364 r = 0; 1420 r = 0;
1365 out: 1421 out:
1422 free(prompt);
1423 if (pin != NULL)
1424 freezero(pin, strlen(pin));
1366 notify_complete(notifier); 1425 notify_complete(notifier);
1367 sshkey_free(prv); 1426 sshkey_free(prv);
1368 return r; 1427 return r;
@@ -1802,10 +1861,7 @@ pubkey_prepare(Authctxt *authctxt)
1802 } 1861 }
1803 ssh_free_identitylist(idlist); 1862 ssh_free_identitylist(idlist);
1804 /* append remaining agent keys */ 1863 /* append remaining agent keys */
1805 for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { 1864 TAILQ_CONCAT(preferred, &agent, next);
1806 TAILQ_REMOVE(&agent, id, next);
1807 TAILQ_INSERT_TAIL(preferred, id, next);
1808 }
1809 authctxt->agent_fd = agent_fd; 1865 authctxt->agent_fd = agent_fd;
1810 } 1866 }
1811 /* Prefer PKCS11 keys that are explicitly listed */ 1867 /* Prefer PKCS11 keys that are explicitly listed */
@@ -1831,10 +1887,7 @@ pubkey_prepare(Authctxt *authctxt)
1831 } 1887 }
1832 } 1888 }
1833 /* append remaining keys from the config file */ 1889 /* append remaining keys from the config file */
1834 for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { 1890 TAILQ_CONCAT(preferred, &files, next);
1835 TAILQ_REMOVE(&files, id, next);
1836 TAILQ_INSERT_TAIL(preferred, id, next);
1837 }
1838 /* finally, filter by PubkeyAcceptedKeyTypes */ 1891 /* finally, filter by PubkeyAcceptedKeyTypes */
1839 TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1892 TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
1840 if (id->key != NULL && !key_type_allowed_by_config(id->key)) { 1893 if (id->key != NULL && !key_type_allowed_by_config(id->key)) {