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 775103185..f79c96beb 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,14 +157,16 @@ 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 | ||
163 | xxx_host = host; | 164 | xxx_host = host; |
164 | xxx_hostaddr = hostaddr; | 165 | xxx_hostaddr = hostaddr; |
165 | 166 | ||
166 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( | 167 | if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) |
167 | options.kex_algorithms); | 168 | fatal("%s: kex_names_cat", __func__); |
169 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); | ||
168 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | 170 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
169 | compat_cipher_proposal(options.ciphers); | 171 | compat_cipher_proposal(options.ciphers); |
170 | myproposal[PROPOSAL_ENC_ALGS_STOC] = | 172 | myproposal[PROPOSAL_ENC_ALGS_STOC] = |
@@ -217,10 +219,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
217 | 219 | ||
218 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); | 220 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
219 | 221 | ||
220 | if (options.use_roaming && !kex->roaming) { | 222 | /* remove ext-info from the KEX proposals for rekeying */ |
221 | debug("Roaming not allowed by server"); | 223 | myproposal[PROPOSAL_KEX_ALGS] = |
222 | options.use_roaming = 0; | 224 | compat_kex_proposal(options.kex_algorithms); |
223 | } | 225 | if ((r = kex_prop2buf(kex->my, myproposal)) != 0) |
226 | fatal("kex_prop2buf: %s", ssh_err(r)); | ||
224 | 227 | ||
225 | session_id2 = kex->session_id; | 228 | session_id2 = kex->session_id; |
226 | session_id2_len = kex->session_id_len; | 229 | session_id2_len = kex->session_id_len; |
@@ -284,6 +287,8 @@ struct cauthmethod { | |||
284 | int *batch_flag; /* flag in option struct that disables method */ | 287 | int *batch_flag; /* flag in option struct that disables method */ |
285 | }; | 288 | }; |
286 | 289 | ||
290 | int input_userauth_service_accept(int, u_int32_t, void *); | ||
291 | int input_userauth_ext_info(int, u_int32_t, void *); | ||
287 | int input_userauth_success(int, u_int32_t, void *); | 292 | int input_userauth_success(int, u_int32_t, void *); |
288 | int input_userauth_success_unexpected(int, u_int32_t, void *); | 293 | int input_userauth_success_unexpected(int, u_int32_t, void *); |
289 | int input_userauth_failure(int, u_int32_t, void *); | 294 | int input_userauth_failure(int, u_int32_t, void *); |
@@ -313,7 +318,7 @@ void userauth(Authctxt *, char *); | |||
313 | static int sign_and_send_pubkey(Authctxt *, Identity *); | 318 | static int sign_and_send_pubkey(Authctxt *, Identity *); |
314 | static void pubkey_prepare(Authctxt *); | 319 | static void pubkey_prepare(Authctxt *); |
315 | static void pubkey_cleanup(Authctxt *); | 320 | static void pubkey_cleanup(Authctxt *); |
316 | static Key *load_identity_file(char *, int); | 321 | static Key *load_identity_file(Identity *); |
317 | 322 | ||
318 | static Authmethod *authmethod_get(char *authlist); | 323 | static Authmethod *authmethod_get(char *authlist); |
319 | static Authmethod *authmethod_lookup(const char *name); | 324 | static Authmethod *authmethod_lookup(const char *name); |
@@ -359,30 +364,12 @@ void | |||
359 | ssh_userauth2(const char *local_user, const char *server_user, char *host, | 364 | ssh_userauth2(const char *local_user, const char *server_user, char *host, |
360 | Sensitive *sensitive) | 365 | Sensitive *sensitive) |
361 | { | 366 | { |
367 | struct ssh *ssh = active_state; | ||
362 | Authctxt authctxt; | 368 | Authctxt authctxt; |
363 | int type; | 369 | int r; |
364 | 370 | ||
365 | if (options.challenge_response_authentication) | 371 | if (options.challenge_response_authentication) |
366 | options.kbd_interactive_authentication = 1; | 372 | options.kbd_interactive_authentication = 1; |
367 | |||
368 | packet_start(SSH2_MSG_SERVICE_REQUEST); | ||
369 | packet_put_cstring("ssh-userauth"); | ||
370 | packet_send(); | ||
371 | debug("SSH2_MSG_SERVICE_REQUEST sent"); | ||
372 | packet_write_wait(); | ||
373 | type = packet_read(); | ||
374 | if (type != SSH2_MSG_SERVICE_ACCEPT) | ||
375 | fatal("Server denied authentication request: %d", type); | ||
376 | if (packet_remaining() > 0) { | ||
377 | char *reply = packet_get_string(NULL); | ||
378 | debug2("service_accept: %s", reply); | ||
379 | free(reply); | ||
380 | } else { | ||
381 | debug2("buggy server: service_accept w/o service"); | ||
382 | } | ||
383 | packet_check_eom(); | ||
384 | debug("SSH2_MSG_SERVICE_ACCEPT received"); | ||
385 | |||
386 | if (options.preferred_authentications == NULL) | 373 | if (options.preferred_authentications == NULL) |
387 | options.preferred_authentications = authmethods_get(); | 374 | options.preferred_authentications = authmethods_get(); |
388 | 375 | ||
@@ -404,21 +391,63 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
404 | if (authctxt.method == NULL) | 391 | if (authctxt.method == NULL) |
405 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); | 392 | fatal("ssh_userauth2: internal error: cannot send userauth none request"); |
406 | 393 | ||
407 | /* initial userauth request */ | 394 | if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_REQUEST)) != 0 || |
408 | userauth_none(&authctxt); | 395 | (r = sshpkt_put_cstring(ssh, "ssh-userauth")) != 0 || |
396 | (r = sshpkt_send(ssh)) != 0) | ||
397 | fatal("%s: %s", __func__, ssh_err(r)); | ||
409 | 398 | ||
410 | dispatch_init(&input_userauth_error); | 399 | ssh_dispatch_init(ssh, &input_userauth_error); |
411 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | 400 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); |
412 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | 401 | ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); |
413 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | 402 | ssh_dispatch_run(ssh, DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ |
414 | dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ | ||
415 | 403 | ||
416 | pubkey_cleanup(&authctxt); | 404 | pubkey_cleanup(&authctxt); |
417 | dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); | 405 | ssh_dispatch_range(ssh, SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); |
418 | 406 | ||
419 | debug("Authentication succeeded (%s).", authctxt.method->name); | 407 | debug("Authentication succeeded (%s).", authctxt.method->name); |
420 | } | 408 | } |
421 | 409 | ||
410 | /* ARGSUSED */ | ||
411 | int | ||
412 | input_userauth_service_accept(int type, u_int32_t seqnr, void *ctxt) | ||
413 | { | ||
414 | Authctxt *authctxt = ctxt; | ||
415 | struct ssh *ssh = active_state; | ||
416 | int r; | ||
417 | |||
418 | if (ssh_packet_remaining(ssh) > 0) { | ||
419 | char *reply; | ||
420 | |||
421 | if ((r = sshpkt_get_cstring(ssh, &reply, NULL)) != 0) | ||
422 | goto out; | ||
423 | debug2("service_accept: %s", reply); | ||
424 | free(reply); | ||
425 | } else { | ||
426 | debug2("buggy server: service_accept w/o service"); | ||
427 | } | ||
428 | if ((r = sshpkt_get_end(ssh)) != 0) | ||
429 | goto out; | ||
430 | debug("SSH2_MSG_SERVICE_ACCEPT received"); | ||
431 | |||
432 | /* initial userauth request */ | ||
433 | userauth_none(authctxt); | ||
434 | |||
435 | ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_error); | ||
436 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | ||
437 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | ||
438 | ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | ||
439 | r = 0; | ||
440 | out: | ||
441 | return r; | ||
442 | } | ||
443 | |||
444 | /* ARGSUSED */ | ||
445 | int | ||
446 | input_userauth_ext_info(int type, u_int32_t seqnr, void *ctxt) | ||
447 | { | ||
448 | return kex_input_ext_info(type, seqnr, active_state); | ||
449 | } | ||
450 | |||
422 | void | 451 | void |
423 | userauth(Authctxt *authctxt, char *authlist) | 452 | userauth(Authctxt *authctxt, char *authlist) |
424 | { | 453 | { |
@@ -970,29 +999,48 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) | |||
970 | return 0; | 999 | return 0; |
971 | } | 1000 | } |
972 | 1001 | ||
1002 | static const char * | ||
1003 | identity_sign_encode(struct identity *id) | ||
1004 | { | ||
1005 | struct ssh *ssh = active_state; | ||
1006 | |||
1007 | if (id->key->type == KEY_RSA) { | ||
1008 | switch (ssh->kex->rsa_sha2) { | ||
1009 | case 256: | ||
1010 | return "rsa-sha2-256"; | ||
1011 | case 512: | ||
1012 | return "rsa-sha2-512"; | ||
1013 | } | ||
1014 | } | ||
1015 | return key_ssh_name(id->key); | ||
1016 | } | ||
1017 | |||
973 | static int | 1018 | static int |
974 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | 1019 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
975 | const u_char *data, size_t datalen, u_int compat) | 1020 | const u_char *data, size_t datalen, u_int compat) |
976 | { | 1021 | { |
977 | Key *prv; | 1022 | Key *prv; |
978 | int ret; | 1023 | int ret; |
1024 | const char *alg; | ||
1025 | |||
1026 | alg = identity_sign_encode(id); | ||
979 | 1027 | ||
980 | /* the agent supports this key */ | 1028 | /* the agent supports this key */ |
981 | if (id->agent_fd) | 1029 | if (id->agent_fd != -1) |
982 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, | 1030 | return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, |
983 | data, datalen, compat); | 1031 | data, datalen, alg, compat); |
984 | 1032 | ||
985 | /* | 1033 | /* |
986 | * we have already loaded the private key or | 1034 | * we have already loaded the private key or |
987 | * the private key is stored in external hardware | 1035 | * the private key is stored in external hardware |
988 | */ | 1036 | */ |
989 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) | 1037 | if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) |
990 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, | 1038 | return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, |
991 | compat)); | 1039 | compat)); |
992 | /* load the private key from the file */ | 1040 | /* load the private key from the file */ |
993 | if ((prv = load_identity_file(id->filename, id->userprovided)) == NULL) | 1041 | if ((prv = load_identity_file(id)) == NULL) |
994 | return (-1); /* XXX return decent error code */ | 1042 | return SSH_ERR_KEY_NOT_FOUND; |
995 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, compat); | 1043 | ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); |
996 | sshkey_free(prv); | 1044 | sshkey_free(prv); |
997 | return (ret); | 1045 | return (ret); |
998 | } | 1046 | } |
@@ -1001,18 +1049,17 @@ static int | |||
1001 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | 1049 | sign_and_send_pubkey(Authctxt *authctxt, Identity *id) |
1002 | { | 1050 | { |
1003 | Buffer b; | 1051 | Buffer b; |
1052 | Identity *private_id; | ||
1004 | u_char *blob, *signature; | 1053 | u_char *blob, *signature; |
1005 | u_int bloblen; | ||
1006 | size_t slen; | 1054 | size_t slen; |
1007 | u_int skip = 0; | 1055 | u_int bloblen, skip = 0; |
1008 | int ret = -1; | 1056 | int matched, ret = -1, have_sig = 1; |
1009 | int have_sig = 1; | ||
1010 | char *fp; | 1057 | char *fp; |
1011 | 1058 | ||
1012 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, | 1059 | if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
1013 | SSH_FP_DEFAULT)) == NULL) | 1060 | SSH_FP_DEFAULT)) == NULL) |
1014 | return 0; | 1061 | return 0; |
1015 | debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); | 1062 | debug3("%s: %s %s", __func__, key_type(id->key), fp); |
1016 | free(fp); | 1063 | free(fp); |
1017 | 1064 | ||
1018 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { | 1065 | if (key_to_blob(id->key, &blob, &bloblen) == 0) { |
@@ -1040,14 +1087,46 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) | |||
1040 | } else { | 1087 | } else { |
1041 | buffer_put_cstring(&b, authctxt->method->name); | 1088 | buffer_put_cstring(&b, authctxt->method->name); |
1042 | buffer_put_char(&b, have_sig); | 1089 | buffer_put_char(&b, have_sig); |
1043 | buffer_put_cstring(&b, key_ssh_name(id->key)); | 1090 | buffer_put_cstring(&b, identity_sign_encode(id)); |
1044 | } | 1091 | } |
1045 | buffer_put_string(&b, blob, bloblen); | 1092 | buffer_put_string(&b, blob, bloblen); |
1046 | 1093 | ||
1094 | /* | ||
1095 | * If the key is an certificate, try to find a matching private key | ||
1096 | * and use it to complete the signature. | ||
1097 | * If no such private key exists, return failure and continue with | ||
1098 | * other methods of authentication. | ||
1099 | */ | ||
1100 | if (key_is_cert(id->key)) { | ||
1101 | matched = 0; | ||
1102 | TAILQ_FOREACH(private_id, &authctxt->keys, next) { | ||
1103 | if (sshkey_equal_public(id->key, private_id->key) && | ||
1104 | id->key->type != private_id->key->type) { | ||
1105 | id = private_id; | ||
1106 | matched = 1; | ||
1107 | break; | ||
1108 | } | ||
1109 | } | ||
1110 | if (matched) { | ||
1111 | debug2("%s: using private key \"%s\"%s for " | ||
1112 | "certificate", __func__, id->filename, | ||
1113 | id->agent_fd != -1 ? " from agent" : ""); | ||
1114 | } else { | ||
1115 | /* XXX maybe verbose/error? */ | ||
1116 | debug("%s: no private key for certificate " | ||
1117 | "\"%s\"", __func__, id->filename); | ||
1118 | free(blob); | ||
1119 | buffer_free(&b); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1047 | /* generate signature */ | 1124 | /* generate signature */ |
1048 | ret = identity_sign(id, &signature, &slen, | 1125 | ret = identity_sign(id, &signature, &slen, |
1049 | buffer_ptr(&b), buffer_len(&b), datafellows); | 1126 | buffer_ptr(&b), buffer_len(&b), datafellows); |
1050 | if (ret != 0) { | 1127 | if (ret != 0) { |
1128 | if (ret != SSH_ERR_KEY_NOT_FOUND) | ||
1129 | error("%s: signing failed: %s", __func__, ssh_err(ret)); | ||
1051 | free(blob); | 1130 | free(blob); |
1052 | buffer_free(&b); | 1131 | buffer_free(&b); |
1053 | return 0; | 1132 | return 0; |
@@ -1110,7 +1189,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) | |||
1110 | packet_put_cstring(authctxt->method->name); | 1189 | packet_put_cstring(authctxt->method->name); |
1111 | packet_put_char(have_sig); | 1190 | packet_put_char(have_sig); |
1112 | if (!(datafellows & SSH_BUG_PKAUTH)) | 1191 | if (!(datafellows & SSH_BUG_PKAUTH)) |
1113 | packet_put_cstring(key_ssh_name(id->key)); | 1192 | packet_put_cstring(identity_sign_encode(id)); |
1114 | packet_put_string(blob, bloblen); | 1193 | packet_put_string(blob, bloblen); |
1115 | free(blob); | 1194 | free(blob); |
1116 | packet_send(); | 1195 | packet_send(); |
@@ -1118,20 +1197,20 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) | |||
1118 | } | 1197 | } |
1119 | 1198 | ||
1120 | static Key * | 1199 | static Key * |
1121 | load_identity_file(char *filename, int userprovided) | 1200 | load_identity_file(Identity *id) |
1122 | { | 1201 | { |
1123 | Key *private; | 1202 | Key *private = NULL; |
1124 | char prompt[300], *passphrase; | 1203 | char prompt[300], *passphrase, *comment; |
1125 | int r, perm_ok = 0, quit = 0, i; | 1204 | int r, perm_ok = 0, quit = 0, i; |
1126 | struct stat st; | 1205 | struct stat st; |
1127 | 1206 | ||
1128 | if (stat(filename, &st) < 0) { | 1207 | if (stat(id->filename, &st) < 0) { |
1129 | (userprovided ? logit : debug3)("no such identity: %s: %s", | 1208 | (id->userprovided ? logit : debug3)("no such identity: %s: %s", |
1130 | filename, strerror(errno)); | 1209 | id->filename, strerror(errno)); |
1131 | return NULL; | 1210 | return NULL; |
1132 | } | 1211 | } |
1133 | snprintf(prompt, sizeof prompt, | 1212 | snprintf(prompt, sizeof prompt, |
1134 | "Enter passphrase for key '%.100s': ", filename); | 1213 | "Enter passphrase for key '%.100s': ", id->filename); |
1135 | for (i = 0; i <= options.number_of_password_prompts; i++) { | 1214 | for (i = 0; i <= options.number_of_password_prompts; i++) { |
1136 | if (i == 0) | 1215 | if (i == 0) |
1137 | passphrase = ""; | 1216 | passphrase = ""; |
@@ -1143,8 +1222,8 @@ load_identity_file(char *filename, int userprovided) | |||
1143 | break; | 1222 | break; |
1144 | } | 1223 | } |
1145 | } | 1224 | } |
1146 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, filename, | 1225 | switch ((r = sshkey_load_private_type(KEY_UNSPEC, id->filename, |
1147 | passphrase, &private, NULL, &perm_ok))) { | 1226 | passphrase, &private, &comment, &perm_ok))) { |
1148 | case 0: | 1227 | case 0: |
1149 | break; | 1228 | break; |
1150 | case SSH_ERR_KEY_WRONG_PASSPHRASE: | 1229 | case SSH_ERR_KEY_WRONG_PASSPHRASE: |
@@ -1158,20 +1237,25 @@ load_identity_file(char *filename, int userprovided) | |||
1158 | case SSH_ERR_SYSTEM_ERROR: | 1237 | case SSH_ERR_SYSTEM_ERROR: |
1159 | if (errno == ENOENT) { | 1238 | if (errno == ENOENT) { |
1160 | debug2("Load key \"%s\": %s", | 1239 | debug2("Load key \"%s\": %s", |
1161 | filename, ssh_err(r)); | 1240 | id->filename, ssh_err(r)); |
1162 | quit = 1; | 1241 | quit = 1; |
1163 | break; | 1242 | break; |
1164 | } | 1243 | } |
1165 | /* FALLTHROUGH */ | 1244 | /* FALLTHROUGH */ |
1166 | default: | 1245 | default: |
1167 | error("Load key \"%s\": %s", filename, ssh_err(r)); | 1246 | error("Load key \"%s\": %s", id->filename, ssh_err(r)); |
1168 | quit = 1; | 1247 | quit = 1; |
1169 | break; | 1248 | break; |
1170 | } | 1249 | } |
1250 | if (!quit && private != NULL && id->agent_fd == -1 && | ||
1251 | !(id->key && id->isprivate)) | ||
1252 | maybe_add_key_to_agent(id->filename, private, comment, | ||
1253 | passphrase); | ||
1171 | if (i > 0) { | 1254 | if (i > 0) { |
1172 | explicit_bzero(passphrase, strlen(passphrase)); | 1255 | explicit_bzero(passphrase, strlen(passphrase)); |
1173 | free(passphrase); | 1256 | free(passphrase); |
1174 | } | 1257 | } |
1258 | free(comment); | ||
1175 | if (private != NULL || quit) | 1259 | if (private != NULL || quit) |
1176 | break; | 1260 | break; |
1177 | } | 1261 | } |
@@ -1180,9 +1264,11 @@ load_identity_file(char *filename, int userprovided) | |||
1180 | 1264 | ||
1181 | /* | 1265 | /* |
1182 | * try keys in the following order: | 1266 | * try keys in the following order: |
1183 | * 1. agent keys that are found in the config file | 1267 | * 1. certificates listed in the config file |
1184 | * 2. other agent keys | 1268 | * 2. other input certificates |
1185 | * 3. keys that are only listed in the config file | 1269 | * 3. agent keys that are found in the config file |
1270 | * 4. other agent keys | ||
1271 | * 5. keys that are only listed in the config file | ||
1186 | */ | 1272 | */ |
1187 | static void | 1273 | static void |
1188 | pubkey_prepare(Authctxt *authctxt) | 1274 | pubkey_prepare(Authctxt *authctxt) |
@@ -1190,7 +1276,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1190 | struct identity *id, *id2, *tmp; | 1276 | struct identity *id, *id2, *tmp; |
1191 | struct idlist agent, files, *preferred; | 1277 | struct idlist agent, files, *preferred; |
1192 | struct sshkey *key; | 1278 | struct sshkey *key; |
1193 | int agent_fd, i, r, found; | 1279 | int agent_fd = -1, i, r, found; |
1194 | size_t j; | 1280 | size_t j; |
1195 | struct ssh_identitylist *idlist; | 1281 | struct ssh_identitylist *idlist; |
1196 | 1282 | ||
@@ -1208,6 +1294,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1208 | continue; | 1294 | continue; |
1209 | options.identity_keys[i] = NULL; | 1295 | options.identity_keys[i] = NULL; |
1210 | id = xcalloc(1, sizeof(*id)); | 1296 | id = xcalloc(1, sizeof(*id)); |
1297 | id->agent_fd = -1; | ||
1211 | id->key = key; | 1298 | id->key = key; |
1212 | id->filename = xstrdup(options.identity_files[i]); | 1299 | id->filename = xstrdup(options.identity_files[i]); |
1213 | id->userprovided = options.identity_file_userprovided[i]; | 1300 | id->userprovided = options.identity_file_userprovided[i]; |
@@ -1236,6 +1323,19 @@ pubkey_prepare(Authctxt *authctxt) | |||
1236 | free(id); | 1323 | free(id); |
1237 | } | 1324 | } |
1238 | } | 1325 | } |
1326 | /* list of certificates specified by user */ | ||
1327 | for (i = 0; i < options.num_certificate_files; i++) { | ||
1328 | key = options.certificates[i]; | ||
1329 | if (!key_is_cert(key) || key->cert == NULL || | ||
1330 | key->cert->type != SSH2_CERT_TYPE_USER) | ||
1331 | continue; | ||
1332 | id = xcalloc(1, sizeof(*id)); | ||
1333 | id->agent_fd = -1; | ||
1334 | id->key = key; | ||
1335 | id->filename = xstrdup(options.certificate_files[i]); | ||
1336 | id->userprovided = options.certificate_file_userprovided[i]; | ||
1337 | TAILQ_INSERT_TAIL(preferred, id, next); | ||
1338 | } | ||
1239 | /* list of keys supported by the agent */ | 1339 | /* list of keys supported by the agent */ |
1240 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { | 1340 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) { |
1241 | if (r != SSH_ERR_AGENT_NOT_PRESENT) | 1341 | if (r != SSH_ERR_AGENT_NOT_PRESENT) |
@@ -1245,6 +1345,7 @@ pubkey_prepare(Authctxt *authctxt) | |||
1245 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) | 1345 | if (r != SSH_ERR_AGENT_NO_IDENTITIES) |
1246 | debug("%s: ssh_fetch_identitylist: %s", | 1346 | debug("%s: ssh_fetch_identitylist: %s", |
1247 | __func__, ssh_err(r)); | 1347 | __func__, ssh_err(r)); |
1348 | close(agent_fd); | ||
1248 | } else { | 1349 | } else { |
1249 | for (j = 0; j < idlist->nkeys; j++) { | 1350 | for (j = 0; j < idlist->nkeys; j++) { |
1250 | found = 0; | 1351 | found = 0; |
@@ -1285,9 +1386,23 @@ pubkey_prepare(Authctxt *authctxt) | |||
1285 | TAILQ_REMOVE(&files, id, next); | 1386 | TAILQ_REMOVE(&files, id, next); |
1286 | TAILQ_INSERT_TAIL(preferred, id, next); | 1387 | TAILQ_INSERT_TAIL(preferred, id, next); |
1287 | } | 1388 | } |
1288 | TAILQ_FOREACH(id, preferred, next) { | 1389 | /* finally, filter by PubkeyAcceptedKeyTypes */ |
1289 | debug2("key: %s (%p),%s", id->filename, id->key, | 1390 | TAILQ_FOREACH_SAFE(id, preferred, next, id2) { |
1290 | id->userprovided ? " explicit" : ""); | 1391 | if (id->key != NULL && |
1392 | match_pattern_list(sshkey_ssh_name(id->key), | ||
1393 | options.pubkey_key_types, 0) != 1) { | ||
1394 | debug("Skipping %s key %s - " | ||
1395 | "not in PubkeyAcceptedKeyTypes", | ||
1396 | sshkey_ssh_name(id->key), id->filename); | ||
1397 | TAILQ_REMOVE(preferred, id, next); | ||
1398 | sshkey_free(id->key); | ||
1399 | free(id->filename); | ||
1400 | memset(id, 0, sizeof(*id)); | ||
1401 | continue; | ||
1402 | } | ||
1403 | debug2("key: %s (%p)%s%s", id->filename, id->key, | ||
1404 | id->userprovided ? ", explicit" : "", | ||
1405 | id->agent_fd != -1 ? ", agent" : ""); | ||
1291 | } | 1406 | } |
1292 | } | 1407 | } |
1293 | 1408 | ||
@@ -1301,8 +1416,7 @@ pubkey_cleanup(Authctxt *authctxt) | |||
1301 | for (id = TAILQ_FIRST(&authctxt->keys); id; | 1416 | for (id = TAILQ_FIRST(&authctxt->keys); id; |
1302 | id = TAILQ_FIRST(&authctxt->keys)) { | 1417 | id = TAILQ_FIRST(&authctxt->keys)) { |
1303 | TAILQ_REMOVE(&authctxt->keys, id, next); | 1418 | TAILQ_REMOVE(&authctxt->keys, id, next); |
1304 | if (id->key) | 1419 | sshkey_free(id->key); |
1305 | sshkey_free(id->key); | ||
1306 | free(id->filename); | 1420 | free(id->filename); |
1307 | free(id); | 1421 | free(id); |
1308 | } | 1422 | } |
@@ -1313,12 +1427,6 @@ try_identity(Identity *id) | |||
1313 | { | 1427 | { |
1314 | if (!id->key) | 1428 | if (!id->key) |
1315 | return (0); | 1429 | return (0); |
1316 | if (match_pattern_list(sshkey_ssh_name(id->key), | ||
1317 | options.pubkey_key_types, 0) != 1) { | ||
1318 | debug("Skipping %s key %s for not in PubkeyAcceptedKeyTypes", | ||
1319 | sshkey_ssh_name(id->key), id->filename); | ||
1320 | return (0); | ||
1321 | } | ||
1322 | if (key_type_plain(id->key->type) == KEY_RSA && | 1430 | if (key_type_plain(id->key->type) == KEY_RSA && |
1323 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | 1431 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { |
1324 | debug("Skipped %s key %s for RSA/MD5 server", | 1432 | debug("Skipped %s key %s for RSA/MD5 server", |
@@ -1353,8 +1461,7 @@ userauth_pubkey(Authctxt *authctxt) | |||
1353 | } | 1461 | } |
1354 | } else { | 1462 | } else { |
1355 | debug("Trying private key: %s", id->filename); | 1463 | debug("Trying private key: %s", id->filename); |
1356 | id->key = load_identity_file(id->filename, | 1464 | id->key = load_identity_file(id); |
1357 | id->userprovided); | ||
1358 | if (id->key != NULL) { | 1465 | if (id->key != NULL) { |
1359 | if (try_identity(id)) { | 1466 | if (try_identity(id)) { |
1360 | id->isprivate = 1; | 1467 | id->isprivate = 1; |
@@ -1513,7 +1620,7 @@ ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, | |||
1513 | closefrom(sock + 1); | 1620 | closefrom(sock + 1); |
1514 | debug3("%s: [child] pid=%ld, exec %s", | 1621 | debug3("%s: [child] pid=%ld, exec %s", |
1515 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); | 1622 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); |
1516 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); | 1623 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *)NULL); |
1517 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, | 1624 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, |
1518 | strerror(errno)); | 1625 | strerror(errno)); |
1519 | } | 1626 | } |
@@ -1685,7 +1792,7 @@ userauth_hostbased(Authctxt *authctxt) | |||
1685 | r = ssh_keysign(private, &sig, &siglen, | 1792 | r = ssh_keysign(private, &sig, &siglen, |
1686 | sshbuf_ptr(b), sshbuf_len(b)); | 1793 | sshbuf_ptr(b), sshbuf_len(b)); |
1687 | else if ((r = sshkey_sign(private, &sig, &siglen, | 1794 | else if ((r = sshkey_sign(private, &sig, &siglen, |
1688 | sshbuf_ptr(b), sshbuf_len(b), datafellows)) != 0) | 1795 | sshbuf_ptr(b), sshbuf_len(b), NULL, datafellows)) != 0) |
1689 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); | 1796 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
1690 | if (r != 0) { | 1797 | if (r != 0) { |
1691 | error("sign using hostkey %s %s failed", | 1798 | error("sign using hostkey %s %s failed", |