diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 265 |
1 files changed, 186 insertions, 79 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 32e9b0df2..b452eae24 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.226 2015/07/30 00:01:34 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.239 2016/02/23 01:34:14 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. |
@@ -157,6 +157,7 @@ void | |||
157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | 157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) |
158 | { | 158 | { |
159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
160 | char *s; | ||
160 | struct kex *kex; | 161 | struct kex *kex; |
161 | int r; | 162 | int r; |
162 | 163 | ||
@@ -168,8 +169,9 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
168 | xxx_host = host; | 169 | xxx_host = host; |
169 | xxx_hostaddr = hostaddr; | 170 | xxx_hostaddr = hostaddr; |
170 | 171 | ||
171 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( | 172 | if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) |
172 | options.kex_algorithms); | 173 | fatal("%s: kex_names_cat", __func__); |
174 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); | ||
173 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | 175 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
174 | compat_cipher_proposal(options.ciphers); | 176 | compat_cipher_proposal(options.ciphers); |
175 | myproposal[PROPOSAL_ENC_ALGS_STOC] = | 177 | myproposal[PROPOSAL_ENC_ALGS_STOC] = |
@@ -269,10 +271,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
269 | 271 | ||
270 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 272 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
271 | 273 | ||
272 | if (options.use_roaming && !kex->roaming) { | 274 | /* remove ext-info from the KEX proposals for rekeying */ |
273 | debug("Roaming not allowed by server"); | 275 | myproposal[PROPOSAL_KEX_ALGS] = |
274 | options.use_roaming = 0; | 276 | compat_kex_proposal(options.kex_algorithms); |
275 | } | 277 | if ((r = kex_prop2buf(kex->my, myproposal)) != 0) |
278 | fatal("kex_prop2buf: %s", ssh_err(r)); | ||
276 | 279 | ||
277 | session_id2 = kex->session_id; | 280 | session_id2 = kex->session_id; |
278 | session_id2_len = kex->session_id_len; | 281 | session_id2_len = kex->session_id_len; |
@@ -336,6 +339,8 @@ struct cauthmethod { | |||
336 | int *batch_flag; /* flag in option struct that disables method */ | 339 | int *batch_flag; /* flag in option struct that disables method */ |
337 | }; | 340 | }; |
338 | 341 | ||
342 | int input_userauth_service_accept(int, u_int32_t, void *); | ||
343 | int input_userauth_ext_info(int, u_int32_t, void *); | ||
339 | int input_userauth_success(int, u_int32_t, void *); | 344 | int input_userauth_success(int, u_int32_t, void *); |
340 | int input_userauth_success_unexpected(int, u_int32_t, void *); | 345 | int input_userauth_success_unexpected(int, u_int32_t, void *); |
341 | int input_userauth_failure(int, u_int32_t, void *); | 346 | int input_userauth_failure(int, u_int32_t, void *); |
@@ -366,7 +371,7 @@ void userauth(Authctxt *, char *); | |||
366 | static int sign_and_send_pubkey(Authctxt *, Identity *); | 371 | static int sign_and_send_pubkey(Authctxt *, Identity *); |
367 | static void pubkey_prepare(Authctxt *); | 372 | static void pubkey_prepare(Authctxt *); |
368 | static void pubkey_cleanup(Authctxt *); | 373 | static void pubkey_cleanup(Authctxt *); |
369 | static Key *load_identity_file(char *, int); | 374 | static Key *load_identity_file(Identity *); |
370 | 375 | ||
371 | static Authmethod *authmethod_get(char *authlist); | 376 | static Authmethod *authmethod_get(char *authlist); |
372 | static Authmethod *authmethod_lookup(const char *name); | 377 | static Authmethod *authmethod_lookup(const char *name); |
@@ -417,30 +422,12 @@ void | |||
417 | ssh_userauth2(const char *local_user, const char *server_user, char *host, | 422 | ssh_userauth2(const char *local_user, const char *server_user, char *host, |
418 | Sensitive *sensitive) | 423 | Sensitive *sensitive) |
419 | { | 424 | { |
425 | struct ssh *ssh = active_state; | ||
420 | Authctxt authctxt; | 426 | Authctxt authctxt; |
421 | int type; | 427 | int r; |
422 | 428 | ||
423 | if (options.challenge_response_authentication) | 429 | if (options.challenge_response_authentication) |
424 | options.kbd_interactive_authentication = 1; | 430 | options.kbd_interactive_authentication = 1; |
425 | |||
426 | packet_start(SSH2_MSG_SERVICE_REQUEST); | ||
427 | packet_put_cstring("ssh-userauth"); | ||
428 | packet_send(); | ||
429 | debug("SSH2_MSG_SERVICE_REQUEST sent"); | ||
430 | packet_write_wait(); | ||
431 | type = packet_read(); | ||
432 | if (type != SSH2_MSG_SERVICE_ACCEPT) | ||
433 | fatal("Server denied authentication request: %d", type); | ||
434 | if (packet_remaining() > 0) { | ||
435 | char *reply = packet_get_string(NULL); | ||
436 | debug2("service_accept: %s", reply); | ||
437 | free(reply); | ||
438 | } else { | ||
439 | debug2("buggy server: service_accept w/o service"); | ||
440 | } | ||
441 | packet_check_eom(); | ||
442 | debug("SSH2_MSG_SERVICE_ACCEPT received"); | ||
443 | |||
444 | if (options.preferred_authentications == NULL) | 431 | if (options.preferred_authentications == NULL) |
445 | options.preferred_authentications = authmethods_get(); | 432 | options.preferred_authentications = authmethods_get(); |
446 | 433 | ||
@@ -462,21 +449,63 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
462 | if (authctxt.method == NULL) | 449 | if (authctxt.method == NULL) |
463 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); | 450 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
464 | 451 | ||
465 | /* initial userauth request */ | 452 | if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 || |
466 | userauth_none(&authctxt); | 453 | (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 || |
454 | (r = sshpkt_send(ssh)) != 0) | ||
455 | fatal("%s: %s", __func__, ssh_err(r)); | ||
467 | 456 | ||
468 | dispatch_init(&input_userauth_error); | 457 | ssh_dispatch_init(ssh, &input_userauth_error); |
469 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | 458 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); |
470 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | 459 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); |
471 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | 460 | ssh_dispatch_run(ssh, DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ |
472 | dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ | ||
473 | 461 | ||
474 | pubkey_cleanup(&authctxt); | 462 | pubkey_cleanup(&authctxt); |
475 | dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); | 463 | ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); |
476 | 464 | ||
477 | debug("Authentication succeeded (%s).", authctxt.method->name); | 465 | debug("Authentication succeeded (%s).", authctxt.method->name); |
478 | } | 466 | } |
479 | 467 | ||
468 | /* ARGSUSED */ | ||
469 | int | ||
470 | input_userauth_service_accept(int type, u_int32_t seqnr, void *ctxt) | ||
471 | { | ||
472 | Authctxt *authctxt = ctxt; | ||
473 | struct ssh *ssh = active_state; | ||
474 | int r; | ||
475 | |||
476 | if (ssh_packet_remaining(ssh) > 0) { | ||
477 | char *reply; | ||
478 | |||
479 | if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0) | ||
480 | goto out; | ||
481 | debug2("service_accept: %s", reply); | ||
482 | free(reply); | ||
483 | } else { | ||
484 | debug2("buggy server: service_accept w/o service"); | ||
485 | } | ||
486 | if ((r = sshpkt_get_end(ssh)) != 0) | ||
487 | goto out; | ||
488 | debug("SSH2_MSG_SERVICE_ACCEPT received"); | ||
489 | |||
490 | /* initial userauth request */ | ||
491 | userauth_none(authctxt); | ||
492 | |||
493 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error); | ||
494 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | ||
495 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | ||
496 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | ||
497 | r = 0; | ||
498 | out: | ||
499 | return r; | ||
500 | } | ||
501 | |||
502 | /* ARGSUSED */ | ||
503 | int | ||
504 | input_userauth_ext_info(int type, u_int32_t seqnr, void *ctxt) | ||
505 | { | ||
506 | return kex_input_ext_info(type, seqnr, active_state); | ||
507 | } | ||
508 | |||
480 | void | 509 | void |
481 | userauth(Authctxt *authctxt, char *authlist) | 510 | userauth(Authctxt *authctxt, char *authlist) |
482 | { | 511 | { |
@@ -1082,29 +1111,48 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
1082 | return 0; | 1111 | return 0; |
1083 | } | 1112 | } |
1084 | 1113 | ||
1114 | static const char * | ||
1115 | identity_sign_encode(struct identity *id) | ||
1116 | { | ||
1117 | struct ssh *ssh = active_state; | ||
1118 | |||
1119 | if (id->key->type == KEY_RSA) { | ||
1120 | switch (ssh->kex->rsa_sha2) { | ||
1121 | case 256: | ||
1122 | return "rsa-sha2-256"; | ||
1123 | case 512: | ||
1124 | return "rsa-sha2-512"; | ||
1125 | } | ||
1126 | } | ||
1127 | return key_ssh_name(id->key); | ||
1128 | } | ||
1129 | |||
1085 | static int | 1130 | static int |
1086 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | 1131 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
1087 | const u_char *data, size_t datalen, u_int compat) | 1132 | const u_char *data, size_t datalen, u_int compat) |
1088 | { | 1133 | { |
1089 | Key *prv; | 1134 | Key *prv; |
1090 | int ret; | 1135 | int ret; |
1136 | const char *alg; | ||
1137 | |||
1138 | alg = identity_sign_encode(id); | ||
1091 | 1139 | ||
1092 | /* the agent supports this key */ | 1140 | /* the agent supports this key */ |
1093 | if (id->agent_fd) | 1141 | if (id->agent_fd != -1) |
1094 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, | 1142 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, |
1095 | data, datalen, compat); | 1143 | data, datalen, alg, compat); |
1096 | 1144 | ||
1097 | /* | 1145 | /* |
1098 | * we have already loaded the private key or | 1146 | * we have already loaded the private key or |
1099 | * the private key is stored in external hardware | 1147 | * the private key is stored in external hardware |
1100 | */ | 1148 | */ |
1101 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) | 1149 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) |
1102 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, | 1150 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, |
1103 | compat)); | 1151 | compat)); |
1104 | /* load the private key from the file */ | 1152 | /* load the private key from the file */ |
1105 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) | 1153 | if ((prv = load_identity_file(id)) == NULL) |
1106 | return (-1); /* XXX return decent error code */ | 1154 | return SSH_ERR_KEY_NOT_FOUND; |
1107 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); | 1155 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); |
1108 | sshkey_free(prv); | 1156 | sshkey_free(prv); |
1109 | return (ret); | 1157 | return (ret); |
1110 | } | 1158 | } |
@@ -1113,18 +1161,17 @@ static int | |||
1113 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | 1161 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) |
1114 | { | 1162 | { |
1115 | Buffer b; | 1163 | Buffer b; |
1164 | Identity *private_id; | ||
1116 | u_char *blob, *signature; | 1165 | u_char *blob, *signature; |
1117 | u_int bloblen; | ||
1118 | size_t slen; | 1166 | size_t slen; |
1119 | u_int skip = 0; | 1167 | u_int bloblen, skip = 0; |
1120 | int ret = -1; | 1168 | int matched, ret = -1, have_sig = 1; |
1121 | int have_sig = 1; | ||
1122 | char *fp; | 1169 | char *fp; |
1123 | 1170 | ||
1124 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, | 1171 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
1125 | SSH_FP_DEFAULT)) == NULL) | 1172 | SSH_FP_DEFAULT)) == NULL) |
1126 | return 0; | 1173 | return 0; |
1127 | debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); | 1174 | debug3("%s: %s %s", __func__, key_type(id->key), fp); |
1128 | free(fp); | 1175 | free(fp); |
1129 | 1176 | ||
1130 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { | 1177 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { |
@@ -1152,14 +1199,46 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1152 | } else { | 1199 | } else { |
1153 | buffer_put_cstring(&b, authctxt->method->name); | 1200 | buffer_put_cstring(&b, authctxt->method->name); |
1154 | buffer_put_char(&b, have_sig); | 1201 | buffer_put_char(&b, have_sig); |
1155 | buffer_put_cstring(&b, key_ssh_name(id->key)); | 1202 | buffer_put_cstring(&b, identity_sign_encode(id)); |
1156 | } | 1203 | } |
1157 | buffer_put_string(&b, blob, bloblen); | 1204 | buffer_put_string(&b, blob, bloblen); |
1158 | 1205 | ||
1206 | /* | ||
1207 | * If the key is an certificate, try to find a matching private key | ||
1208 | * and use it to complete the signature. | ||
1209 | * If no such private key exists, return failure and continue with | ||
1210 | * other methods of authentication. | ||
1211 | */ | ||
1212 | if (key_is_cert(id->key)) { | ||
1213 | matched = 0; | ||
1214 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { | ||
1215 | if (sshkey_equal_public(id->key, private_id->key) && | ||
1216 | id->key->type != private_id->key->type) { | ||
1217 | id = private_id; | ||
1218 | matched = 1; | ||
1219 | break; | ||
1220 | } | ||
1221 | } | ||
1222 | if (matched) { | ||
1223 | debug2("%s: using private key \"%s\"%s for " | ||
1224 | "certificate", __func__, id->filename, | ||
1225 | id->agent_fd != -1 ? " from agent" : ""); | ||
1226 | } else { | ||
1227 | /* XXX maybe verbose/error? */ | ||
1228 | debug("%s: no private key for certificate " | ||
1229 | "\"%s\"", __func__, id->filename); | ||
1230 | free(blob); | ||
1231 | buffer_free(&b); | ||
1232 | return 0; | ||
1233 | } | ||
1234 | } | ||
1235 | |||
1159 | /* generate signature */ | 1236 | /* generate signature */ |
1160 | ret = identity_sign(id, &signature, &slen, | 1237 | ret = identity_sign(id, &signature, &slen, |
1161 | buffer_ptr(&b), buffer_len(&b), datafellows); | 1238 | buffer_ptr(&b), buffer_len(&b), datafellows); |
1162 | if (ret != 0) { | 1239 | if (ret != 0) { |
1240 | if (ret != SSH_ERR_KEY_NOT_FOUND) | ||
1241 | error("%s: signing failed: %s", __func__, ssh_err(ret)); | ||
1163 | free(blob); | 1242 | free(blob); |
1164 | buffer_free(&b); | 1243 | buffer_free(&b); |
1165 | return 0; | 1244 | return 0; |
@@ -1222,7 +1301,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) | |||
1222 | packet_put_cstring(authctxt->method->name); | 1301 | packet_put_cstring(authctxt->method->name); |
1223 | packet_put_char(have_sig); | 1302 | packet_put_char(have_sig); |
1224 | if (!(datafellows & SSH_BUG_PKAUTH)) | 1303 | if (!(datafellows & SSH_BUG_PKAUTH)) |
1225 | packet_put_cstring(key_ssh_name(id->key)); | 1304 | packet_put_cstring(identity_sign_encode(id)); |
1226 | packet_put_string(blob, bloblen); | 1305 | packet_put_string(blob, bloblen); |
1227 | free(blob); | 1306 | free(blob); |
1228 | packet_send(); | 1307 | packet_send(); |
@@ -1230,20 +1309,20 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) | |||
1230 | } | 1309 | } |
1231 | 1310 | ||
1232 | static Key * | 1311 | static Key * |
1233 | load_identity_file(char *filename, int userprovided) | 1312 | load_identity_file(Identity *id) |
1234 | { | 1313 | { |
1235 | Key *private; | 1314 | Key *private = NULL; |
1236 | char prompt[300], *passphrase; | 1315 | char prompt[300], *passphrase, *comment; |
1237 | int r, perm_ok = 0, quit = 0, i; | 1316 | int r, perm_ok = 0, quit = 0, i; |
1238 | struct stat st; | 1317 | struct stat st; |
1239 | 1318 | ||
1240 | if (stat(filename, &st) < 0) { | 1319 | if (stat(id->filename, &st) < 0) { |
1241 | (userprovided ? logit : debug3)("no such identity: %s: %s", | 1320 | (id->userprovided ? logit : debug3)("no such identity: %s: %s", |
1242 | filename, strerror(errno)); | 1321 | id->filename, strerror(errno)); |
1243 | return NULL; | 1322 | return NULL; |
1244 | } | 1323 | } |
1245 | snprintf(prompt, sizeof prompt, | 1324 | snprintf(prompt, sizeof prompt, |
1246 | "Enter passphrase for key '%.100s': ", filename); | 1325 | "Enter passphrase for key '%.100s': ", id->filename); |
1247 | for (i = 0; i <= options.number_of_password_prompts; i++) { | 1326 | for (i = 0; i <= options.number_of_password_prompts; i++) { |
1248 | if (i == 0) | 1327 | if (i == 0) |
1249 | passphrase = ""; | 1328 | passphrase = ""; |
@@ -1255,8 +1334,8 @@ load_identity_file(char *filename, int userprovided) | |||
1255 | break; | 1334 | break; |
1256 | } | 1335 | } |
1257 | } | 1336 | } |
1258 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, | 1337 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename, |
1259 | passphrase, &private, NULL, &perm_ok))) { | 1338 | passphrase, &private, &comment, &perm_ok))) { |
1260 | case 0: | 1339 | case 0: |
1261 | break; | 1340 | break; |
1262 | case SSH_ERR_KEY_WRONG_PASSPHRASE: | 1341 | case SSH_ERR_KEY_WRONG_PASSPHRASE: |
@@ -1270,20 +1349,25 @@ load_identity_file(char *filename, int userprovided) | |||
1270 | case SSH_ERR_SYSTEM_ERROR: | 1349 | case SSH_ERR_SYSTEM_ERROR: |
1271 | if (errno == ENOENT) { | 1350 | if (errno == ENOENT) { |
1272 | debug2("Load key \"%s\": %s", | 1351 | debug2("Load key \"%s\": %s", |
1273 | filename, ssh_err(r)); | 1352 | id->filename, ssh_err(r)); |
1274 | quit = 1; | 1353 | quit = 1; |
1275 | break; | 1354 | break; |
1276 | } | 1355 | } |
1277 | /* FALLTHROUGH */ | 1356 | /* FALLTHROUGH */ |
1278 | default: | 1357 | default: |
1279 | error("Load key \"%s\": %s", filename, ssh_err(r)); | 1358 | error("Load key \"%s\": %s", id->filename, ssh_err(r)); |
1280 | quit = 1; | 1359 | quit = 1; |
1281 | break; | 1360 | break; |
1282 | } | 1361 | } |
1362 | if (!quit && private != NULL && id->agent_fd == -1 && | ||
1363 | !(id->key && id->isprivate)) | ||
1364 | maybe_add_key_to_agent(id->filename, private, comment, | ||
1365 | passphrase); | ||
1283 | if (i > 0) { | 1366 | if (i > 0) { |
1284 | explicit_bzero(passphrase, strlen(passphrase)); | 1367 | explicit_bzero(passphrase, strlen(passphrase)); |
1285 | free(passphrase); | 1368 | free(passphrase); |
1286 | } | 1369 | } |
1370 | free(comment); | ||
1287 | if (private != NULL || quit) | 1371 | if (private != NULL || quit) |
1288 | break; | 1372 | break; |
1289 | } | 1373 | } |
@@ -1292,9 +1376,11 @@ load_identity_file(char *filename, int userprovided) | |||
1292 | 1376 | ||
1293 | /* | 1377 | /* |
1294 | * try keys in the following order: | 1378 | * try keys in the following order: |
1295 | * 1. agent keys that are found in the config file | 1379 | * 1. certificates listed in the config file |
1296 | * 2. other agent keys | 1380 | * 2. other input certificates |
1297 | * 3. keys that are only listed in the config file | 1381 | * 3. agent keys that are found in the config file |
1382 | * 4. other agent keys | ||
1383 | * 5. keys that are only listed in the config file | ||
1298 | */ | 1384 | */ |
1299 | static void | 1385 | static void |
1300 | pubkey_prepare(Authctxt *authctxt) | 1386 | pubkey_prepare(Authctxt *authctxt) |
@@ -1302,7 +1388,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1302 | struct identity *id, *id2, *tmp; | 1388 | struct identity *id, *id2, *tmp; |
1303 | struct idlist agent, files, *preferred; | 1389 | struct idlist agent, files, *preferred; |
1304 | struct sshkey *key; | 1390 | struct sshkey *key; |
1305 | int agent_fd, i, r, found; | 1391 | int agent_fd = -1, i, r, found; |
1306 | size_t j; | 1392 | size_t j; |
1307 | struct ssh_identitylist *idlist; | 1393 | struct ssh_identitylist *idlist; |
1308 | 1394 | ||
@@ -1320,6 +1406,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1320 | continue; | 1406 | continue; |
1321 | options.identity_keys[i] = NULL; | 1407 | options.identity_keys[i] = NULL; |
1322 | id = xcalloc(1, sizeof(*id)); | 1408 | id = xcalloc(1, sizeof(*id)); |
1409 | id->agent_fd = -1; | ||
1323 | id->key = key; | 1410 | id->key = key; |
1324 | id->filename = xstrdup(options.identity_files[i]); | 1411 | id->filename = xstrdup(options.identity_files[i]); |
1325 | id->userprovided = options.identity_file_userprovided[i]; | 1412 | id->userprovided = options.identity_file_userprovided[i]; |
@@ -1348,6 +1435,19 @@ pubkey_prepare(Authctxt *authctxt) | |||
1348 | free(id); | 1435 | free(id); |
1349 | } | 1436 | } |
1350 | } | 1437 | } |
1438 | /* list of certificates specified by user */ | ||
1439 | for (i = 0; i < options.num_certificate_files; i++) { | ||
1440 | key = options.certificates[i]; | ||
1441 | if (!key_is_cert(key) || key->cert == NULL || | ||
1442 | key->cert->type != SSH2_CERT_TYPE_USER) | ||
1443 | continue; | ||
1444 | id = xcalloc(1, sizeof(*id)); | ||
1445 | id->agent_fd = -1; | ||
1446 | id->key = key; | ||
1447 | id->filename = xstrdup(options.certificate_files[i]); | ||
1448 | id->userprovided = options.certificate_file_userprovided[i]; | ||
1449 | TAILQ_INSERT_TAIL(preferred, id, next); | ||
1450 | } | ||
1351 | /* list of keys supported by the agent */ | 1451 | /* list of keys supported by the agent */ |
1352 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { | 1452 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
1353 | if (r != SSH_ERR_AGENT_NOT_PRESENT) | 1453 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
@@ -1357,6 +1457,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1357 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) | 1457 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) |
1358 | debug("%s: ssh_fetch_identitylist: %s", | 1458 | debug("%s: ssh_fetch_identitylist: %s", |
1359 | __func__, ssh_err(r)); | 1459 | __func__, ssh_err(r)); |
1460 | close(agent_fd); | ||
1360 | } else { | 1461 | } else { |
1361 | for (j = 0; j < idlist->nkeys; j++) { | 1462 | for (j = 0; j < idlist->nkeys; j++) { |
1362 | found = 0; | 1463 | found = 0; |
@@ -1397,9 +1498,23 @@ pubkey_prepare(Authctxt *authctxt) | |||
1397 | TAILQ_REMOVE(&files, id, next); | 1498 | TAILQ_REMOVE(&files, id, next); |
1398 | TAILQ_INSERT_TAIL(preferred, id, next); | 1499 | TAILQ_INSERT_TAIL(preferred, id, next); |
1399 | } | 1500 | } |
1400 | TAILQ_FOREACH(id, preferred, next) { | 1501 | /* finally, filter by PubkeyAcceptedKeyTypes */ |
1401 | debug2("key: %s (%p),%s", id->filename, id->key, | 1502 | TAILQ_FOREACH_SAFE(id, preferred, next, id2) { |
1402 | id->userprovided ? " explicit" : ""); | 1503 | if (id->key != NULL && |
1504 | match_pattern_list(sshkey_ssh_name(id->key), | ||
1505 | options.pubkey_key_types, 0) != 1) { | ||
1506 | debug("Skipping %s key %s - " | ||
1507 | "not in PubkeyAcceptedKeyTypes", | ||
1508 | sshkey_ssh_name(id->key), id->filename); | ||
1509 | TAILQ_REMOVE(preferred, id, next); | ||
1510 | sshkey_free(id->key); | ||
1511 | free(id->filename); | ||
1512 | memset(id, 0, sizeof(*id)); | ||
1513 | continue; | ||
1514 | } | ||
1515 | debug2("key: %s (%p)%s%s", id->filename, id->key, | ||
1516 | id->userprovided ? ", explicit" : "", | ||
1517 | id->agent_fd != -1 ? ", agent" : ""); | ||
1403 | } | 1518 | } |
1404 | } | 1519 | } |
1405 | 1520 | ||
@@ -1413,8 +1528,7 @@ pubkey_cleanup(Authctxt *authctxt) | |||
1413 | for (id = TAILQ_FIRST(&authctxt->keys); id; | 1528 | for (id = TAILQ_FIRST(&authctxt->keys); id; |
1414 | id = TAILQ_FIRST(&authctxt->keys)) { | 1529 | id = TAILQ_FIRST(&authctxt->keys)) { |
1415 | TAILQ_REMOVE(&authctxt->keys, id, next); | 1530 | TAILQ_REMOVE(&authctxt->keys, id, next); |
1416 | if (id->key) | 1531 | sshkey_free(id->key); |
1417 | sshkey_free(id->key); | ||
1418 | free(id->filename); | 1532 | free(id->filename); |
1419 | free(id); | 1533 | free(id); |
1420 | } | 1534 | } |
@@ -1425,12 +1539,6 @@ try_identity(Identity *id) | |||
1425 | { | 1539 | { |
1426 | if (!id->key) | 1540 | if (!id->key) |
1427 | return (0); | 1541 | return (0); |
1428 | if (match_pattern_list(sshkey_ssh_name(id->key), | ||
1429 | options.pubkey_key_types, 0) != 1) { | ||
1430 | debug("Skipping %s key %s for not in PubkeyAcceptedKeyTypes", | ||
1431 | sshkey_ssh_name(id->key), id->filename); | ||
1432 | return (0); | ||
1433 | } | ||
1434 | if (key_type_plain(id->key->type) == KEY_RSA && | 1542 | if (key_type_plain(id->key->type) == KEY_RSA && |
1435 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | 1543 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { |
1436 | debug("Skipped %s key %s for RSA/MD5 server", | 1544 | debug("Skipped %s key %s for RSA/MD5 server", |
@@ -1465,8 +1573,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1465 | } | 1573 | } |
1466 | } else { | 1574 | } else { |
1467 | debug("Trying private key: %s", id->filename); | 1575 | debug("Trying private key: %s", id->filename); |
1468 | id->key = load_identity_file(id->filename, | 1576 | id->key = load_identity_file(id); |
1469 | id->userprovided); | ||
1470 | if (id->key != NULL) { | 1577 | if (id->key != NULL) { |
1471 | if (try_identity(id)) { | 1578 | if (try_identity(id)) { |
1472 | id->isprivate = 1; | 1579 | id->isprivate = 1; |
@@ -1625,7 +1732,7 @@ ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, | |||
1625 | closefrom(sock + 1); | 1732 | closefrom(sock + 1); |
1626 | debug3("%s: [child] pid=%ld, exec %s", | 1733 | debug3("%s: [child] pid=%ld, exec %s", |
1627 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); | 1734 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); |
1628 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); | 1735 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL); |
1629 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, | 1736 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, |
1630 | strerror(errno)); | 1737 | strerror(errno)); |
1631 | } | 1738 | } |
@@ -1797,7 +1904,7 @@ userauth_hostbased(Authctxt *authctxt) | |||
1797 | r = ssh_keysign(private, &sig, &siglen, | 1904 | r = ssh_keysign(private, &sig, &siglen, |
1798 | sshbuf_ptr(b), sshbuf_len(b)); | 1905 | sshbuf_ptr(b), sshbuf_len(b)); |
1799 | else if ((r = sshkey_sign(private, &sig, &siglen, | 1906 | else if ((r = sshkey_sign(private, &sig, &siglen, |
1800 | sshbuf_ptr(b), sshbuf_len(b), datafellows)) != 0) | 1907 | sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0) |
1801 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); | 1908 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
1802 | if (r != 0) { | 1909 | if (r != 0) { |
1803 | error("sign using hostkey %s %s failed", | 1910 | error("sign using hostkey %s %s failed", |