sshconnect2.c revision 215116
1215116Sdes/* $OpenBSD: sshconnect2.c,v 1.183 2010/04/26 22:28:24 djm Exp $ */ 260573Skris/* 360573Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 4192595Sdes * Copyright (c) 2008 Damien Miller. All rights reserved. 560573Skris * 660573Skris * Redistribution and use in source and binary forms, with or without 760573Skris * modification, are permitted provided that the following conditions 860573Skris * are met: 960573Skris * 1. Redistributions of source code must retain the above copyright 1060573Skris * notice, this list of conditions and the following disclaimer. 1160573Skris * 2. Redistributions in binary form must reproduce the above copyright 1260573Skris * notice, this list of conditions and the following disclaimer in the 1360573Skris * documentation and/or other materials provided with the distribution. 1460573Skris * 1560573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1660573Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1760573Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1860573Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1960573Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2060573Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2160573Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2260573Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2360573Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2460573Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2560573Skris */ 2660573Skris 2760573Skris#include "includes.h" 2860573Skris 29162856Sdes#include <sys/types.h> 30162856Sdes#include <sys/socket.h> 31162856Sdes#include <sys/wait.h> 32162856Sdes#include <sys/stat.h> 33162856Sdes 34162856Sdes#include <errno.h> 35204917Sdes#include <fcntl.h> 36181111Sdes#include <netdb.h> 37162856Sdes#include <pwd.h> 38162856Sdes#include <signal.h> 39162856Sdes#include <stdarg.h> 40162856Sdes#include <stdio.h> 41162856Sdes#include <string.h> 42162856Sdes#include <unistd.h> 43181111Sdes#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) 44181111Sdes#include <vis.h> 45181111Sdes#endif 46162856Sdes 47124211Sdes#include "openbsd-compat/sys-queue.h" 48124211Sdes 49162856Sdes#include "xmalloc.h" 5060573Skris#include "ssh.h" 5176262Sgreen#include "ssh2.h" 5260573Skris#include "buffer.h" 5360573Skris#include "packet.h" 5460573Skris#include "compat.h" 5576262Sgreen#include "cipher.h" 56162856Sdes#include "key.h" 5760573Skris#include "kex.h" 5860573Skris#include "myproposal.h" 5960573Skris#include "sshconnect.h" 6060573Skris#include "authfile.h" 6176262Sgreen#include "dh.h" 6276262Sgreen#include "authfd.h" 6376262Sgreen#include "log.h" 6476262Sgreen#include "readconf.h" 65137019Sdes#include "misc.h" 6676262Sgreen#include "match.h" 6769587Sgreen#include "dispatch.h" 6876262Sgreen#include "canohost.h" 6998684Sdes#include "msg.h" 7098684Sdes#include "pathnames.h" 71162856Sdes#include "uidswap.h" 72197679Sdes#include "schnorr.h" 73192595Sdes#include "jpake.h" 7460573Skris 75124211Sdes#ifdef GSSAPI 76124211Sdes#include "ssh-gss.h" 77124211Sdes#endif 78124211Sdes 7960573Skris/* import */ 8060573Skrisextern char *client_version_string; 8160573Skrisextern char *server_version_string; 8260573Skrisextern Options options; 8360573Skris 8460573Skris/* 8560573Skris * SSH2 key exchange 8660573Skris */ 8760573Skris 8876262Sgreenu_char *session_id2 = NULL; 89124211Sdesu_int session_id2_len = 0; 9060573Skris 9176262Sgreenchar *xxx_host; 9276262Sgreenstruct sockaddr *xxx_hostaddr; 9376262Sgreen 9476262SgreenKex *xxx_kex = NULL; 9576262Sgreen 9692559Sdesstatic int 9792559Sdesverify_host_key_callback(Key *hostkey) 9876262Sgreen{ 9992559Sdes if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) 10092559Sdes fatal("Host key verification failed."); 10176262Sgreen return 0; 10276262Sgreen} 10376262Sgreen 10460573Skrisvoid 10569587Sgreenssh_kex2(char *host, struct sockaddr *hostaddr) 10660573Skris{ 10769587Sgreen Kex *kex; 10869587Sgreen 10976262Sgreen xxx_host = host; 11076262Sgreen xxx_hostaddr = hostaddr; 11176262Sgreen 11276262Sgreen if (options.ciphers == (char *)-1) { 113124211Sdes logit("No valid ciphers for protocol version 2 given, using defaults."); 11476262Sgreen options.ciphers = NULL; 11569587Sgreen } 11669587Sgreen if (options.ciphers != NULL) { 11769587Sgreen myproposal[PROPOSAL_ENC_ALGS_CTOS] = 11869587Sgreen myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; 11969587Sgreen } 12076262Sgreen myproposal[PROPOSAL_ENC_ALGS_CTOS] = 12176262Sgreen compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); 12276262Sgreen myproposal[PROPOSAL_ENC_ALGS_STOC] = 12376262Sgreen compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); 12469587Sgreen if (options.compression) { 12576262Sgreen myproposal[PROPOSAL_COMP_ALGS_CTOS] = 126149753Sdes myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none"; 12769587Sgreen } else { 12876262Sgreen myproposal[PROPOSAL_COMP_ALGS_CTOS] = 129149753Sdes myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib"; 13069587Sgreen } 13176262Sgreen if (options.macs != NULL) { 13276262Sgreen myproposal[PROPOSAL_MAC_ALGS_CTOS] = 13376262Sgreen myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 13476262Sgreen } 13576262Sgreen if (options.hostkeyalgorithms != NULL) 13692559Sdes myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 13776262Sgreen options.hostkeyalgorithms; 13869587Sgreen 139124211Sdes if (options.rekey_limit) 140181111Sdes packet_set_rekey_limit((u_int32_t)options.rekey_limit); 141124211Sdes 14276262Sgreen /* start key exchange */ 14376262Sgreen kex = kex_setup(myproposal); 144113911Sdes kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 145137019Sdes kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 146113911Sdes kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 147162856Sdes kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 14876262Sgreen kex->client_version_string=client_version_string; 14976262Sgreen kex->server_version_string=server_version_string; 15092559Sdes kex->verify_host_key=&verify_host_key_callback; 15169587Sgreen 15276262Sgreen xxx_kex = kex; 15369587Sgreen 15476262Sgreen dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 15569587Sgreen 156204917Sdes if (options.use_roaming && !kex->roaming) { 157204917Sdes debug("Roaming not allowed by server"); 158204917Sdes options.use_roaming = 0; 159204917Sdes } 160204917Sdes 16176262Sgreen session_id2 = kex->session_id; 16276262Sgreen session_id2_len = kex->session_id_len; 16369587Sgreen 16469587Sgreen#ifdef DEBUG_KEXDH 16569587Sgreen /* send 1st encrypted/maced/compressed message */ 16669587Sgreen packet_start(SSH2_MSG_IGNORE); 16769587Sgreen packet_put_cstring("markus"); 16869587Sgreen packet_send(); 16969587Sgreen packet_write_wait(); 17069587Sgreen#endif 17169587Sgreen} 17269587Sgreen 17369587Sgreen/* 17460573Skris * Authenticate user 17560573Skris */ 17669587Sgreen 17769587Sgreentypedef struct Authctxt Authctxt; 17869587Sgreentypedef struct Authmethod Authmethod; 179124211Sdestypedef struct identity Identity; 180124211Sdestypedef struct idlist Idlist; 18169587Sgreen 182124211Sdesstruct identity { 183124211Sdes TAILQ_ENTRY(identity) next; 184124211Sdes AuthenticationConnection *ac; /* set if agent supports key */ 185124211Sdes Key *key; /* public/private key */ 186124211Sdes char *filename; /* comment for agent-only keys */ 187124211Sdes int tried; 188124211Sdes int isprivate; /* key points to the private key */ 189124211Sdes}; 190124211SdesTAILQ_HEAD(idlist, identity); 19169587Sgreen 19269587Sgreenstruct Authctxt { 19369587Sgreen const char *server_user; 19476262Sgreen const char *local_user; 19569587Sgreen const char *host; 19669587Sgreen const char *service; 19769587Sgreen Authmethod *method; 198215116Sdes sig_atomic_t success; 19976262Sgreen char *authlist; 20076262Sgreen /* pubkey */ 201124211Sdes Idlist keys; 20276262Sgreen AuthenticationConnection *agent; 20376262Sgreen /* hostbased */ 20498684Sdes Sensitive *sensitive; 20592559Sdes /* kbd-interactive */ 20692559Sdes int info_req_seen; 207124211Sdes /* generic */ 208124211Sdes void *methoddata; 20969587Sgreen}; 21069587Sgreenstruct Authmethod { 21169587Sgreen char *name; /* string to compare against server's list */ 21269587Sgreen int (*userauth)(Authctxt *authctxt); 213192595Sdes void (*cleanup)(Authctxt *authctxt); 21469587Sgreen int *enabled; /* flag in option struct that enables method */ 21569587Sgreen int *batch_flag; /* flag in option struct that disables method */ 21669587Sgreen}; 21769587Sgreen 21892559Sdesvoid input_userauth_success(int, u_int32_t, void *); 219204917Sdesvoid input_userauth_success_unexpected(int, u_int32_t, void *); 22092559Sdesvoid input_userauth_failure(int, u_int32_t, void *); 22192559Sdesvoid input_userauth_banner(int, u_int32_t, void *); 22292559Sdesvoid input_userauth_error(int, u_int32_t, void *); 22392559Sdesvoid input_userauth_info_req(int, u_int32_t, void *); 22492559Sdesvoid input_userauth_pk_ok(int, u_int32_t, void *); 22598684Sdesvoid input_userauth_passwd_changereq(int, u_int32_t, void *); 226192595Sdesvoid input_userauth_jpake_server_step1(int, u_int32_t, void *); 227192595Sdesvoid input_userauth_jpake_server_step2(int, u_int32_t, void *); 228192595Sdesvoid input_userauth_jpake_server_confirm(int, u_int32_t, void *); 22969587Sgreen 23092559Sdesint userauth_none(Authctxt *); 23192559Sdesint userauth_pubkey(Authctxt *); 23292559Sdesint userauth_passwd(Authctxt *); 23392559Sdesint userauth_kbdint(Authctxt *); 23492559Sdesint userauth_hostbased(Authctxt *); 235192595Sdesint userauth_jpake(Authctxt *); 23669587Sgreen 237192595Sdesvoid userauth_jpake_cleanup(Authctxt *); 238192595Sdes 239124211Sdes#ifdef GSSAPI 240124211Sdesint userauth_gssapi(Authctxt *authctxt); 241124211Sdesvoid input_gssapi_response(int type, u_int32_t, void *); 242124211Sdesvoid input_gssapi_token(int type, u_int32_t, void *); 243124211Sdesvoid input_gssapi_hash(int type, u_int32_t, void *); 244124211Sdesvoid input_gssapi_error(int, u_int32_t, void *); 245124211Sdesvoid input_gssapi_errtok(int, u_int32_t, void *); 246124211Sdes#endif 247124211Sdes 24892559Sdesvoid userauth(Authctxt *, char *); 24976262Sgreen 250124211Sdesstatic int sign_and_send_pubkey(Authctxt *, Identity *); 251124211Sdesstatic void pubkey_prepare(Authctxt *); 252124211Sdesstatic void pubkey_cleanup(Authctxt *); 253124211Sdesstatic Key *load_identity_file(char *); 25476262Sgreen 25592559Sdesstatic Authmethod *authmethod_get(char *authlist); 25692559Sdesstatic Authmethod *authmethod_lookup(const char *name); 25792559Sdesstatic char *authmethods_get(void); 25869587Sgreen 25969587SgreenAuthmethod authmethods[] = { 260124211Sdes#ifdef GSSAPI 261126277Sdes {"gssapi-with-mic", 262124211Sdes userauth_gssapi, 263192595Sdes NULL, 264124211Sdes &options.gss_authentication, 265124211Sdes NULL}, 266124211Sdes#endif 26792559Sdes {"hostbased", 26892559Sdes userauth_hostbased, 269192595Sdes NULL, 27092559Sdes &options.hostbased_authentication, 27192559Sdes NULL}, 27269587Sgreen {"publickey", 27369587Sgreen userauth_pubkey, 274192595Sdes NULL, 27576262Sgreen &options.pubkey_authentication, 27669587Sgreen NULL}, 277192595Sdes#ifdef JPAKE 278192595Sdes {"jpake-01@openssh.com", 279192595Sdes userauth_jpake, 280192595Sdes userauth_jpake_cleanup, 281192595Sdes &options.zero_knowledge_password_authentication, 282192595Sdes &options.batch_mode}, 283192595Sdes#endif 28492559Sdes {"keyboard-interactive", 28592559Sdes userauth_kbdint, 286192595Sdes NULL, 28792559Sdes &options.kbd_interactive_authentication, 28892559Sdes &options.batch_mode}, 28969587Sgreen {"password", 29069587Sgreen userauth_passwd, 291192595Sdes NULL, 29269587Sgreen &options.password_authentication, 29369587Sgreen &options.batch_mode}, 29469587Sgreen {"none", 29569587Sgreen userauth_none, 29669587Sgreen NULL, 297192595Sdes NULL, 29869587Sgreen NULL}, 299192595Sdes {NULL, NULL, NULL, NULL, NULL} 30069587Sgreen}; 30169587Sgreen 30269587Sgreenvoid 30376262Sgreenssh_userauth2(const char *local_user, const char *server_user, char *host, 30498684Sdes Sensitive *sensitive) 30569587Sgreen{ 30669587Sgreen Authctxt authctxt; 30769587Sgreen int type; 30869587Sgreen 30992559Sdes if (options.challenge_response_authentication) 31076262Sgreen options.kbd_interactive_authentication = 1; 31176262Sgreen 31269587Sgreen packet_start(SSH2_MSG_SERVICE_REQUEST); 31369587Sgreen packet_put_cstring("ssh-userauth"); 31469587Sgreen packet_send(); 315113911Sdes debug("SSH2_MSG_SERVICE_REQUEST sent"); 31669587Sgreen packet_write_wait(); 31792559Sdes type = packet_read(); 318113911Sdes if (type != SSH2_MSG_SERVICE_ACCEPT) 319113911Sdes fatal("Server denied authentication request: %d", type); 32069587Sgreen if (packet_remaining() > 0) { 32192559Sdes char *reply = packet_get_string(NULL); 322113911Sdes debug2("service_accept: %s", reply); 32369587Sgreen xfree(reply); 32469587Sgreen } else { 325113911Sdes debug2("buggy server: service_accept w/o service"); 32669587Sgreen } 32792559Sdes packet_check_eom(); 328113911Sdes debug("SSH2_MSG_SERVICE_ACCEPT received"); 32969587Sgreen 33076262Sgreen if (options.preferred_authentications == NULL) 33176262Sgreen options.preferred_authentications = authmethods_get(); 33276262Sgreen 33369587Sgreen /* setup authentication context */ 33492559Sdes memset(&authctxt, 0, sizeof(authctxt)); 335124211Sdes pubkey_prepare(&authctxt); 33669587Sgreen authctxt.server_user = server_user; 33776262Sgreen authctxt.local_user = local_user; 33869587Sgreen authctxt.host = host; 33969587Sgreen authctxt.service = "ssh-connection"; /* service name */ 34069587Sgreen authctxt.success = 0; 34169587Sgreen authctxt.method = authmethod_lookup("none"); 34276262Sgreen authctxt.authlist = NULL; 343124211Sdes authctxt.methoddata = NULL; 34498684Sdes authctxt.sensitive = sensitive; 34592559Sdes authctxt.info_req_seen = 0; 34669587Sgreen if (authctxt.method == NULL) 34769587Sgreen fatal("ssh_userauth2: internal error: cannot send userauth none request"); 34869587Sgreen 34969587Sgreen /* initial userauth request */ 35069587Sgreen userauth_none(&authctxt); 35169587Sgreen 35269587Sgreen dispatch_init(&input_userauth_error); 35369587Sgreen dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 35469587Sgreen dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); 35576262Sgreen dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); 35669587Sgreen dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ 35769587Sgreen 358124211Sdes pubkey_cleanup(&authctxt); 359124211Sdes dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); 36069587Sgreen 361113911Sdes debug("Authentication succeeded (%s).", authctxt.method->name); 36269587Sgreen} 363124211Sdes 36469587Sgreenvoid 36576262Sgreenuserauth(Authctxt *authctxt, char *authlist) 36676262Sgreen{ 367192595Sdes if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 368192595Sdes authctxt->method->cleanup(authctxt); 369192595Sdes 370124211Sdes if (authctxt->methoddata) { 371124211Sdes xfree(authctxt->methoddata); 372124211Sdes authctxt->methoddata = NULL; 373124211Sdes } 37476262Sgreen if (authlist == NULL) { 37576262Sgreen authlist = authctxt->authlist; 37676262Sgreen } else { 37776262Sgreen if (authctxt->authlist) 37876262Sgreen xfree(authctxt->authlist); 37976262Sgreen authctxt->authlist = authlist; 38076262Sgreen } 38176262Sgreen for (;;) { 38276262Sgreen Authmethod *method = authmethod_get(authlist); 38376262Sgreen if (method == NULL) 38476262Sgreen fatal("Permission denied (%s).", authlist); 38576262Sgreen authctxt->method = method; 386124211Sdes 387124211Sdes /* reset the per method handler */ 388124211Sdes dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, 389124211Sdes SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); 390124211Sdes 391124211Sdes /* and try new method */ 39276262Sgreen if (method->userauth(authctxt) != 0) { 39376262Sgreen debug2("we sent a %s packet, wait for reply", method->name); 39476262Sgreen break; 39576262Sgreen } else { 39676262Sgreen debug2("we did not send a packet, disable method"); 39776262Sgreen method->enabled = NULL; 39876262Sgreen } 39976262Sgreen } 40076262Sgreen} 40199063Sdes 402192595Sdes/* ARGSUSED */ 40376262Sgreenvoid 40492559Sdesinput_userauth_error(int type, u_int32_t seq, void *ctxt) 40569587Sgreen{ 40676262Sgreen fatal("input_userauth_error: bad message during authentication: " 407149753Sdes "type %d", type); 40869587Sgreen} 40999063Sdes 410192595Sdes/* ARGSUSED */ 41169587Sgreenvoid 41292559Sdesinput_userauth_banner(int type, u_int32_t seq, void *ctxt) 41376262Sgreen{ 414181111Sdes char *msg, *raw, *lang; 415181111Sdes u_int len; 416126277Sdes 41776262Sgreen debug3("input_userauth_banner"); 418181111Sdes raw = packet_get_string(&len); 41976262Sgreen lang = packet_get_string(NULL); 420192595Sdes if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) { 421181111Sdes if (len > 65536) 422181111Sdes len = 65536; 423183336Sdes msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ 424204917Sdes strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH); 425126277Sdes fprintf(stderr, "%s", msg); 426181111Sdes xfree(msg); 427181111Sdes } 428181111Sdes xfree(raw); 42976262Sgreen xfree(lang); 43076262Sgreen} 43199063Sdes 432192595Sdes/* ARGSUSED */ 43376262Sgreenvoid 43492559Sdesinput_userauth_success(int type, u_int32_t seq, void *ctxt) 43569587Sgreen{ 43669587Sgreen Authctxt *authctxt = ctxt; 437204917Sdes 43869587Sgreen if (authctxt == NULL) 43969587Sgreen fatal("input_userauth_success: no authentication context"); 440126277Sdes if (authctxt->authlist) { 44176262Sgreen xfree(authctxt->authlist); 442126277Sdes authctxt->authlist = NULL; 443126277Sdes } 444204917Sdes if (authctxt->method != NULL && authctxt->method->cleanup != NULL) 445204917Sdes authctxt->method->cleanup(authctxt); 446126277Sdes if (authctxt->methoddata) { 447124211Sdes xfree(authctxt->methoddata); 448126277Sdes authctxt->methoddata = NULL; 449126277Sdes } 45069587Sgreen authctxt->success = 1; /* break out */ 45169587Sgreen} 45299063Sdes 453204917Sdesvoid 454204917Sdesinput_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) 455204917Sdes{ 456204917Sdes Authctxt *authctxt = ctxt; 457204917Sdes 458204917Sdes if (authctxt == NULL) 459204917Sdes fatal("%s: no authentication context", __func__); 460204917Sdes 461204917Sdes fatal("Unexpected authentication success during %s.", 462204917Sdes authctxt->method->name); 463204917Sdes} 464204917Sdes 465192595Sdes/* ARGSUSED */ 46669587Sgreenvoid 46792559Sdesinput_userauth_failure(int type, u_int32_t seq, void *ctxt) 46869587Sgreen{ 46969587Sgreen Authctxt *authctxt = ctxt; 47069587Sgreen char *authlist = NULL; 47169587Sgreen int partial; 47269587Sgreen 47369587Sgreen if (authctxt == NULL) 47469587Sgreen fatal("input_userauth_failure: no authentication context"); 47569587Sgreen 47669587Sgreen authlist = packet_get_string(NULL); 47769587Sgreen partial = packet_get_char(); 47892559Sdes packet_check_eom(); 47969587Sgreen 48069587Sgreen if (partial != 0) 481124211Sdes logit("Authenticated with partial success."); 482113911Sdes debug("Authentications that can continue: %s", authlist); 48369587Sgreen 48476262Sgreen userauth(authctxt, authlist); 48576262Sgreen} 486192595Sdes 487192595Sdes/* ARGSUSED */ 48876262Sgreenvoid 48992559Sdesinput_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) 49076262Sgreen{ 49176262Sgreen Authctxt *authctxt = ctxt; 49276262Sgreen Key *key = NULL; 493124211Sdes Identity *id = NULL; 49476262Sgreen Buffer b; 49592559Sdes int pktype, sent = 0; 49692559Sdes u_int alen, blen; 49792559Sdes char *pkalg, *fp; 49892559Sdes u_char *pkblob; 49976262Sgreen 50076262Sgreen if (authctxt == NULL) 50176262Sgreen fatal("input_userauth_pk_ok: no authentication context"); 50276262Sgreen if (datafellows & SSH_BUG_PKOK) { 50376262Sgreen /* this is similar to SSH_BUG_PKAUTH */ 50476262Sgreen debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); 50576262Sgreen pkblob = packet_get_string(&blen); 50676262Sgreen buffer_init(&b); 50776262Sgreen buffer_append(&b, pkblob, blen); 50876262Sgreen pkalg = buffer_get_string(&b, &alen); 50976262Sgreen buffer_free(&b); 51076262Sgreen } else { 51176262Sgreen pkalg = packet_get_string(&alen); 51276262Sgreen pkblob = packet_get_string(&blen); 51376262Sgreen } 51492559Sdes packet_check_eom(); 51576262Sgreen 516124211Sdes debug("Server accepts key: pkalg %s blen %u", pkalg, blen); 51776262Sgreen 518124211Sdes if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { 519124211Sdes debug("unknown pkalg %s", pkalg); 520124211Sdes goto done; 521124211Sdes } 522124211Sdes if ((key = key_from_blob(pkblob, blen)) == NULL) { 523124211Sdes debug("no key from blob. pkalg %s", pkalg); 524124211Sdes goto done; 525124211Sdes } 526124211Sdes if (key->type != pktype) { 527124211Sdes error("input_userauth_pk_ok: type mismatch " 528124211Sdes "for decoded key (received %d, expected %d)", 529124211Sdes key->type, pktype); 530124211Sdes goto done; 531124211Sdes } 532124211Sdes fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); 533124211Sdes debug2("input_userauth_pk_ok: fp %s", fp); 534124211Sdes xfree(fp); 535124211Sdes 536126277Sdes /* 537126277Sdes * search keys in the reverse order, because last candidate has been 538126277Sdes * moved to the end of the queue. this also avoids confusion by 539126277Sdes * duplicate keys 540126277Sdes */ 541137019Sdes TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { 542124211Sdes if (key_equal(key, id->key)) { 543124211Sdes sent = sign_and_send_pubkey(authctxt, id); 54469587Sgreen break; 54569587Sgreen } 546124211Sdes } 547124211Sdesdone: 54876262Sgreen if (key != NULL) 54976262Sgreen key_free(key); 55076262Sgreen xfree(pkalg); 55176262Sgreen xfree(pkblob); 55276262Sgreen 553106130Sdes /* try another method if we did not send a packet */ 55476262Sgreen if (sent == 0) 55576262Sgreen userauth(authctxt, NULL); 556124211Sdes} 55776262Sgreen 558124211Sdes#ifdef GSSAPI 559126277Sdesint 560124211Sdesuserauth_gssapi(Authctxt *authctxt) 561124211Sdes{ 562124211Sdes Gssctxt *gssctxt = NULL; 563126277Sdes static gss_OID_set gss_supported = NULL; 564149753Sdes static u_int mech = 0; 565124211Sdes OM_uint32 min; 566124211Sdes int ok = 0; 567124211Sdes 568124211Sdes /* Try one GSSAPI method at a time, rather than sending them all at 569124211Sdes * once. */ 570124211Sdes 571126277Sdes if (gss_supported == NULL) 572126277Sdes gss_indicate_mechs(&min, &gss_supported); 573124211Sdes 574124211Sdes /* Check to see if the mechanism is usable before we offer it */ 575126277Sdes while (mech < gss_supported->count && !ok) { 576124211Sdes /* My DER encoding requires length<128 */ 577126277Sdes if (gss_supported->elements[mech].length < 128 && 578162856Sdes ssh_gssapi_check_mechanism(&gssctxt, 579162856Sdes &gss_supported->elements[mech], authctxt->host)) { 580124211Sdes ok = 1; /* Mechanism works */ 581124211Sdes } else { 582124211Sdes mech++; 583124211Sdes } 584124211Sdes } 585124211Sdes 586149753Sdes if (!ok) 587149753Sdes return 0; 588124211Sdes 589124211Sdes authctxt->methoddata=(void *)gssctxt; 590124211Sdes 591124211Sdes packet_start(SSH2_MSG_USERAUTH_REQUEST); 592124211Sdes packet_put_cstring(authctxt->server_user); 593124211Sdes packet_put_cstring(authctxt->service); 594124211Sdes packet_put_cstring(authctxt->method->name); 595124211Sdes 596124211Sdes packet_put_int(1); 597124211Sdes 598126277Sdes packet_put_int((gss_supported->elements[mech].length) + 2); 599126277Sdes packet_put_char(SSH_GSS_OIDTYPE); 600126277Sdes packet_put_char(gss_supported->elements[mech].length); 601126277Sdes packet_put_raw(gss_supported->elements[mech].elements, 602126277Sdes gss_supported->elements[mech].length); 603124211Sdes 604124211Sdes packet_send(); 605124211Sdes 606124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); 607124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 608124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); 609124211Sdes dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 610124211Sdes 611124211Sdes mech++; /* Move along to next candidate */ 612124211Sdes 613124211Sdes return 1; 61469587Sgreen} 61569587Sgreen 616126277Sdesstatic OM_uint32 617126277Sdesprocess_gssapi_token(void *ctxt, gss_buffer_t recv_tok) 618126277Sdes{ 619126277Sdes Authctxt *authctxt = ctxt; 620126277Sdes Gssctxt *gssctxt = authctxt->methoddata; 621126277Sdes gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 622149753Sdes gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; 623149753Sdes gss_buffer_desc gssbuf; 624126277Sdes OM_uint32 status, ms, flags; 625126277Sdes Buffer b; 626126277Sdes 627126277Sdes status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 628126277Sdes recv_tok, &send_tok, &flags); 629126277Sdes 630126277Sdes if (send_tok.length > 0) { 631126277Sdes if (GSS_ERROR(status)) 632126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 633126277Sdes else 634126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 635126277Sdes 636126277Sdes packet_put_string(send_tok.value, send_tok.length); 637126277Sdes packet_send(); 638126277Sdes gss_release_buffer(&ms, &send_tok); 639126277Sdes } 640126277Sdes 641126277Sdes if (status == GSS_S_COMPLETE) { 642126277Sdes /* send either complete or MIC, depending on mechanism */ 643126277Sdes if (!(flags & GSS_C_INTEG_FLAG)) { 644126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); 645126277Sdes packet_send(); 646126277Sdes } else { 647126277Sdes ssh_gssapi_buildmic(&b, authctxt->server_user, 648126277Sdes authctxt->service, "gssapi-with-mic"); 649126277Sdes 650126277Sdes gssbuf.value = buffer_ptr(&b); 651126277Sdes gssbuf.length = buffer_len(&b); 652126277Sdes 653126277Sdes status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); 654126277Sdes 655126277Sdes if (!GSS_ERROR(status)) { 656126277Sdes packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); 657126277Sdes packet_put_string(mic.value, mic.length); 658126277Sdes 659126277Sdes packet_send(); 660126277Sdes } 661126277Sdes 662126277Sdes buffer_free(&b); 663126277Sdes gss_release_buffer(&ms, &mic); 664126277Sdes } 665126277Sdes } 666126277Sdes 667126277Sdes return status; 668126277Sdes} 669126277Sdes 670192595Sdes/* ARGSUSED */ 671124211Sdesvoid 672124211Sdesinput_gssapi_response(int type, u_int32_t plen, void *ctxt) 673124211Sdes{ 674124211Sdes Authctxt *authctxt = ctxt; 675124211Sdes Gssctxt *gssctxt; 676124211Sdes int oidlen; 677124211Sdes char *oidv; 678124211Sdes 679124211Sdes if (authctxt == NULL) 680124211Sdes fatal("input_gssapi_response: no authentication context"); 681124211Sdes gssctxt = authctxt->methoddata; 682124211Sdes 683124211Sdes /* Setup our OID */ 684124211Sdes oidv = packet_get_string(&oidlen); 685124211Sdes 686126277Sdes if (oidlen <= 2 || 687126277Sdes oidv[0] != SSH_GSS_OIDTYPE || 688126277Sdes oidv[1] != oidlen - 2) { 689126277Sdes xfree(oidv); 690126277Sdes debug("Badly encoded mechanism OID received"); 691126277Sdes userauth(authctxt, NULL); 692126277Sdes return; 693124211Sdes } 694124211Sdes 695126277Sdes if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) 696126277Sdes fatal("Server returned different OID than expected"); 697126277Sdes 698124211Sdes packet_check_eom(); 699124211Sdes 700124211Sdes xfree(oidv); 701124211Sdes 702126277Sdes if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { 703124211Sdes /* Start again with next method on list */ 704124211Sdes debug("Trying to start again"); 705124211Sdes userauth(authctxt, NULL); 706124211Sdes return; 707124211Sdes } 708124211Sdes} 709124211Sdes 710192595Sdes/* ARGSUSED */ 711124211Sdesvoid 712124211Sdesinput_gssapi_token(int type, u_int32_t plen, void *ctxt) 713124211Sdes{ 714124211Sdes Authctxt *authctxt = ctxt; 715124211Sdes gss_buffer_desc recv_tok; 716126277Sdes OM_uint32 status; 717124211Sdes u_int slen; 718124211Sdes 719124211Sdes if (authctxt == NULL) 720124211Sdes fatal("input_gssapi_response: no authentication context"); 721124211Sdes 722124211Sdes recv_tok.value = packet_get_string(&slen); 723124211Sdes recv_tok.length = slen; /* safe typecast */ 724124211Sdes 725124211Sdes packet_check_eom(); 726124211Sdes 727126277Sdes status = process_gssapi_token(ctxt, &recv_tok); 728124211Sdes 729124211Sdes xfree(recv_tok.value); 730124211Sdes 731124211Sdes if (GSS_ERROR(status)) { 732124211Sdes /* Start again with the next method in the list */ 733124211Sdes userauth(authctxt, NULL); 734124211Sdes return; 735124211Sdes } 736124211Sdes} 737124211Sdes 738192595Sdes/* ARGSUSED */ 739124211Sdesvoid 740124211Sdesinput_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 741124211Sdes{ 742124211Sdes Authctxt *authctxt = ctxt; 743124211Sdes Gssctxt *gssctxt; 744124211Sdes gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 745124211Sdes gss_buffer_desc recv_tok; 746124211Sdes OM_uint32 status, ms; 747124211Sdes u_int len; 748124211Sdes 749124211Sdes if (authctxt == NULL) 750124211Sdes fatal("input_gssapi_response: no authentication context"); 751124211Sdes gssctxt = authctxt->methoddata; 752124211Sdes 753124211Sdes recv_tok.value = packet_get_string(&len); 754124211Sdes recv_tok.length = len; 755124211Sdes 756124211Sdes packet_check_eom(); 757124211Sdes 758124211Sdes /* Stick it into GSSAPI and see what it says */ 759124211Sdes status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, 760149753Sdes &recv_tok, &send_tok, NULL); 761124211Sdes 762124211Sdes xfree(recv_tok.value); 763124211Sdes gss_release_buffer(&ms, &send_tok); 764124211Sdes 765124211Sdes /* Server will be returning a failed packet after this one */ 766124211Sdes} 767124211Sdes 768192595Sdes/* ARGSUSED */ 769124211Sdesvoid 770124211Sdesinput_gssapi_error(int type, u_int32_t plen, void *ctxt) 771124211Sdes{ 772124211Sdes OM_uint32 maj, min; 773124211Sdes char *msg; 774124211Sdes char *lang; 775124211Sdes 776124211Sdes maj=packet_get_int(); 777124211Sdes min=packet_get_int(); 778124211Sdes msg=packet_get_string(NULL); 779124211Sdes lang=packet_get_string(NULL); 780124211Sdes 781124211Sdes packet_check_eom(); 782124211Sdes 783157019Sdes debug("Server GSSAPI Error:\n%s", msg); 784124211Sdes xfree(msg); 785124211Sdes xfree(lang); 786124211Sdes} 787124211Sdes#endif /* GSSAPI */ 788124211Sdes 78960573Skrisint 79069587Sgreenuserauth_none(Authctxt *authctxt) 79160573Skris{ 79269587Sgreen /* initial userauth request */ 79369587Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 79469587Sgreen packet_put_cstring(authctxt->server_user); 79569587Sgreen packet_put_cstring(authctxt->service); 79669587Sgreen packet_put_cstring(authctxt->method->name); 79769587Sgreen packet_send(); 79869587Sgreen return 1; 79969587Sgreen} 80069587Sgreen 80169587Sgreenint 80269587Sgreenuserauth_passwd(Authctxt *authctxt) 80369587Sgreen{ 80460573Skris static int attempt = 0; 80598684Sdes char prompt[150]; 80660573Skris char *password; 807204917Sdes const char *host = options.host_key_alias ? options.host_key_alias : 808204917Sdes authctxt->host; 80960573Skris 81065668Skris if (attempt++ >= options.number_of_password_prompts) 81160573Skris return 0; 81260573Skris 81392559Sdes if (attempt != 1) 81465668Skris error("Permission denied, please try again."); 81565668Skris 81676262Sgreen snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", 817204917Sdes authctxt->server_user, host); 81860573Skris password = read_passphrase(prompt, 0); 81960573Skris packet_start(SSH2_MSG_USERAUTH_REQUEST); 82069587Sgreen packet_put_cstring(authctxt->server_user); 82169587Sgreen packet_put_cstring(authctxt->service); 82269587Sgreen packet_put_cstring(authctxt->method->name); 82360573Skris packet_put_char(0); 82493704Sdes packet_put_cstring(password); 82560573Skris memset(password, 0, strlen(password)); 82660573Skris xfree(password); 82792559Sdes packet_add_padding(64); 82860573Skris packet_send(); 82998684Sdes 83098684Sdes dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 83198684Sdes &input_userauth_passwd_changereq); 83298684Sdes 83360573Skris return 1; 83460573Skris} 835192595Sdes 83698684Sdes/* 83798684Sdes * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST 83898684Sdes */ 839192595Sdes/* ARGSUSED */ 84098684Sdesvoid 84198941Sdesinput_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) 84298684Sdes{ 84398684Sdes Authctxt *authctxt = ctxt; 84498684Sdes char *info, *lang, *password = NULL, *retype = NULL; 84598684Sdes char prompt[150]; 846204917Sdes const char *host = options.host_key_alias ? options.host_key_alias : 847204917Sdes authctxt->host; 84860573Skris 84998684Sdes debug2("input_userauth_passwd_changereq"); 85098684Sdes 85198684Sdes if (authctxt == NULL) 85298684Sdes fatal("input_userauth_passwd_changereq: " 85398684Sdes "no authentication context"); 85498684Sdes 85598684Sdes info = packet_get_string(NULL); 85698684Sdes lang = packet_get_string(NULL); 85798684Sdes if (strlen(info) > 0) 858124211Sdes logit("%s", info); 85998684Sdes xfree(info); 86098684Sdes xfree(lang); 86198684Sdes packet_start(SSH2_MSG_USERAUTH_REQUEST); 86298684Sdes packet_put_cstring(authctxt->server_user); 86398684Sdes packet_put_cstring(authctxt->service); 86498684Sdes packet_put_cstring(authctxt->method->name); 86598684Sdes packet_put_char(1); /* additional info */ 86698684Sdes snprintf(prompt, sizeof(prompt), 86798684Sdes "Enter %.30s@%.128s's old password: ", 868204917Sdes authctxt->server_user, host); 86998684Sdes password = read_passphrase(prompt, 0); 87098684Sdes packet_put_cstring(password); 87198684Sdes memset(password, 0, strlen(password)); 87298684Sdes xfree(password); 87398684Sdes password = NULL; 87498684Sdes while (password == NULL) { 87598684Sdes snprintf(prompt, sizeof(prompt), 87698684Sdes "Enter %.30s@%.128s's new password: ", 877204917Sdes authctxt->server_user, host); 87898684Sdes password = read_passphrase(prompt, RP_ALLOW_EOF); 87998684Sdes if (password == NULL) { 88098684Sdes /* bail out */ 88198684Sdes return; 88298684Sdes } 88398684Sdes snprintf(prompt, sizeof(prompt), 88498684Sdes "Retype %.30s@%.128s's new password: ", 885204917Sdes authctxt->server_user, host); 88698684Sdes retype = read_passphrase(prompt, 0); 88798684Sdes if (strcmp(password, retype) != 0) { 88898684Sdes memset(password, 0, strlen(password)); 88998684Sdes xfree(password); 890124211Sdes logit("Mismatch; try again, EOF to quit."); 89198684Sdes password = NULL; 89298684Sdes } 89398684Sdes memset(retype, 0, strlen(retype)); 89498684Sdes xfree(retype); 89598684Sdes } 89698684Sdes packet_put_cstring(password); 89798684Sdes memset(password, 0, strlen(password)); 89898684Sdes xfree(password); 89998684Sdes packet_add_padding(64); 90098684Sdes packet_send(); 90198684Sdes 90298684Sdes dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, 90398684Sdes &input_userauth_passwd_changereq); 90498684Sdes} 90598684Sdes 906192595Sdes#ifdef JPAKE 907192595Sdesstatic char * 908192595Sdespw_encrypt(const char *password, const char *crypt_scheme, const char *salt) 909192595Sdes{ 910192595Sdes /* OpenBSD crypt(3) handles all of these */ 911192595Sdes if (strcmp(crypt_scheme, "crypt") == 0 || 912192595Sdes strcmp(crypt_scheme, "bcrypt") == 0 || 913192595Sdes strcmp(crypt_scheme, "md5crypt") == 0 || 914192595Sdes strcmp(crypt_scheme, "crypt-extended") == 0) 915192595Sdes return xstrdup(crypt(password, salt)); 916192595Sdes error("%s: unsupported password encryption scheme \"%.100s\"", 917192595Sdes __func__, crypt_scheme); 918192595Sdes return NULL; 919192595Sdes} 920192595Sdes 921192595Sdesstatic BIGNUM * 922192595Sdesjpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme, 923192595Sdes const char *salt) 924192595Sdes{ 925192595Sdes char prompt[256], *password, *crypted; 926192595Sdes u_char *secret; 927192595Sdes u_int secret_len; 928192595Sdes BIGNUM *ret; 929192595Sdes 930192595Sdes snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ", 931192595Sdes authctxt->server_user, authctxt->host); 932192595Sdes password = read_passphrase(prompt, 0); 933192595Sdes 934192595Sdes if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) { 935192595Sdes logit("Disabling %s authentication", authctxt->method->name); 936192595Sdes authctxt->method->enabled = NULL; 937192595Sdes /* Continue with an empty password to fail gracefully */ 938192595Sdes crypted = xstrdup(""); 939192595Sdes } 940192595Sdes 941192595Sdes#ifdef JPAKE_DEBUG 942192595Sdes debug3("%s: salt = %s", __func__, salt); 943192595Sdes debug3("%s: scheme = %s", __func__, crypt_scheme); 944192595Sdes debug3("%s: crypted = %s", __func__, crypted); 945192595Sdes#endif 946192595Sdes 947192595Sdes if (hash_buffer(crypted, strlen(crypted), EVP_sha256(), 948192595Sdes &secret, &secret_len) != 0) 949192595Sdes fatal("%s: hash_buffer", __func__); 950192595Sdes 951192595Sdes bzero(password, strlen(password)); 952192595Sdes bzero(crypted, strlen(crypted)); 953192595Sdes xfree(password); 954192595Sdes xfree(crypted); 955192595Sdes 956192595Sdes if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL) 957192595Sdes fatal("%s: BN_bin2bn (secret)", __func__); 958192595Sdes bzero(secret, secret_len); 959192595Sdes xfree(secret); 960192595Sdes 961192595Sdes return ret; 962192595Sdes} 963192595Sdes 964192595Sdes/* ARGSUSED */ 965192595Sdesvoid 966192595Sdesinput_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt) 967192595Sdes{ 968192595Sdes Authctxt *authctxt = ctxt; 969192595Sdes struct jpake_ctx *pctx = authctxt->methoddata; 970192595Sdes u_char *x3_proof, *x4_proof, *x2_s_proof; 971192595Sdes u_int x3_proof_len, x4_proof_len, x2_s_proof_len; 972192595Sdes char *crypt_scheme, *salt; 973192595Sdes 974192595Sdes /* Disable this message */ 975192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL); 976192595Sdes 977192595Sdes if ((pctx->g_x3 = BN_new()) == NULL || 978192595Sdes (pctx->g_x4 = BN_new()) == NULL) 979192595Sdes fatal("%s: BN_new", __func__); 980192595Sdes 981192595Sdes /* Fetch step 1 values */ 982192595Sdes crypt_scheme = packet_get_string(NULL); 983192595Sdes salt = packet_get_string(NULL); 984192595Sdes pctx->server_id = packet_get_string(&pctx->server_id_len); 985192595Sdes packet_get_bignum2(pctx->g_x3); 986192595Sdes packet_get_bignum2(pctx->g_x4); 987192595Sdes x3_proof = packet_get_string(&x3_proof_len); 988192595Sdes x4_proof = packet_get_string(&x4_proof_len); 989192595Sdes packet_check_eom(); 990192595Sdes 991192595Sdes JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__)); 992192595Sdes 993192595Sdes /* Obtain password and derive secret */ 994192595Sdes pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt); 995192595Sdes bzero(crypt_scheme, strlen(crypt_scheme)); 996192595Sdes bzero(salt, strlen(salt)); 997192595Sdes xfree(crypt_scheme); 998192595Sdes xfree(salt); 999192595Sdes JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__)); 1000192595Sdes 1001192595Sdes /* Calculate step 2 values */ 1002192595Sdes jpake_step2(pctx->grp, pctx->s, pctx->g_x1, 1003192595Sdes pctx->g_x3, pctx->g_x4, pctx->x2, 1004192595Sdes pctx->server_id, pctx->server_id_len, 1005192595Sdes pctx->client_id, pctx->client_id_len, 1006192595Sdes x3_proof, x3_proof_len, 1007192595Sdes x4_proof, x4_proof_len, 1008192595Sdes &pctx->a, 1009192595Sdes &x2_s_proof, &x2_s_proof_len); 1010192595Sdes 1011192595Sdes bzero(x3_proof, x3_proof_len); 1012192595Sdes bzero(x4_proof, x4_proof_len); 1013192595Sdes xfree(x3_proof); 1014192595Sdes xfree(x4_proof); 1015192595Sdes 1016192595Sdes JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__)); 1017192595Sdes 1018192595Sdes /* Send values for step 2 */ 1019192595Sdes packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2); 1020192595Sdes packet_put_bignum2(pctx->a); 1021192595Sdes packet_put_string(x2_s_proof, x2_s_proof_len); 1022192595Sdes packet_send(); 1023192595Sdes 1024192595Sdes bzero(x2_s_proof, x2_s_proof_len); 1025192595Sdes xfree(x2_s_proof); 1026192595Sdes 1027192595Sdes /* Expect step 2 packet from peer */ 1028192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, 1029192595Sdes input_userauth_jpake_server_step2); 1030192595Sdes} 1031192595Sdes 1032192595Sdes/* ARGSUSED */ 1033192595Sdesvoid 1034192595Sdesinput_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt) 1035192595Sdes{ 1036192595Sdes Authctxt *authctxt = ctxt; 1037192595Sdes struct jpake_ctx *pctx = authctxt->methoddata; 1038192595Sdes u_char *x4_s_proof; 1039192595Sdes u_int x4_s_proof_len; 1040192595Sdes 1041192595Sdes /* Disable this message */ 1042192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL); 1043192595Sdes 1044192595Sdes if ((pctx->b = BN_new()) == NULL) 1045192595Sdes fatal("%s: BN_new", __func__); 1046192595Sdes 1047192595Sdes /* Fetch step 2 values */ 1048192595Sdes packet_get_bignum2(pctx->b); 1049192595Sdes x4_s_proof = packet_get_string(&x4_s_proof_len); 1050192595Sdes packet_check_eom(); 1051192595Sdes 1052192595Sdes JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__)); 1053192595Sdes 1054192595Sdes /* Derive shared key and calculate confirmation hash */ 1055192595Sdes jpake_key_confirm(pctx->grp, pctx->s, pctx->b, 1056192595Sdes pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4, 1057192595Sdes pctx->client_id, pctx->client_id_len, 1058192595Sdes pctx->server_id, pctx->server_id_len, 1059192595Sdes session_id2, session_id2_len, 1060192595Sdes x4_s_proof, x4_s_proof_len, 1061192595Sdes &pctx->k, 1062192595Sdes &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len); 1063192595Sdes 1064192595Sdes bzero(x4_s_proof, x4_s_proof_len); 1065192595Sdes xfree(x4_s_proof); 1066192595Sdes 1067192595Sdes JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__)); 1068192595Sdes 1069192595Sdes /* Send key confirmation proof */ 1070192595Sdes packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM); 1071192595Sdes packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len); 1072192595Sdes packet_send(); 1073192595Sdes 1074192595Sdes /* Expect confirmation from peer */ 1075192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, 1076192595Sdes input_userauth_jpake_server_confirm); 1077192595Sdes} 1078192595Sdes 1079192595Sdes/* ARGSUSED */ 1080192595Sdesvoid 1081192595Sdesinput_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt) 1082192595Sdes{ 1083192595Sdes Authctxt *authctxt = ctxt; 1084192595Sdes struct jpake_ctx *pctx = authctxt->methoddata; 1085192595Sdes 1086192595Sdes /* Disable this message */ 1087192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL); 1088192595Sdes 1089192595Sdes pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len); 1090192595Sdes packet_check_eom(); 1091192595Sdes 1092192595Sdes JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__)); 1093192595Sdes 1094192595Sdes /* Verify expected confirmation hash */ 1095192595Sdes if (jpake_check_confirm(pctx->k, 1096192595Sdes pctx->server_id, pctx->server_id_len, 1097192595Sdes session_id2, session_id2_len, 1098192595Sdes pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1) 1099192595Sdes debug("%s: %s success", __func__, authctxt->method->name); 1100192595Sdes else { 1101192595Sdes debug("%s: confirmation mismatch", __func__); 1102192595Sdes /* XXX stash this so if auth succeeds then we can warn/kill */ 1103192595Sdes } 1104192595Sdes 1105192595Sdes userauth_jpake_cleanup(authctxt); 1106192595Sdes} 1107192595Sdes#endif /* JPAKE */ 1108192595Sdes 1109124211Sdesstatic int 1110124211Sdesidentity_sign(Identity *id, u_char **sigp, u_int *lenp, 1111124211Sdes u_char *data, u_int datalen) 111276262Sgreen{ 1113124211Sdes Key *prv; 1114124211Sdes int ret; 111598684Sdes 1116124211Sdes /* the agent supports this key */ 1117124211Sdes if (id->ac) 1118124211Sdes return (ssh_agent_sign(id->ac, id->key, sigp, lenp, 1119124211Sdes data, datalen)); 1120124211Sdes /* 1121124211Sdes * we have already loaded the private key or 1122124211Sdes * the private key is stored in external hardware 1123124211Sdes */ 1124124211Sdes if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) 1125124211Sdes return (key_sign(id->key, sigp, lenp, data, datalen)); 1126124211Sdes /* load the private key from the file */ 1127124211Sdes if ((prv = load_identity_file(id->filename)) == NULL) 1128124211Sdes return (-1); 1129124211Sdes ret = key_sign(prv, sigp, lenp, data, datalen); 1130124211Sdes key_free(prv); 1131124211Sdes return (ret); 113276262Sgreen} 113376262Sgreen 113492559Sdesstatic int 1135124211Sdessign_and_send_pubkey(Authctxt *authctxt, Identity *id) 113660573Skris{ 113760573Skris Buffer b; 113876262Sgreen u_char *blob, *signature; 113992559Sdes u_int bloblen, slen; 1140124211Sdes u_int skip = 0; 114165668Skris int ret = -1; 114269587Sgreen int have_sig = 1; 1143215116Sdes char *fp; 114460573Skris 1145215116Sdes fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); 1146215116Sdes debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); 1147215116Sdes xfree(fp); 114860573Skris 1149124211Sdes if (key_to_blob(id->key, &blob, &bloblen) == 0) { 115076262Sgreen /* we cannot handle this key */ 115176262Sgreen debug3("sign_and_send_pubkey: cannot handle key"); 115276262Sgreen return 0; 115376262Sgreen } 115460573Skris /* data to be signed */ 115560573Skris buffer_init(&b); 115669587Sgreen if (datafellows & SSH_OLD_SESSIONID) { 115769587Sgreen buffer_append(&b, session_id2, session_id2_len); 115876262Sgreen skip = session_id2_len; 115969587Sgreen } else { 116065668Skris buffer_put_string(&b, session_id2, session_id2_len); 116165668Skris skip = buffer_len(&b); 116265668Skris } 116360573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 116469587Sgreen buffer_put_cstring(&b, authctxt->server_user); 116560573Skris buffer_put_cstring(&b, 116676262Sgreen datafellows & SSH_BUG_PKSERVICE ? 116760573Skris "ssh-userauth" : 116869587Sgreen authctxt->service); 116976262Sgreen if (datafellows & SSH_BUG_PKAUTH) { 117076262Sgreen buffer_put_char(&b, have_sig); 117176262Sgreen } else { 117276262Sgreen buffer_put_cstring(&b, authctxt->method->name); 117376262Sgreen buffer_put_char(&b, have_sig); 1174124211Sdes buffer_put_cstring(&b, key_ssh_name(id->key)); 117576262Sgreen } 117660573Skris buffer_put_string(&b, blob, bloblen); 117760573Skris 117860573Skris /* generate signature */ 1179124211Sdes ret = identity_sign(id, &signature, &slen, 118076262Sgreen buffer_ptr(&b), buffer_len(&b)); 118165668Skris if (ret == -1) { 118265668Skris xfree(blob); 118365668Skris buffer_free(&b); 118465668Skris return 0; 118565668Skris } 118676262Sgreen#ifdef DEBUG_PK 118760573Skris buffer_dump(&b); 118860573Skris#endif 118976262Sgreen if (datafellows & SSH_BUG_PKSERVICE) { 119060573Skris buffer_clear(&b); 119160573Skris buffer_append(&b, session_id2, session_id2_len); 119276262Sgreen skip = session_id2_len; 119360573Skris buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 119469587Sgreen buffer_put_cstring(&b, authctxt->server_user); 119569587Sgreen buffer_put_cstring(&b, authctxt->service); 119669587Sgreen buffer_put_cstring(&b, authctxt->method->name); 119769587Sgreen buffer_put_char(&b, have_sig); 119876262Sgreen if (!(datafellows & SSH_BUG_PKAUTH)) 1199124211Sdes buffer_put_cstring(&b, key_ssh_name(id->key)); 120060573Skris buffer_put_string(&b, blob, bloblen); 120160573Skris } 120260573Skris xfree(blob); 120376262Sgreen 120460573Skris /* append signature */ 120560573Skris buffer_put_string(&b, signature, slen); 120660573Skris xfree(signature); 120760573Skris 120860573Skris /* skip session id and packet type */ 120965668Skris if (buffer_len(&b) < skip + 1) 121069587Sgreen fatal("userauth_pubkey: internal error"); 121165668Skris buffer_consume(&b, skip + 1); 121260573Skris 121360573Skris /* put remaining data from buffer into packet */ 121460573Skris packet_start(SSH2_MSG_USERAUTH_REQUEST); 121560573Skris packet_put_raw(buffer_ptr(&b), buffer_len(&b)); 121660573Skris buffer_free(&b); 121760573Skris packet_send(); 121865668Skris 121960573Skris return 1; 122060573Skris} 122160573Skris 122292559Sdesstatic int 1223124211Sdessend_pubkey_test(Authctxt *authctxt, Identity *id) 122469587Sgreen{ 122576262Sgreen u_char *blob; 122692559Sdes u_int bloblen, have_sig = 0; 122776262Sgreen 122876262Sgreen debug3("send_pubkey_test"); 122976262Sgreen 1230124211Sdes if (key_to_blob(id->key, &blob, &bloblen) == 0) { 123176262Sgreen /* we cannot handle this key */ 123276262Sgreen debug3("send_pubkey_test: cannot handle key"); 123376262Sgreen return 0; 123476262Sgreen } 123576262Sgreen /* register callback for USERAUTH_PK_OK message */ 123676262Sgreen dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); 123776262Sgreen 123876262Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 123976262Sgreen packet_put_cstring(authctxt->server_user); 124076262Sgreen packet_put_cstring(authctxt->service); 124176262Sgreen packet_put_cstring(authctxt->method->name); 124276262Sgreen packet_put_char(have_sig); 124376262Sgreen if (!(datafellows & SSH_BUG_PKAUTH)) 1244124211Sdes packet_put_cstring(key_ssh_name(id->key)); 124576262Sgreen packet_put_string(blob, bloblen); 124676262Sgreen xfree(blob); 124776262Sgreen packet_send(); 124876262Sgreen return 1; 124969587Sgreen} 125069587Sgreen 125192559Sdesstatic Key * 125276262Sgreenload_identity_file(char *filename) 125365668Skris{ 125476262Sgreen Key *private; 125576262Sgreen char prompt[300], *passphrase; 1256204917Sdes int perm_ok = 0, quit, i; 125765668Skris struct stat st; 125865668Skris 125976262Sgreen if (stat(filename, &st) < 0) { 126076262Sgreen debug3("no such identity: %s", filename); 126176262Sgreen return NULL; 126265668Skris } 1263162856Sdes private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); 1264162856Sdes if (!perm_ok) 1265162856Sdes return NULL; 126676262Sgreen if (private == NULL) { 126776262Sgreen if (options.batch_mode) 126876262Sgreen return NULL; 126965668Skris snprintf(prompt, sizeof prompt, 127092559Sdes "Enter passphrase for key '%.100s': ", filename); 127169587Sgreen for (i = 0; i < options.number_of_password_prompts; i++) { 127269587Sgreen passphrase = read_passphrase(prompt, 0); 127369587Sgreen if (strcmp(passphrase, "") != 0) { 1274162856Sdes private = key_load_private_type(KEY_UNSPEC, 1275162856Sdes filename, passphrase, NULL, NULL); 127676262Sgreen quit = 0; 127769587Sgreen } else { 127869587Sgreen debug2("no passphrase given, try next key"); 127976262Sgreen quit = 1; 128069587Sgreen } 128169587Sgreen memset(passphrase, 0, strlen(passphrase)); 128269587Sgreen xfree(passphrase); 128376262Sgreen if (private != NULL || quit) 128469587Sgreen break; 128569587Sgreen debug2("bad passphrase given, try again..."); 128669587Sgreen } 128765668Skris } 128876262Sgreen return private; 128976262Sgreen} 129076262Sgreen 1291124211Sdes/* 1292124211Sdes * try keys in the following order: 1293124211Sdes * 1. agent keys that are found in the config file 1294124211Sdes * 2. other agent keys 1295124211Sdes * 3. keys that are only listed in the config file 1296124211Sdes */ 1297124211Sdesstatic void 1298124211Sdespubkey_prepare(Authctxt *authctxt) 129976262Sgreen{ 1300124211Sdes Identity *id; 1301124211Sdes Idlist agent, files, *preferred; 1302124211Sdes Key *key; 1303124211Sdes AuthenticationConnection *ac; 1304124211Sdes char *comment; 1305124211Sdes int i, found; 130676262Sgreen 1307124211Sdes TAILQ_INIT(&agent); /* keys from the agent */ 1308124211Sdes TAILQ_INIT(&files); /* keys from the config file */ 1309124211Sdes preferred = &authctxt->keys; 1310124211Sdes TAILQ_INIT(preferred); /* preferred order of keys */ 131192559Sdes 1312124211Sdes /* list of keys stored in the filesystem */ 1313124211Sdes for (i = 0; i < options.num_identity_files; i++) { 1314124211Sdes key = options.identity_keys[i]; 1315124211Sdes if (key && key->type == KEY_RSA1) 1316124211Sdes continue; 1317204917Sdes if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) 1318204917Sdes continue; 1319124211Sdes options.identity_keys[i] = NULL; 1320162856Sdes id = xcalloc(1, sizeof(*id)); 1321124211Sdes id->key = key; 1322124211Sdes id->filename = xstrdup(options.identity_files[i]); 1323124211Sdes TAILQ_INSERT_TAIL(&files, id, next); 1324124211Sdes } 1325124211Sdes /* list of keys supported by the agent */ 1326124211Sdes if ((ac = ssh_get_authentication_connection())) { 1327124211Sdes for (key = ssh_get_first_identity(ac, &comment, 2); 1328124211Sdes key != NULL; 1329124211Sdes key = ssh_get_next_identity(ac, &comment, 2)) { 1330124211Sdes found = 0; 1331124211Sdes TAILQ_FOREACH(id, &files, next) { 1332126277Sdes /* agent keys from the config file are preferred */ 1333124211Sdes if (key_equal(key, id->key)) { 1334124211Sdes key_free(key); 1335124211Sdes xfree(comment); 1336124211Sdes TAILQ_REMOVE(&files, id, next); 1337124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1338124211Sdes id->ac = ac; 1339124211Sdes found = 1; 1340124211Sdes break; 1341124211Sdes } 1342124211Sdes } 1343128460Sdes if (!found && !options.identities_only) { 1344162856Sdes id = xcalloc(1, sizeof(*id)); 1345124211Sdes id->key = key; 1346124211Sdes id->filename = comment; 1347124211Sdes id->ac = ac; 1348124211Sdes TAILQ_INSERT_TAIL(&agent, id, next); 1349124211Sdes } 1350124211Sdes } 1351124211Sdes /* append remaining agent keys */ 1352124211Sdes for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { 1353124211Sdes TAILQ_REMOVE(&agent, id, next); 1354124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1355124211Sdes } 1356124211Sdes authctxt->agent = ac; 1357124211Sdes } 1358124211Sdes /* append remaining keys from the config file */ 1359124211Sdes for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { 1360124211Sdes TAILQ_REMOVE(&files, id, next); 1361124211Sdes TAILQ_INSERT_TAIL(preferred, id, next); 1362124211Sdes } 1363124211Sdes TAILQ_FOREACH(id, preferred, next) { 1364124211Sdes debug2("key: %s (%p)", id->filename, id->key); 1365124211Sdes } 136665668Skris} 136765668Skris 1368124211Sdesstatic void 1369124211Sdespubkey_cleanup(Authctxt *authctxt) 137065668Skris{ 1371124211Sdes Identity *id; 137265668Skris 1373124211Sdes if (authctxt->agent != NULL) 1374124211Sdes ssh_close_authentication_connection(authctxt->agent); 1375124211Sdes for (id = TAILQ_FIRST(&authctxt->keys); id; 1376124211Sdes id = TAILQ_FIRST(&authctxt->keys)) { 1377124211Sdes TAILQ_REMOVE(&authctxt->keys, id, next); 1378124211Sdes if (id->key) 1379124211Sdes key_free(id->key); 1380124211Sdes if (id->filename) 1381124211Sdes xfree(id->filename); 1382124211Sdes xfree(id); 138365668Skris } 138465668Skris} 138565668Skris 138669587Sgreenint 138769587Sgreenuserauth_pubkey(Authctxt *authctxt) 138869587Sgreen{ 1389124211Sdes Identity *id; 139069587Sgreen int sent = 0; 139169587Sgreen 1392124211Sdes while ((id = TAILQ_FIRST(&authctxt->keys))) { 1393124211Sdes if (id->tried++) 1394124211Sdes return (0); 1395126277Sdes /* move key to the end of the queue */ 1396124211Sdes TAILQ_REMOVE(&authctxt->keys, id, next); 1397124211Sdes TAILQ_INSERT_TAIL(&authctxt->keys, id, next); 1398124211Sdes /* 1399124211Sdes * send a test message if we have the public key. for 1400124211Sdes * encrypted keys we cannot do this and have to load the 1401124211Sdes * private key instead 1402124211Sdes */ 1403124211Sdes if (id->key && id->key->type != KEY_RSA1) { 1404215116Sdes debug("Offering %s public key: %s", key_type(id->key), 1405215116Sdes id->filename); 1406124211Sdes sent = send_pubkey_test(authctxt, id); 1407124211Sdes } else if (id->key == NULL) { 1408124211Sdes debug("Trying private key: %s", id->filename); 1409124211Sdes id->key = load_identity_file(id->filename); 1410124211Sdes if (id->key != NULL) { 1411124211Sdes id->isprivate = 1; 1412124211Sdes sent = sign_and_send_pubkey(authctxt, id); 1413124211Sdes key_free(id->key); 1414124211Sdes id->key = NULL; 141576262Sgreen } 141676262Sgreen } 1417124211Sdes if (sent) 1418124211Sdes return (sent); 141976262Sgreen } 1420124211Sdes return (0); 142169587Sgreen} 142269587Sgreen 142369587Sgreen/* 142469587Sgreen * Send userauth request message specifying keyboard-interactive method. 142569587Sgreen */ 142669587Sgreenint 142769587Sgreenuserauth_kbdint(Authctxt *authctxt) 142869587Sgreen{ 142969587Sgreen static int attempt = 0; 143069587Sgreen 143169587Sgreen if (attempt++ >= options.number_of_password_prompts) 143269587Sgreen return 0; 143392559Sdes /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ 143492559Sdes if (attempt > 1 && !authctxt->info_req_seen) { 143592559Sdes debug3("userauth_kbdint: disable: no info_req_seen"); 143692559Sdes dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); 143792559Sdes return 0; 143892559Sdes } 143969587Sgreen 144069587Sgreen debug2("userauth_kbdint"); 144169587Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 144269587Sgreen packet_put_cstring(authctxt->server_user); 144369587Sgreen packet_put_cstring(authctxt->service); 144469587Sgreen packet_put_cstring(authctxt->method->name); 144569587Sgreen packet_put_cstring(""); /* lang */ 144669587Sgreen packet_put_cstring(options.kbd_interactive_devices ? 144769587Sgreen options.kbd_interactive_devices : ""); 144869587Sgreen packet_send(); 144969587Sgreen 145069587Sgreen dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); 145169587Sgreen return 1; 145269587Sgreen} 145369587Sgreen 145469587Sgreen/* 145576262Sgreen * parse INFO_REQUEST, prompt user and send INFO_RESPONSE 145669587Sgreen */ 145760573Skrisvoid 145892559Sdesinput_userauth_info_req(int type, u_int32_t seq, void *ctxt) 145960573Skris{ 146069587Sgreen Authctxt *authctxt = ctxt; 146176262Sgreen char *name, *inst, *lang, *prompt, *response; 146276262Sgreen u_int num_prompts, i; 146369587Sgreen int echo = 0; 146460573Skris 146569587Sgreen debug2("input_userauth_info_req"); 146669587Sgreen 146769587Sgreen if (authctxt == NULL) 146869587Sgreen fatal("input_userauth_info_req: no authentication context"); 146969587Sgreen 147092559Sdes authctxt->info_req_seen = 1; 147192559Sdes 147269587Sgreen name = packet_get_string(NULL); 147369587Sgreen inst = packet_get_string(NULL); 147469587Sgreen lang = packet_get_string(NULL); 147569587Sgreen if (strlen(name) > 0) 1476124211Sdes logit("%s", name); 147769587Sgreen if (strlen(inst) > 0) 1478124211Sdes logit("%s", inst); 147976262Sgreen xfree(name); 148069587Sgreen xfree(inst); 148176262Sgreen xfree(lang); 148269587Sgreen 148369587Sgreen num_prompts = packet_get_int(); 148469587Sgreen /* 148569587Sgreen * Begin to build info response packet based on prompts requested. 148669587Sgreen * We commit to providing the correct number of responses, so if 148769587Sgreen * further on we run into a problem that prevents this, we have to 148869587Sgreen * be sure and clean this up and send a correct error response. 148969587Sgreen */ 149069587Sgreen packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); 149169587Sgreen packet_put_int(num_prompts); 149269587Sgreen 149392559Sdes debug2("input_userauth_info_req: num_prompts %d", num_prompts); 149469587Sgreen for (i = 0; i < num_prompts; i++) { 149569587Sgreen prompt = packet_get_string(NULL); 149669587Sgreen echo = packet_get_char(); 149769587Sgreen 149892559Sdes response = read_passphrase(prompt, echo ? RP_ECHO : 0); 149969587Sgreen 150093704Sdes packet_put_cstring(response); 150169587Sgreen memset(response, 0, strlen(response)); 150269587Sgreen xfree(response); 150369587Sgreen xfree(prompt); 150469587Sgreen } 150592559Sdes packet_check_eom(); /* done with parsing incoming message. */ 150669587Sgreen 150792559Sdes packet_add_padding(64); 150860573Skris packet_send(); 150969587Sgreen} 151060573Skris 151198684Sdesstatic int 151299063Sdesssh_keysign(Key *key, u_char **sigp, u_int *lenp, 151398684Sdes u_char *data, u_int datalen) 151498684Sdes{ 151598684Sdes Buffer b; 151698684Sdes struct stat st; 151798684Sdes pid_t pid; 151898684Sdes int to[2], from[2], status, version = 2; 151998684Sdes 1520113911Sdes debug2("ssh_keysign called"); 152198684Sdes 152298684Sdes if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { 1523204917Sdes error("ssh_keysign: not installed: %s", strerror(errno)); 152498684Sdes return -1; 152598684Sdes } 152698684Sdes if (fflush(stdout) != 0) 152798684Sdes error("ssh_keysign: fflush: %s", strerror(errno)); 152898684Sdes if (pipe(to) < 0) { 152998684Sdes error("ssh_keysign: pipe: %s", strerror(errno)); 153098684Sdes return -1; 153198684Sdes } 153298684Sdes if (pipe(from) < 0) { 153398684Sdes error("ssh_keysign: pipe: %s", strerror(errno)); 153498684Sdes return -1; 153598684Sdes } 153698684Sdes if ((pid = fork()) < 0) { 153798684Sdes error("ssh_keysign: fork: %s", strerror(errno)); 153898684Sdes return -1; 153998684Sdes } 154098684Sdes if (pid == 0) { 1541204917Sdes /* keep the socket on exec */ 1542204917Sdes fcntl(packet_get_connection_in(), F_SETFD, 0); 1543162856Sdes permanently_drop_suid(getuid()); 154498684Sdes close(from[0]); 154598684Sdes if (dup2(from[1], STDOUT_FILENO) < 0) 154698684Sdes fatal("ssh_keysign: dup2: %s", strerror(errno)); 154798684Sdes close(to[1]); 154898684Sdes if (dup2(to[0], STDIN_FILENO) < 0) 154998684Sdes fatal("ssh_keysign: dup2: %s", strerror(errno)); 155098684Sdes close(from[1]); 155198684Sdes close(to[0]); 155298684Sdes execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); 155398684Sdes fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, 155498684Sdes strerror(errno)); 155598684Sdes } 155698684Sdes close(from[1]); 155798684Sdes close(to[0]); 155898684Sdes 155998684Sdes buffer_init(&b); 156098684Sdes buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ 156198684Sdes buffer_put_string(&b, data, datalen); 1562126277Sdes if (ssh_msg_send(to[1], version, &b) == -1) 1563126277Sdes fatal("ssh_keysign: couldn't send request"); 156498684Sdes 1565106130Sdes if (ssh_msg_recv(from[0], &b) < 0) { 156698684Sdes error("ssh_keysign: no reply"); 1567126277Sdes buffer_free(&b); 156898684Sdes return -1; 156998684Sdes } 157098684Sdes close(from[0]); 157198684Sdes close(to[1]); 157298684Sdes 157398684Sdes while (waitpid(pid, &status, 0) < 0) 157498684Sdes if (errno != EINTR) 157598684Sdes break; 157698684Sdes 157798684Sdes if (buffer_get_char(&b) != version) { 157898684Sdes error("ssh_keysign: bad version"); 1579126277Sdes buffer_free(&b); 158098684Sdes return -1; 158198684Sdes } 158298684Sdes *sigp = buffer_get_string(&b, lenp); 1583126277Sdes buffer_free(&b); 158498684Sdes 158598684Sdes return 0; 158698684Sdes} 158798684Sdes 158876262Sgreenint 158976262Sgreenuserauth_hostbased(Authctxt *authctxt) 159069587Sgreen{ 159176262Sgreen Key *private = NULL; 159298684Sdes Sensitive *sensitive = authctxt->sensitive; 159376262Sgreen Buffer b; 159476262Sgreen u_char *signature, *blob; 1595204917Sdes char *chost, *pkalg, *p; 159676262Sgreen const char *service; 159776262Sgreen u_int blen, slen; 1598204917Sdes int ok, i, found = 0; 159976262Sgreen 160076262Sgreen /* check for a useful key */ 160198684Sdes for (i = 0; i < sensitive->nkeys; i++) { 160298684Sdes private = sensitive->keys[i]; 160376262Sgreen if (private && private->type != KEY_RSA1) { 160476262Sgreen found = 1; 160576262Sgreen /* we take and free the key */ 160698684Sdes sensitive->keys[i] = NULL; 160776262Sgreen break; 160876262Sgreen } 160969587Sgreen } 161076262Sgreen if (!found) { 1611113911Sdes debug("No more client hostkeys for hostbased authentication."); 161276262Sgreen return 0; 161369587Sgreen } 161476262Sgreen if (key_to_blob(private, &blob, &blen) == 0) { 161576262Sgreen key_free(private); 161676262Sgreen return 0; 161776262Sgreen } 161892559Sdes /* figure out a name for the client host */ 1619204917Sdes p = get_local_name(packet_get_connection_in()); 162092559Sdes if (p == NULL) { 162192559Sdes error("userauth_hostbased: cannot get local ipaddr/name"); 162292559Sdes key_free(private); 1623162856Sdes xfree(blob); 162492559Sdes return 0; 162592559Sdes } 1626162856Sdes xasprintf(&chost, "%s.", p); 162792559Sdes debug2("userauth_hostbased: chost %s", chost); 1628113911Sdes xfree(p); 162992559Sdes 163076262Sgreen service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : 163176262Sgreen authctxt->service; 163276262Sgreen pkalg = xstrdup(key_ssh_name(private)); 163376262Sgreen buffer_init(&b); 163476262Sgreen /* construct data */ 163576262Sgreen buffer_put_string(&b, session_id2, session_id2_len); 163676262Sgreen buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 163776262Sgreen buffer_put_cstring(&b, authctxt->server_user); 163876262Sgreen buffer_put_cstring(&b, service); 163976262Sgreen buffer_put_cstring(&b, authctxt->method->name); 164076262Sgreen buffer_put_cstring(&b, pkalg); 164176262Sgreen buffer_put_string(&b, blob, blen); 164276262Sgreen buffer_put_cstring(&b, chost); 164376262Sgreen buffer_put_cstring(&b, authctxt->local_user); 164476262Sgreen#ifdef DEBUG_PK 164576262Sgreen buffer_dump(&b); 164676262Sgreen#endif 164798684Sdes if (sensitive->external_keysign) 164898684Sdes ok = ssh_keysign(private, &signature, &slen, 164998684Sdes buffer_ptr(&b), buffer_len(&b)); 165098684Sdes else 165198684Sdes ok = key_sign(private, &signature, &slen, 165298684Sdes buffer_ptr(&b), buffer_len(&b)); 165376262Sgreen key_free(private); 165476262Sgreen buffer_free(&b); 165576262Sgreen if (ok != 0) { 165676262Sgreen error("key_sign failed"); 165776262Sgreen xfree(chost); 165876262Sgreen xfree(pkalg); 1659162856Sdes xfree(blob); 166076262Sgreen return 0; 166176262Sgreen } 166276262Sgreen packet_start(SSH2_MSG_USERAUTH_REQUEST); 166376262Sgreen packet_put_cstring(authctxt->server_user); 166476262Sgreen packet_put_cstring(authctxt->service); 166576262Sgreen packet_put_cstring(authctxt->method->name); 166676262Sgreen packet_put_cstring(pkalg); 166776262Sgreen packet_put_string(blob, blen); 166876262Sgreen packet_put_cstring(chost); 166976262Sgreen packet_put_cstring(authctxt->local_user); 167076262Sgreen packet_put_string(signature, slen); 167176262Sgreen memset(signature, 's', slen); 167276262Sgreen xfree(signature); 167376262Sgreen xfree(chost); 167476262Sgreen xfree(pkalg); 1675162856Sdes xfree(blob); 167676262Sgreen 167776262Sgreen packet_send(); 167876262Sgreen return 1; 167969587Sgreen} 168069587Sgreen 1681192595Sdes#ifdef JPAKE 1682192595Sdesint 1683192595Sdesuserauth_jpake(Authctxt *authctxt) 1684192595Sdes{ 1685192595Sdes struct jpake_ctx *pctx; 1686192595Sdes u_char *x1_proof, *x2_proof; 1687192595Sdes u_int x1_proof_len, x2_proof_len; 1688192595Sdes static int attempt = 0; /* XXX share with userauth_password's? */ 1689192595Sdes 1690192595Sdes if (attempt++ >= options.number_of_password_prompts) 1691192595Sdes return 0; 1692192595Sdes if (attempt != 1) 1693192595Sdes error("Permission denied, please try again."); 1694192595Sdes 1695192595Sdes if (authctxt->methoddata != NULL) 1696192595Sdes fatal("%s: authctxt->methoddata already set (%p)", 1697192595Sdes __func__, authctxt->methoddata); 1698192595Sdes 1699192595Sdes authctxt->methoddata = pctx = jpake_new(); 1700192595Sdes 1701192595Sdes /* 1702192595Sdes * Send request immediately, to get the protocol going while 1703192595Sdes * we do the initial computations. 1704192595Sdes */ 1705192595Sdes packet_start(SSH2_MSG_USERAUTH_REQUEST); 1706192595Sdes packet_put_cstring(authctxt->server_user); 1707192595Sdes packet_put_cstring(authctxt->service); 1708192595Sdes packet_put_cstring(authctxt->method->name); 1709192595Sdes packet_send(); 1710192595Sdes packet_write_wait(); 1711192595Sdes 1712192595Sdes jpake_step1(pctx->grp, 1713192595Sdes &pctx->client_id, &pctx->client_id_len, 1714192595Sdes &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2, 1715192595Sdes &x1_proof, &x1_proof_len, 1716192595Sdes &x2_proof, &x2_proof_len); 1717192595Sdes 1718192595Sdes JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__)); 1719192595Sdes 1720192595Sdes packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1); 1721192595Sdes packet_put_string(pctx->client_id, pctx->client_id_len); 1722192595Sdes packet_put_bignum2(pctx->g_x1); 1723192595Sdes packet_put_bignum2(pctx->g_x2); 1724192595Sdes packet_put_string(x1_proof, x1_proof_len); 1725192595Sdes packet_put_string(x2_proof, x2_proof_len); 1726192595Sdes packet_send(); 1727192595Sdes 1728192595Sdes bzero(x1_proof, x1_proof_len); 1729192595Sdes bzero(x2_proof, x2_proof_len); 1730192595Sdes xfree(x1_proof); 1731192595Sdes xfree(x2_proof); 1732192595Sdes 1733192595Sdes /* Expect step 1 packet from peer */ 1734192595Sdes dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, 1735192595Sdes input_userauth_jpake_server_step1); 1736204917Sdes dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, 1737204917Sdes &input_userauth_success_unexpected); 1738192595Sdes 1739192595Sdes return 1; 1740192595Sdes} 1741192595Sdes 1742192595Sdesvoid 1743192595Sdesuserauth_jpake_cleanup(Authctxt *authctxt) 1744192595Sdes{ 1745192595Sdes debug3("%s: clean up", __func__); 1746192595Sdes if (authctxt->methoddata != NULL) { 1747192595Sdes jpake_free(authctxt->methoddata); 1748192595Sdes authctxt->methoddata = NULL; 1749192595Sdes } 1750204917Sdes dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); 1751192595Sdes} 1752192595Sdes#endif /* JPAKE */ 1753192595Sdes 175476262Sgreen/* find auth method */ 175576262Sgreen 175669587Sgreen/* 175769587Sgreen * given auth method name, if configurable options permit this method fill 175869587Sgreen * in auth_ident field and return true, otherwise return false. 175969587Sgreen */ 176092559Sdesstatic int 176169587Sgreenauthmethod_is_enabled(Authmethod *method) 176269587Sgreen{ 176369587Sgreen if (method == NULL) 176469587Sgreen return 0; 176569587Sgreen /* return false if options indicate this method is disabled */ 176669587Sgreen if (method->enabled == NULL || *method->enabled == 0) 176769587Sgreen return 0; 176869587Sgreen /* return false if batch mode is enabled but method needs interactive mode */ 176969587Sgreen if (method->batch_flag != NULL && *method->batch_flag != 0) 177069587Sgreen return 0; 177169587Sgreen return 1; 177269587Sgreen} 177369587Sgreen 177492559Sdesstatic Authmethod * 177569587Sgreenauthmethod_lookup(const char *name) 177669587Sgreen{ 177769587Sgreen Authmethod *method = NULL; 177869587Sgreen if (name != NULL) 177969587Sgreen for (method = authmethods; method->name != NULL; method++) 178069587Sgreen if (strcmp(name, method->name) == 0) 178169587Sgreen return method; 178269587Sgreen debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); 178369587Sgreen return NULL; 178469587Sgreen} 178569587Sgreen 178676262Sgreen/* XXX internal state */ 178776262Sgreenstatic Authmethod *current = NULL; 178876262Sgreenstatic char *supported = NULL; 178976262Sgreenstatic char *preferred = NULL; 179099063Sdes 179169587Sgreen/* 179269587Sgreen * Given the authentication method list sent by the server, return the 179369587Sgreen * next method we should try. If the server initially sends a nil list, 179476262Sgreen * use a built-in default list. 179576262Sgreen */ 179692559Sdesstatic Authmethod * 179769587Sgreenauthmethod_get(char *authlist) 179869587Sgreen{ 179976262Sgreen char *name = NULL; 180092559Sdes u_int next; 180176262Sgreen 180269587Sgreen /* Use a suitable default if we're passed a nil list. */ 180369587Sgreen if (authlist == NULL || strlen(authlist) == 0) 180476262Sgreen authlist = options.preferred_authentications; 180569587Sgreen 180676262Sgreen if (supported == NULL || strcmp(authlist, supported) != 0) { 180776262Sgreen debug3("start over, passed a different list %s", authlist); 180876262Sgreen if (supported != NULL) 180976262Sgreen xfree(supported); 181076262Sgreen supported = xstrdup(authlist); 181176262Sgreen preferred = options.preferred_authentications; 181276262Sgreen debug3("preferred %s", preferred); 181376262Sgreen current = NULL; 181476262Sgreen } else if (current != NULL && authmethod_is_enabled(current)) 181576262Sgreen return current; 181660573Skris 181776262Sgreen for (;;) { 181876262Sgreen if ((name = match_list(preferred, supported, &next)) == NULL) { 1819113911Sdes debug("No more authentication methods to try."); 182076262Sgreen current = NULL; 182176262Sgreen return NULL; 182276262Sgreen } 182376262Sgreen preferred += next; 182469587Sgreen debug3("authmethod_lookup %s", name); 182576262Sgreen debug3("remaining preferred: %s", preferred); 182676262Sgreen if ((current = authmethod_lookup(name)) != NULL && 182776262Sgreen authmethod_is_enabled(current)) { 182869587Sgreen debug3("authmethod_is_enabled %s", name); 1829113911Sdes debug("Next authentication method: %s", name); 183076262Sgreen return current; 183160573Skris } 183260573Skris } 183376262Sgreen} 183469587Sgreen 183592559Sdesstatic char * 183676262Sgreenauthmethods_get(void) 183776262Sgreen{ 183876262Sgreen Authmethod *method = NULL; 183992559Sdes Buffer b; 184092559Sdes char *list; 184169587Sgreen 184292559Sdes buffer_init(&b); 184376262Sgreen for (method = authmethods; method->name != NULL; method++) { 184476262Sgreen if (authmethod_is_enabled(method)) { 184592559Sdes if (buffer_len(&b) > 0) 184692559Sdes buffer_append(&b, ",", 1); 184792559Sdes buffer_append(&b, method->name, strlen(method->name)); 184876262Sgreen } 184976262Sgreen } 185092559Sdes buffer_append(&b, "\0", 1); 185192559Sdes list = xstrdup(buffer_ptr(&b)); 185292559Sdes buffer_free(&b); 185392559Sdes return list; 185460573Skris} 1855192595Sdes 1856