=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshconnect2.c,v retrieving revision 1.10 retrieving revision 1.10.2.2 diff -u -r1.10 -r1.10.2.2 --- src/usr.bin/ssh/sshconnect2.c 2000/05/08 17:42:25 1.10 +++ src/usr.bin/ssh/sshconnect2.c 2000/09/01 18:23:24 1.10.2.2 @@ -28,7 +28,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.10 2000/05/08 17:42:25 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.10.2.2 2000/09/01 18:23:24 jason Exp $"); #include #include @@ -54,6 +54,7 @@ #include "dsa.h" #include "sshconnect.h" #include "authfile.h" +#include "authfd.h" /* import */ extern char *client_version_string; @@ -68,16 +69,11 @@ int session_id2_len = 0; void -ssh_kex2(char *host, struct sockaddr *hostaddr) +ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, + Buffer *client_kexinit, Buffer *server_kexinit) { - Kex *kex; - char *cprop[PROPOSAL_MAX]; - char *sprop[PROPOSAL_MAX]; - Buffer *client_kexinit; - Buffer *server_kexinit; - int payload_len, dlen; + int plen, dlen; unsigned int klen, kout; - char *ptr; char *signature = NULL; unsigned int slen; char *server_host_key_blob = NULL; @@ -86,72 +82,10 @@ DH *dh; BIGNUM *dh_server_pub = 0; BIGNUM *shared_secret = 0; - int i; unsigned char *kbuf; unsigned char *hash; -/* KEXINIT */ - - debug("Sending KEX init."); - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; - } else if (options.cipher == SSH_CIPHER_3DES) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = - cipher_name(SSH_CIPHER_3DES_CBC); - } else if (options.cipher == SSH_CIPHER_BLOWFISH) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = - cipher_name(SSH_CIPHER_BLOWFISH_CBC); - } - if (options.compression) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; - myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; - } else { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; - myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; - } - for (i = 0; i < PROPOSAL_MAX; i++) - cprop[i] = xstrdup(myproposal[i]); - - client_kexinit = kex_init(cprop); - packet_start(SSH2_MSG_KEXINIT); - packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit)); - packet_send(); - packet_write_wait(); - - debug("done"); - - packet_read_expect(&payload_len, SSH2_MSG_KEXINIT); - - /* save payload for session_id */ - server_kexinit = xmalloc(sizeof(*server_kexinit)); - buffer_init(server_kexinit); - ptr = packet_get_raw(&payload_len); - buffer_append(server_kexinit, ptr, payload_len); - - /* skip cookie */ - for (i = 0; i < 16; i++) - (void) packet_get_char(); - /* kex init proposal strings */ - for (i = 0; i < PROPOSAL_MAX; i++) { - sprop[i] = packet_get_string(NULL); - debug("got kexinit string: %s", sprop[i]); - } - i = (int) packet_get_char(); - debug("first kex follow == %d", i); - i = packet_get_int(); - debug("reserved == %d", i); - packet_done(); - - debug("done read kexinit"); - kex = kex_choose_conf(cprop, sprop, 0); - -/* KEXDH */ - debug("Sending SSH2_MSG_KEXDH_INIT."); - /* generate and send 'e', client DH public key */ dh = dh_new_group1(); packet_start(SSH2_MSG_KEXDH_INIT); @@ -172,7 +106,7 @@ debug("Wait SSH2_MSG_KEXDH_REPLY."); - packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY); + packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); debug("Got SSH2_MSG_KEXDH_REPLY."); @@ -233,10 +167,7 @@ shared_secret ); xfree(server_host_key_blob); - buffer_free(client_kexinit); - buffer_free(server_kexinit); - xfree(client_kexinit); - xfree(server_kexinit); + DH_free(dh); #ifdef DEBUG_KEXDH fprintf(stderr, "hash == "); for (i = 0; i< 20; i++) @@ -250,16 +181,61 @@ kex_derive_keys(kex, hash, shared_secret); packet_set_kex(kex); - /* have keys, free DH */ - DH_free(dh); - /* save session id */ session_id2_len = 20; session_id2 = xmalloc(session_id2_len); memcpy(session_id2, hash, session_id2_len); +} +void +ssh_kex2(char *host, struct sockaddr *hostaddr) +{ + int i, plen; + Kex *kex; + Buffer *client_kexinit, *server_kexinit; + char *sprop[PROPOSAL_MAX]; + + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } else if (options.cipher == SSH_CIPHER_3DES) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = + (char *) cipher_name(SSH_CIPHER_3DES_CBC); + } else if (options.cipher == SSH_CIPHER_BLOWFISH) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = + (char *) cipher_name(SSH_CIPHER_BLOWFISH_CBC); + } + if (options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; + myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; + } else { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; + } + + /* buffers with raw kexinit messages */ + server_kexinit = xmalloc(sizeof(*server_kexinit)); + buffer_init(server_kexinit); + client_kexinit = kex_init(myproposal); + + /* algorithm negotiation */ + kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); + kex = kex_choose_conf(myproposal, sprop, 0); + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(sprop[i]); + + /* server authentication and session key agreement */ + ssh_kex_dh(kex, host, hostaddr, client_kexinit, server_kexinit); + + buffer_free(client_kexinit); + buffer_free(server_kexinit); + xfree(client_kexinit); + xfree(server_kexinit); + debug("Wait SSH2_MSG_NEWKEYS."); - packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); + packet_read_expect(&plen, SSH2_MSG_NEWKEYS); packet_done(); debug("GOT SSH2_MSG_NEWKEYS."); @@ -278,6 +254,7 @@ #endif debug("done: KEX2."); } + /* * Authenticate user */ @@ -288,9 +265,12 @@ char prompt[80]; char *password; - if (attempt++ > options.number_of_password_prompts) + if (attempt++ >= options.number_of_password_prompts) return 0; + if(attempt != 1) + error("Permission denied, please try again."); + snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", server_user, host); password = read_passphrase(prompt, 0); @@ -307,42 +287,32 @@ return 1; } +typedef int sign_fn( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen); + int -ssh2_try_pubkey(char *filename, +ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, const char *server_user, const char *host, const char *service) { Buffer b; - Key *k; unsigned char *blob, *signature; int bloblen, slen; - struct stat st; + int skip = 0; + int ret = -1; - if (stat(filename, &st) != 0) { - debug("key does not exist: %s", filename); - return 0; - } - debug("try pubkey: %s", filename); - - k = key_new(KEY_DSA); - if (!load_private_key(filename, "", k, NULL)) { - int success = 0; - char *passphrase; - char prompt[300]; - snprintf(prompt, sizeof prompt, - "Enter passphrase for DSA key '%.100s': ", - filename); - passphrase = read_passphrase(prompt, 0); - success = load_private_key(filename, passphrase, k, NULL); - memset(passphrase, 0, strlen(passphrase)); - xfree(passphrase); - if (!success) - return 0; - } dsa_make_key_blob(k, &blob, &bloblen); /* data to be signed */ buffer_init(&b); - buffer_append(&b, session_id2, session_id2_len); + if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) { + buffer_put_string(&b, session_id2, session_id2_len); + skip = buffer_len(&b); + } else { + buffer_append(&b, session_id2, session_id2_len); + skip = session_id2_len; + } buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, server_user); buffer_put_cstring(&b, @@ -355,13 +325,16 @@ buffer_put_string(&b, blob, bloblen); /* generate signature */ - dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); - key_free(k); + ret = do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); + if (ret == -1) { + xfree(blob); + buffer_free(&b); + return 0; + } #ifdef DEBUG_DSS buffer_dump(&b); #endif if (datafellows & SSH_BUG_PUBKEYAUTH) { - /* e.g. ssh-2.0.13: data-to-be-signed != data-on-the-wire */ buffer_clear(&b); buffer_append(&b, session_id2, session_id2_len); buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); @@ -378,9 +351,9 @@ xfree(signature); /* skip session id and packet type */ - if (buffer_len(&b) < session_id2_len + 1) + if (buffer_len(&b) < skip + 1) fatal("ssh2_try_pubkey: internal error"); - buffer_consume(&b, session_id2_len + 1); + buffer_consume(&b, skip + 1); /* put remaining data from buffer into packet */ packet_start(SSH2_MSG_USERAUTH_REQUEST); @@ -390,12 +363,88 @@ /* send */ packet_send(); packet_write_wait(); + return 1; } +int +ssh2_try_pubkey(char *filename, + const char *server_user, const char *host, const char *service) +{ + Key *k; + int ret = 0; + struct stat st; + + if (stat(filename, &st) != 0) { + debug("key does not exist: %s", filename); + return 0; + } + debug("try pubkey: %s", filename); + + k = key_new(KEY_DSA); + if (!load_private_key(filename, "", k, NULL)) { + int success = 0; + char *passphrase; + char prompt[300]; + snprintf(prompt, sizeof prompt, + "Enter passphrase for DSA key '%.100s': ", + filename); + passphrase = read_passphrase(prompt, 0); + success = load_private_key(filename, passphrase, k, NULL); + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + if (!success) { + key_free(k); + return 0; + } + } + ret = ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service); + key_free(k); + return ret; +} + +int agent_sign( + Key *key, + unsigned char **sigp, int *lenp, + unsigned char *data, int datalen) +{ + int ret = -1; + AuthenticationConnection *ac = ssh_get_authentication_connection(); + if (ac != NULL) { + ret = ssh_agent_sign(ac, key, sigp, lenp, data, datalen); + ssh_close_authentication_connection(ac); + } + return ret; +} + +int +ssh2_try_agent(AuthenticationConnection *ac, + const char *server_user, const char *host, const char *service) +{ + static int called = 0; + char *comment; + Key *k; + int ret; + + if (called == 0) { + k = ssh_get_first_identity(ac, &comment, 2); + called ++; + } else { + k = ssh_get_next_identity(ac, &comment, 2); + } + if (k == NULL) + return 0; + debug("trying DSA agent key %s", comment); + xfree(comment); + ret = ssh2_sign_and_send_pubkey(k, agent_sign, server_user, host, service); + key_free(k); + return ret; +} + void ssh_userauth2(const char *server_user, char *host) { + AuthenticationConnection *ac = ssh_get_authentication_connection(); int type; int plen; int sent; @@ -450,12 +499,17 @@ debug("partial success"); if (options.dsa_authentication && strstr(auths, "publickey") != NULL) { - while (i < options.num_identity_files2) { - sent = ssh2_try_pubkey( - options.identity_files2[i++], + if (ac != NULL) + sent = ssh2_try_agent(ac, server_user, host, service); - if (sent) - break; + if (!sent) { + while (i < options.num_identity_files2) { + sent = ssh2_try_pubkey( + options.identity_files2[i++], + server_user, host, service); + if (sent) + break; + } } } if (!sent) { @@ -469,6 +523,8 @@ fatal("Permission denied (%s).", auths); xfree(auths); } + if (ac != NULL) + ssh_close_authentication_connection(ac); packet_done(); debug("ssh-userauth2 successfull"); }