[BACK]Return to sshconnect2.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

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: }