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 1a6545edf..f64aae66a 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.
@@ -102,12 +102,25 @@ verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
102 return 0; 102 return 0;
103} 103}
104 104
105/* Returns the first item from a comma-separated algorithm list */
106static char *
107first_alg(const char *algs)
108{
109 char *ret, *cp;
110
111 ret = xstrdup(algs);
112 if ((cp = strchr(ret, ',')) != NULL)
113 *cp = '\0';
114 return ret;
115}
116
105static char * 117static char *
106order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port) 118order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
107{ 119{
108 char *oavail, *avail, *first, *last, *alg, *hostname, *ret; 120 char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL;
121 char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL;
109 size_t maxlen; 122 size_t maxlen;
110 struct hostkeys *hostkeys; 123 struct hostkeys *hostkeys = NULL;
111 int ktype; 124 int ktype;
112 u_int i; 125 u_int i;
113 126
@@ -119,6 +132,26 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
119 for (i = 0; i < options.num_system_hostfiles; i++) 132 for (i = 0; i < options.num_system_hostfiles; i++)
120 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]); 133 load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]);
121 134
135 /*
136 * If a plain public key exists that matches the type of the best
137 * preference HostkeyAlgorithms, then use the whole list as is.
138 * Note that we ignore whether the best preference algorithm is a
139 * certificate type, as sshconnect.c will downgrade certs to
140 * plain keys if necessary.
141 */
142 best = first_alg(options.hostkeyalgorithms);
143 if (lookup_key_in_hostkeys_by_type(hostkeys,
144 sshkey_type_plain(sshkey_type_from_name(best)), NULL)) {
145 debug3("%s: have matching best-preference key type %s, "
146 "using HostkeyAlgorithms verbatim", __func__, best);
147 ret = xstrdup(options.hostkeyalgorithms);
148 goto out;
149 }
150
151 /*
152 * Otherwise, prefer the host key algorithms that match known keys
153 * while keeping the ordering of HostkeyAlgorithms as much as possible.
154 */
122 oavail = avail = xstrdup(options.hostkeyalgorithms); 155 oavail = avail = xstrdup(options.hostkeyalgorithms);
123 maxlen = strlen(avail) + 1; 156 maxlen = strlen(avail) + 1;
124 first = xmalloc(maxlen); 157 first = xmalloc(maxlen);
@@ -135,11 +168,23 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
135 while ((alg = strsep(&avail, ",")) && *alg != '\0') { 168 while ((alg = strsep(&avail, ",")) && *alg != '\0') {
136 if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 169 if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
137 fatal("%s: unknown alg %s", __func__, alg); 170 fatal("%s: unknown alg %s", __func__, alg);
171 /*
172 * If we have a @cert-authority marker in known_hosts then
173 * prefer all certificate algorithms.
174 */
175 if (sshkey_type_is_cert(ktype) &&
176 lookup_marker_in_hostkeys(hostkeys, MRK_CA)) {
177 ALG_APPEND(first, alg);
178 continue;
179 }
180 /* If the key appears in known_hosts then prefer it */
138 if (lookup_key_in_hostkeys_by_type(hostkeys, 181 if (lookup_key_in_hostkeys_by_type(hostkeys,
139 sshkey_type_plain(ktype), NULL)) 182 sshkey_type_plain(ktype), NULL)) {
140 ALG_APPEND(first, alg); 183 ALG_APPEND(first, alg);
141 else 184 continue;
142 ALG_APPEND(last, alg); 185 }
186 /* Otherwise, put it last */
187 ALG_APPEND(last, alg);
143 } 188 }
144#undef ALG_APPEND 189#undef ALG_APPEND
145 xasprintf(&ret, "%s%s%s", first, 190 xasprintf(&ret, "%s%s%s", first,
@@ -147,6 +192,8 @@ order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
147 if (*first != '\0') 192 if (*first != '\0')
148 debug3("%s: prefer hostkeyalgs: %s", __func__, first); 193 debug3("%s: prefer hostkeyalgs: %s", __func__, first);
149 194
195 out:
196 free(best);
150 free(first); 197 free(first);
151 free(last); 198 free(last);
152 free(hostname); 199 free(hostname);
@@ -1144,7 +1191,8 @@ key_sig_algorithm(struct ssh *ssh, const struct sshkey *key)
1144 while ((cp = strsep(&allowed, ",")) != NULL) { 1191 while ((cp = strsep(&allowed, ",")) != NULL) {
1145 if (sshkey_type_from_name(cp) != key->type) 1192 if (sshkey_type_from_name(cp) != key->type)
1146 continue; 1193 continue;
1147 tmp = match_list(sshkey_sigalg_by_name(cp), ssh->kex->server_sig_algs, NULL); 1194 tmp = match_list(sshkey_sigalg_by_name(cp),
1195 ssh->kex->server_sig_algs, NULL);
1148 if (tmp != NULL) 1196 if (tmp != NULL)
1149 alg = xstrdup(cp); 1197 alg = xstrdup(cp);
1150 free(tmp); 1198 free(tmp);
@@ -1162,7 +1210,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1162 struct sshkey *sign_key = NULL, *prv = NULL; 1210 struct sshkey *sign_key = NULL, *prv = NULL;
1163 int r = SSH_ERR_INTERNAL_ERROR; 1211 int r = SSH_ERR_INTERNAL_ERROR;
1164 struct notifier_ctx *notifier = NULL; 1212 struct notifier_ctx *notifier = NULL;
1165 char *fp = NULL; 1213 char *fp = NULL, *pin = NULL, *prompt = NULL;
1166 1214
1167 *sigp = NULL; 1215 *sigp = NULL;
1168 *lenp = 0; 1216 *lenp = 0;
@@ -1191,20 +1239,28 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1191 goto out; 1239 goto out;
1192 } 1240 }
1193 sign_key = prv; 1241 sign_key = prv;
1194 if (sshkey_is_sk(sign_key) && 1242 if (sshkey_is_sk(sign_key)) {
1195 (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 1243 if ((sign_key->sk_flags &
1196 /* XXX match batch mode should just skip these keys? */ 1244 SSH_SK_USER_VERIFICATION_REQD)) {
1197 if ((fp = sshkey_fingerprint(sign_key, 1245 xasprintf(&prompt, "Enter PIN for %s key %s: ",
1198 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 1246 sshkey_type(sign_key), id->filename);
1199 fatal("%s: sshkey_fingerprint", __func__); 1247 pin = read_passphrase(prompt, 0);
1200 notifier = notify_start(options.batch_mode, 1248 }
1201 "Confirm user presence for key %s %s", 1249 if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
1202 sshkey_type(sign_key), fp); 1250 /* XXX should batch mode just skip these? */
1203 free(fp); 1251 if ((fp = sshkey_fingerprint(sign_key,
1252 options.fingerprint_hash,
1253 SSH_FP_DEFAULT)) == NULL)
1254 fatal("%s: fingerprint", __func__);
1255 notifier = notify_start(options.batch_mode,
1256 "Confirm user presence for key %s %s",
1257 sshkey_type(sign_key), fp);
1258 free(fp);
1259 }
1204 } 1260 }
1205 } 1261 }
1206 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, 1262 if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
1207 alg, options.sk_provider, compat)) != 0) { 1263 alg, options.sk_provider, pin, compat)) != 0) {
1208 debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); 1264 debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
1209 goto out; 1265 goto out;
1210 } 1266 }
@@ -1219,6 +1275,9 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1219 /* success */ 1275 /* success */
1220 r = 0; 1276 r = 0;
1221 out: 1277 out:
1278 free(prompt);
1279 if (pin != NULL)
1280 freezero(pin, strlen(pin));
1222 notify_complete(notifier); 1281 notify_complete(notifier);
1223 sshkey_free(prv); 1282 sshkey_free(prv);
1224 return r; 1283 return r;
@@ -1658,10 +1717,7 @@ pubkey_prepare(Authctxt *authctxt)
1658 } 1717 }
1659 ssh_free_identitylist(idlist); 1718 ssh_free_identitylist(idlist);
1660 /* append remaining agent keys */ 1719 /* append remaining agent keys */
1661 for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { 1720 TAILQ_CONCAT(preferred, &agent, next);
1662 TAILQ_REMOVE(&agent, id, next);
1663 TAILQ_INSERT_TAIL(preferred, id, next);
1664 }
1665 authctxt->agent_fd = agent_fd; 1721 authctxt->agent_fd = agent_fd;
1666 } 1722 }
1667 /* Prefer PKCS11 keys that are explicitly listed */ 1723 /* Prefer PKCS11 keys that are explicitly listed */
@@ -1687,10 +1743,7 @@ pubkey_prepare(Authctxt *authctxt)
1687 } 1743 }
1688 } 1744 }
1689 /* append remaining keys from the config file */ 1745 /* append remaining keys from the config file */
1690 for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { 1746 TAILQ_CONCAT(preferred, &files, next);
1691 TAILQ_REMOVE(&files, id, next);
1692 TAILQ_INSERT_TAIL(preferred, id, next);
1693 }
1694 /* finally, filter by PubkeyAcceptedKeyTypes */ 1747 /* finally, filter by PubkeyAcceptedKeyTypes */
1695 TAILQ_FOREACH_SAFE(id, preferred, next, id2) { 1748 TAILQ_FOREACH_SAFE(id, preferred, next, id2) {
1696 if (id->key != NULL && !key_type_allowed_by_config(id->key)) { 1749 if (id->key != NULL && !key_type_allowed_by_config(id->key)) {