Annotation of src/usr.bin/ssh/sshconnect2.c, Revision 1.1
1.1 ! markus 1: /*
! 2: * Copyright (c) 2000 Markus Friedl. All rights reserved.
! 3: *
! 4: * Redistribution and use in source and binary forms, with or without
! 5: * modification, are permitted provided that the following conditions
! 6: * are met:
! 7: * 1. Redistributions of source code must retain the above copyright
! 8: * notice, this list of conditions and the following disclaimer.
! 9: * 2. Redistributions in binary form must reproduce the above copyright
! 10: * notice, this list of conditions and the following disclaimer in the
! 11: * documentation and/or other materials provided with the distribution.
! 12: * 3. All advertising materials mentioning features or use of this software
! 13: * must display the following acknowledgement:
! 14: * This product includes software developed by Markus Friedl.
! 15: * 4. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: #include "includes.h"
! 31: RCSID("$OpenBSD: sshconnect2.c,v 1.1 2000/04/18 15:01:34 markus Exp $");
! 32:
! 33: #include <openssl/bn.h>
! 34: #include <openssl/rsa.h>
! 35: #include <openssl/dsa.h>
! 36: #include <openssl/md5.h>
! 37: #include <openssl/dh.h>
! 38: #include <openssl/hmac.h>
! 39:
! 40: #include "ssh.h"
! 41: #include "xmalloc.h"
! 42: #include "rsa.h"
! 43: #include "buffer.h"
! 44: #include "packet.h"
! 45: #include "cipher.h"
! 46: #include "uidswap.h"
! 47: #include "compat.h"
! 48: #include "readconf.h"
! 49: #include "bufaux.h"
! 50: #include "ssh2.h"
! 51: #include "kex.h"
! 52: #include "myproposal.h"
! 53: #include "key.h"
! 54: #include "dsa.h"
! 55: #include "sshconnect.h"
! 56: #include "authfile.h"
! 57:
! 58: /* import */
! 59: extern char *client_version_string;
! 60: extern char *server_version_string;
! 61: extern Options options;
! 62:
! 63: /*
! 64: * SSH2 key exchange
! 65: */
! 66:
! 67: unsigned char *session_id2 = NULL;
! 68: int session_id2_len = 0;
! 69:
! 70: void
! 71: ssh_kex2(char *host, struct sockaddr *hostaddr)
! 72: {
! 73: Kex *kex;
! 74: char *cprop[PROPOSAL_MAX];
! 75: char *sprop[PROPOSAL_MAX];
! 76: Buffer *client_kexinit;
! 77: Buffer *server_kexinit;
! 78: int payload_len, dlen;
! 79: unsigned int klen, kout;
! 80: char *ptr;
! 81: char *signature = NULL;
! 82: unsigned int slen;
! 83: char *server_host_key_blob = NULL;
! 84: Key *server_host_key;
! 85: unsigned int sbloblen;
! 86: DH *dh;
! 87: BIGNUM *dh_server_pub = 0;
! 88: BIGNUM *shared_secret = 0;
! 89: int i;
! 90: unsigned char *kbuf;
! 91: unsigned char *hash;
! 92:
! 93: /* KEXINIT */
! 94:
! 95: debug("Sending KEX init.");
! 96: if (options.ciphers != NULL) {
! 97: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
! 98: myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers;
! 99: } else if (
! 100: options.cipher == SSH_CIPHER_ARCFOUR ||
! 101: options.cipher == SSH_CIPHER_3DES_CBC ||
! 102: options.cipher == SSH_CIPHER_CAST128_CBC ||
! 103: options.cipher == SSH_CIPHER_BLOWFISH_CBC) {
! 104: myproposal[PROPOSAL_ENC_ALGS_CTOS] =
! 105: myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher);
! 106: }
! 107: if (options.compression) {
! 108: myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib";
! 109: myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib";
! 110: } else {
! 111: myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none";
! 112: myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
! 113: }
! 114: for (i = 0; i < PROPOSAL_MAX; i++)
! 115: cprop[i] = xstrdup(myproposal[i]);
! 116:
! 117: client_kexinit = kex_init(cprop);
! 118: packet_start(SSH2_MSG_KEXINIT);
! 119: packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit));
! 120: packet_send();
! 121: packet_write_wait();
! 122:
! 123: debug("done");
! 124:
! 125: packet_read_expect(&payload_len, SSH2_MSG_KEXINIT);
! 126:
! 127: /* save payload for session_id */
! 128: server_kexinit = xmalloc(sizeof(*server_kexinit));
! 129: buffer_init(server_kexinit);
! 130: ptr = packet_get_raw(&payload_len);
! 131: buffer_append(server_kexinit, ptr, payload_len);
! 132:
! 133: /* skip cookie */
! 134: for (i = 0; i < 16; i++)
! 135: (void) packet_get_char();
! 136: /* kex init proposal strings */
! 137: for (i = 0; i < PROPOSAL_MAX; i++) {
! 138: sprop[i] = packet_get_string(NULL);
! 139: debug("got kexinit string: %s", sprop[i]);
! 140: }
! 141: i = (int) packet_get_char();
! 142: debug("first kex follow == %d", i);
! 143: i = packet_get_int();
! 144: debug("reserved == %d", i);
! 145: packet_done();
! 146:
! 147: debug("done read kexinit");
! 148: kex = kex_choose_conf(cprop, sprop, 0);
! 149:
! 150: /* KEXDH */
! 151:
! 152: debug("Sending SSH2_MSG_KEXDH_INIT.");
! 153:
! 154: /* generate and send 'e', client DH public key */
! 155: dh = dh_new_group1();
! 156: packet_start(SSH2_MSG_KEXDH_INIT);
! 157: packet_put_bignum2(dh->pub_key);
! 158: packet_send();
! 159: packet_write_wait();
! 160:
! 161: #ifdef DEBUG_KEXDH
! 162: fprintf(stderr, "\np= ");
! 163: bignum_print(dh->p);
! 164: fprintf(stderr, "\ng= ");
! 165: bignum_print(dh->g);
! 166: fprintf(stderr, "\npub= ");
! 167: bignum_print(dh->pub_key);
! 168: fprintf(stderr, "\n");
! 169: DHparams_print_fp(stderr, dh);
! 170: #endif
! 171:
! 172: debug("Wait SSH2_MSG_KEXDH_REPLY.");
! 173:
! 174: packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY);
! 175:
! 176: debug("Got SSH2_MSG_KEXDH_REPLY.");
! 177:
! 178: /* key, cert */
! 179: server_host_key_blob = packet_get_string(&sbloblen);
! 180: server_host_key = dsa_key_from_blob(server_host_key_blob, sbloblen);
! 181: if (server_host_key == NULL)
! 182: fatal("cannot decode server_host_key_blob");
! 183:
! 184: dump_base64(stderr, server_host_key_blob, sbloblen);
! 185:
! 186: check_host_key(host, hostaddr, server_host_key,
! 187: options.user_hostfile2, options.system_hostfile2);
! 188:
! 189: /* DH paramter f, server public DH key */
! 190: dh_server_pub = BN_new();
! 191: if (dh_server_pub == NULL)
! 192: fatal("dh_server_pub == NULL");
! 193: packet_get_bignum2(dh_server_pub, &dlen);
! 194:
! 195: #ifdef DEBUG_KEXDH
! 196: fprintf(stderr, "\ndh_server_pub= ");
! 197: bignum_print(dh_server_pub);
! 198: fprintf(stderr, "\n");
! 199: debug("bits %d", BN_num_bits(dh_server_pub));
! 200: #endif
! 201:
! 202: /* signed H */
! 203: signature = packet_get_string(&slen);
! 204: packet_done();
! 205:
! 206: if (!dh_pub_is_valid(dh, dh_server_pub))
! 207: packet_disconnect("bad server public DH value");
! 208:
! 209: klen = DH_size(dh);
! 210: kbuf = xmalloc(klen);
! 211: kout = DH_compute_key(kbuf, dh_server_pub, dh);
! 212: #ifdef DEBUG_KEXDH
! 213: debug("shared secret: len %d/%d", klen, kout);
! 214: fprintf(stderr, "shared secret == ");
! 215: for (i = 0; i< kout; i++)
! 216: fprintf(stderr, "%02x", (kbuf[i])&0xff);
! 217: fprintf(stderr, "\n");
! 218: #endif
! 219: shared_secret = BN_new();
! 220:
! 221: BN_bin2bn(kbuf, kout, shared_secret);
! 222: memset(kbuf, 0, klen);
! 223: xfree(kbuf);
! 224:
! 225: /* calc and verify H */
! 226: hash = kex_hash(
! 227: client_version_string,
! 228: server_version_string,
! 229: buffer_ptr(client_kexinit), buffer_len(client_kexinit),
! 230: buffer_ptr(server_kexinit), buffer_len(server_kexinit),
! 231: server_host_key_blob, sbloblen,
! 232: dh->pub_key,
! 233: dh_server_pub,
! 234: shared_secret
! 235: );
! 236: buffer_free(client_kexinit);
! 237: buffer_free(server_kexinit);
! 238: xfree(client_kexinit);
! 239: xfree(server_kexinit);
! 240: #ifdef DEBUG_KEXDH
! 241: fprintf(stderr, "hash == ");
! 242: for (i = 0; i< 20; i++)
! 243: fprintf(stderr, "%02x", (hash[i])&0xff);
! 244: fprintf(stderr, "\n");
! 245: #endif
! 246: if (dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20) != 1)
! 247: fatal("dsa_verify failed for server_host_key");
! 248: key_free(server_host_key);
! 249:
! 250: kex_derive_keys(kex, hash, shared_secret);
! 251: packet_set_kex(kex);
! 252:
! 253: /* have keys, free DH */
! 254: DH_free(dh);
! 255:
! 256: /* save session id */
! 257: session_id2_len = 20;
! 258: session_id2 = xmalloc(session_id2_len);
! 259: memcpy(session_id2, hash, session_id2_len);
! 260:
! 261: debug("Wait SSH2_MSG_NEWKEYS.");
! 262: packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS);
! 263: packet_done();
! 264: debug("GOT SSH2_MSG_NEWKEYS.");
! 265:
! 266: debug("send SSH2_MSG_NEWKEYS.");
! 267: packet_start(SSH2_MSG_NEWKEYS);
! 268: packet_send();
! 269: packet_write_wait();
! 270: debug("done: send SSH2_MSG_NEWKEYS.");
! 271:
! 272: #ifdef DEBUG_KEXDH
! 273: /* send 1st encrypted/maced/compressed message */
! 274: packet_start(SSH2_MSG_IGNORE);
! 275: packet_put_cstring("markus");
! 276: packet_send();
! 277: packet_write_wait();
! 278: #endif
! 279: debug("done: KEX2.");
! 280: }
! 281: /*
! 282: * Authenticate user
! 283: */
! 284: int
! 285: ssh2_try_passwd(const char *server_user, const char *host, const char *service)
! 286: {
! 287: char prompt[80];
! 288: char *password;
! 289:
! 290: snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ",
! 291: server_user, host);
! 292: password = read_passphrase(prompt, 0);
! 293: packet_start(SSH2_MSG_USERAUTH_REQUEST);
! 294: packet_put_cstring(server_user);
! 295: packet_put_cstring(service);
! 296: packet_put_cstring("password");
! 297: packet_put_char(0);
! 298: packet_put_cstring(password);
! 299: memset(password, 0, strlen(password));
! 300: xfree(password);
! 301: packet_send();
! 302: packet_write_wait();
! 303: return 1;
! 304: }
! 305:
! 306: int
! 307: ssh2_try_pubkey(char *filename,
! 308: const char *server_user, const char *host, const char *service)
! 309: {
! 310: Buffer b;
! 311: Key *k;
! 312: unsigned char *blob, *signature;
! 313: int bloblen, slen;
! 314:
! 315: debug("try pubkey: %s", filename);
! 316:
! 317: k = key_new(KEY_DSA);
! 318: if (!load_private_key(filename, "", k, NULL)) {
! 319: int success = 0;
! 320: char *passphrase;
! 321: char prompt[300];
! 322: snprintf(prompt, sizeof prompt,
! 323: "Enter passphrase for DSA key '%.100s': ",
! 324: filename);
! 325: passphrase = read_passphrase(prompt, 0);
! 326: success = load_private_key(filename, passphrase, k, NULL);
! 327: memset(passphrase, 0, strlen(passphrase));
! 328: xfree(passphrase);
! 329: if (!success)
! 330: return 0;
! 331: }
! 332: dsa_make_key_blob(k, &blob, &bloblen);
! 333:
! 334: //DSA_print_fp(stderr, k->dsa, 8);
! 335:
! 336: /* data to be signed */
! 337: buffer_init(&b);
! 338: buffer_append(&b, session_id2, session_id2_len);
! 339: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
! 340: buffer_put_cstring(&b, server_user);
! 341: buffer_put_cstring(&b, service);
! 342: buffer_put_cstring(&b, "publickey");
! 343: buffer_put_char(&b, 1);
! 344: buffer_put_cstring(&b, KEX_DSS);
! 345: buffer_put_string(&b, blob, bloblen);
! 346:
! 347: /* generate signature */
! 348: dsa_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));
! 349: key_free(k);
! 350: #ifdef DEBUG_DSS
! 351: buffer_dump(&b);
! 352: #endif
! 353: /* append signature */
! 354: buffer_put_string(&b, signature, slen);
! 355: xfree(signature);
! 356:
! 357: /* skip session id and packet type */
! 358: if (buffer_len(&b) < session_id2_len + 1)
! 359: fatal("ssh2_try_pubkey: internal error");
! 360: buffer_consume(&b, session_id2_len + 1);
! 361:
! 362: /* put remaining data from buffer into packet */
! 363: packet_start(SSH2_MSG_USERAUTH_REQUEST);
! 364: packet_put_raw(buffer_ptr(&b), buffer_len(&b));
! 365: buffer_free(&b);
! 366:
! 367: /* send */
! 368: packet_send();
! 369: packet_write_wait();
! 370: return 1;
! 371: }
! 372:
! 373: void
! 374: ssh_userauth2(const char *server_user, char *host)
! 375: {
! 376: int type;
! 377: int plen;
! 378: int sent;
! 379: unsigned int dlen;
! 380: int partial;
! 381: int i = 0;
! 382: char *auths;
! 383: char *service = "ssh-connection"; /* service name */
! 384:
! 385: debug("send SSH2_MSG_SERVICE_REQUEST");
! 386: packet_start(SSH2_MSG_SERVICE_REQUEST);
! 387: packet_put_cstring("ssh-userauth");
! 388: packet_send();
! 389: packet_write_wait();
! 390:
! 391: type = packet_read(&plen);
! 392: if (type != SSH2_MSG_SERVICE_ACCEPT) {
! 393: fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);
! 394: }
! 395: if (packet_remaining() > 0) {
! 396: char *reply = packet_get_string(&plen);
! 397: debug("service_accept: %s", reply);
! 398: xfree(reply);
! 399: } else {
! 400: /* payload empty for ssh-2.0.13 ?? */
! 401: log("buggy server: service_accept w/o service");
! 402: }
! 403: packet_done();
! 404: debug("got SSH2_MSG_SERVICE_ACCEPT");
! 405:
! 406: /* INITIAL request for auth */
! 407: packet_start(SSH2_MSG_USERAUTH_REQUEST);
! 408: packet_put_cstring(server_user);
! 409: packet_put_cstring(service);
! 410: packet_put_cstring("none");
! 411: packet_send();
! 412: packet_write_wait();
! 413:
! 414: for (;;) {
! 415: sent = 0;
! 416: type = packet_read(&plen);
! 417: if (type == SSH2_MSG_USERAUTH_SUCCESS)
! 418: break;
! 419: if (type != SSH2_MSG_USERAUTH_FAILURE)
! 420: fatal("access denied: %d", type);
! 421: /* SSH2_MSG_USERAUTH_FAILURE means: try again */
! 422: auths = packet_get_string(&dlen);
! 423: debug("authentications that can continue: %s", auths);
! 424: partial = packet_get_char();
! 425: packet_done();
! 426: if (partial)
! 427: debug("partial success");
! 428: if (strstr(auths, "publickey") != NULL) {
! 429: while (i < options.num_identity_files2) {
! 430: sent = ssh2_try_pubkey(
! 431: options.identity_files2[i++],
! 432: server_user, host, service);
! 433: if (sent)
! 434: break;
! 435: }
! 436: }
! 437: if (!sent) {
! 438: if (strstr(auths, "password") != NULL) {
! 439: sent = ssh2_try_passwd(server_user, host, service);
! 440: } else {
! 441: fatal("passwd auth not supported: %s", auths);
! 442: }
! 443: if (!sent)
! 444: fatal("no more auths: %s", auths);
! 445: }
! 446: xfree(auths);
! 447: }
! 448: packet_done();
! 449: debug("ssh-userauth2 successfull");
! 450: }