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

Annotation of src/usr.bin/ssh/kexgex.c, Revision 1.1

1.1     ! markus      1: /*
        !             2:  * Copyright (c) 2000 Niels Provos.  All rights reserved.
        !             3:  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  *
        !            14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            15:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            16:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            17:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            18:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            19:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            20:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            21:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            22:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            23:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            24:  */
        !            25:
        !            26: #include "includes.h"
        !            27: RCSID("$OpenBSD: kex.c,v 1.24 2001/03/28 21:59:40 provos Exp $");
        !            28:
        !            29: #include <openssl/bn.h>
        !            30:
        !            31: #include "xmalloc.h"
        !            32: #include "buffer.h"
        !            33: #include "bufaux.h"
        !            34: #include "key.h"
        !            35: #include "kex.h"
        !            36: #include "log.h"
        !            37: #include "dispatch.h"
        !            38: #include "packet.h"
        !            39: #include "dh.h"
        !            40: #include "ssh2.h"
        !            41: #include "compat.h"
        !            42:
        !            43: extern u_char *session_id2;
        !            44: extern int session_id2_len;
        !            45:
        !            46: typedef struct State State;
        !            47: struct State {
        !            48:        DH *dh;
        !            49:        int min, nbits, max;
        !            50: };
        !            51:
        !            52: dispatch_fn kexgex_input_request;      /* C -> S */
        !            53: dispatch_fn kexgex_input_group;                /* S -> C */
        !            54: dispatch_fn kexgex_input_init;         /* C -> S */
        !            55: dispatch_fn kexgex_input_reply;                /* S -> C */
        !            56:
        !            57: u_char *
        !            58: kexgex_hash(
        !            59:     char *client_version_string,
        !            60:     char *server_version_string,
        !            61:     char *ckexinit, int ckexinitlen,
        !            62:     char *skexinit, int skexinitlen,
        !            63:     char *serverhostkeyblob, int sbloblen,
        !            64:     int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
        !            65:     BIGNUM *client_dh_pub,
        !            66:     BIGNUM *server_dh_pub,
        !            67:     BIGNUM *shared_secret)
        !            68: {
        !            69:        Buffer b;
        !            70:        static u_char digest[EVP_MAX_MD_SIZE];
        !            71:        EVP_MD *evp_md = EVP_sha1();
        !            72:        EVP_MD_CTX md;
        !            73:
        !            74:        buffer_init(&b);
        !            75:        buffer_put_string(&b, client_version_string, strlen(client_version_string));
        !            76:        buffer_put_string(&b, server_version_string, strlen(server_version_string));
        !            77:
        !            78:        /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
        !            79:        buffer_put_int(&b, ckexinitlen+1);
        !            80:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
        !            81:        buffer_append(&b, ckexinit, ckexinitlen);
        !            82:        buffer_put_int(&b, skexinitlen+1);
        !            83:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
        !            84:        buffer_append(&b, skexinit, skexinitlen);
        !            85:
        !            86:        buffer_put_string(&b, serverhostkeyblob, sbloblen);
        !            87:        if (min == -1 || max == -1)
        !            88:                buffer_put_int(&b, wantbits);
        !            89:        else {
        !            90:                buffer_put_int(&b, min);
        !            91:                buffer_put_int(&b, wantbits);
        !            92:                buffer_put_int(&b, max);
        !            93:        }
        !            94:        buffer_put_bignum2(&b, prime);
        !            95:        buffer_put_bignum2(&b, gen);
        !            96:        buffer_put_bignum2(&b, client_dh_pub);
        !            97:        buffer_put_bignum2(&b, server_dh_pub);
        !            98:        buffer_put_bignum2(&b, shared_secret);
        !            99:
        !           100: #ifdef DEBUG_KEXDH
        !           101:        buffer_dump(&b);
        !           102: #endif
        !           103:        EVP_DigestInit(&md, evp_md);
        !           104:        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
        !           105:        EVP_DigestFinal(&md, digest, NULL);
        !           106:
        !           107:        buffer_free(&b);
        !           108:
        !           109: #ifdef DEBUG_KEXDH
        !           110:        dump_digest("hash", digest, evp_md->md_size);
        !           111: #endif
        !           112:        return digest;
        !           113: }
        !           114:
        !           115: /* client */
        !           116:
        !           117: void
        !           118: kexgex_client(Kex *kex)
        !           119: {
        !           120:        State *state;
        !           121:
        !           122:        dispatch_set(SSH2_MSG_KEX_DH_GEX_GROUP, &kexgex_input_group);
        !           123:
        !           124:        state = xmalloc(sizeof(*state));
        !           125:        state->nbits = dh_estimate(kex->we_need * 8);
        !           126:        kex->state = state;
        !           127:
        !           128:        if (datafellows & SSH_OLD_DHGEX) {
        !           129:                debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
        !           130:
        !           131:                /* Old GEX request */
        !           132:                packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
        !           133:                packet_put_int(state->nbits);
        !           134:                state->min = DH_GRP_MIN;
        !           135:                state->max = DH_GRP_MAX;
        !           136:        } else {
        !           137:                debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
        !           138:
        !           139:                /* New GEX request */
        !           140:                state->min = DH_GRP_MIN;
        !           141:                state->max = DH_GRP_MAX;
        !           142:                packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
        !           143:                packet_put_int(state->min);
        !           144:                packet_put_int(state->nbits);
        !           145:                packet_put_int(state->max);
        !           146:        }
        !           147: #ifdef DEBUG_KEXDH
        !           148:        fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
        !           149:            state->min, state->nbits, state->max);
        !           150: #endif
        !           151:        packet_send();
        !           152: }
        !           153:
        !           154: void
        !           155: kexgex_input_group(int type, int plen, void *ctxt)
        !           156: {
        !           157:        DH *dh;
        !           158:        int dlen;
        !           159:        BIGNUM *p = 0, *g = 0;
        !           160:        Kex *kex = (Kex*) ctxt;
        !           161:        State *state = (State *) kex->state;
        !           162:
        !           163:        debug("SSH2_MSG_KEX_DH_GEX_GROUP receivied");
        !           164:        dispatch_set(SSH2_MSG_KEX_DH_GEX_GROUP, &kex_protocol_error);
        !           165:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REPLY, &kexgex_input_reply);
        !           166:
        !           167:        if ((p = BN_new()) == NULL)
        !           168:                fatal("BN_new");
        !           169:        packet_get_bignum2(p, &dlen);
        !           170:        if ((g = BN_new()) == NULL)
        !           171:                fatal("BN_new");
        !           172:        packet_get_bignum2(g, &dlen);
        !           173:
        !           174:        if (BN_num_bits(p) < state->min || BN_num_bits(p) > state->max)
        !           175:                fatal("DH_GEX group out of range: %d !< %d !< %d",
        !           176:                    state->min, BN_num_bits(p), state->max);
        !           177:
        !           178:        dh = dh_new_group(g, p);
        !           179:        dh_gen_key(dh, kex->we_need * 8);
        !           180:
        !           181:        state->dh = dh;
        !           182:
        !           183: #ifdef DEBUG_KEXDH
        !           184:        DHparams_print_fp(stderr, dh);
        !           185:        fprintf(stderr, "pub= ");
        !           186:        BN_print_fp(stderr, dh->pub_key);
        !           187:        fprintf(stderr, "\n");
        !           188: #endif
        !           189:
        !           190:        debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
        !           191:        /* generate and send 'e', client DH public key */
        !           192:        packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
        !           193:        packet_put_bignum2(dh->pub_key);
        !           194:        packet_send();
        !           195: }
        !           196:
        !           197: void
        !           198: kexgex_input_reply(int type, int plen, void *ctxt)
        !           199: {
        !           200:        BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
        !           201:        Key *server_host_key;
        !           202:        Kex *kex = (Kex*) ctxt;
        !           203:        State *state = (State *) kex->state;
        !           204:        DH *dh = state->dh;
        !           205:        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
        !           206:        u_int klen, kout, slen, sbloblen;
        !           207:        int dlen, min, max;
        !           208:
        !           209:        debug("SSH2_MSG_KEX_DH_GEX_REPLY received");
        !           210:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REPLY, &kex_protocol_error);
        !           211:
        !           212:        /* key, cert */
        !           213:        server_host_key_blob = packet_get_string(&sbloblen);
        !           214:        server_host_key = key_from_blob(server_host_key_blob, sbloblen);
        !           215:        if (server_host_key == NULL)
        !           216:                fatal("cannot decode server_host_key_blob");
        !           217:
        !           218:        if (kex->check_host_key == NULL)
        !           219:                fatal("cannot check server_host_key");
        !           220:        kex->check_host_key(server_host_key);
        !           221:
        !           222:        /* DH paramter f, server public DH key */
        !           223:        dh_server_pub = BN_new();
        !           224:        if (dh_server_pub == NULL)
        !           225:                fatal("dh_server_pub == NULL");
        !           226:        packet_get_bignum2(dh_server_pub, &dlen);
        !           227:
        !           228: #ifdef DEBUG_KEXDH
        !           229:        fprintf(stderr, "dh_server_pub= ");
        !           230:        BN_print_fp(stderr, dh_server_pub);
        !           231:        fprintf(stderr, "\n");
        !           232:        debug("bits %d", BN_num_bits(dh_server_pub));
        !           233: #endif
        !           234:
        !           235:        /* signed H */
        !           236:        signature = packet_get_string(&slen);
        !           237:        packet_done();
        !           238:
        !           239:        if (!dh_pub_is_valid(dh, dh_server_pub))
        !           240:                packet_disconnect("bad server public DH value");
        !           241:
        !           242:        klen = DH_size(dh);
        !           243:        kbuf = xmalloc(klen);
        !           244:        kout = DH_compute_key(kbuf, dh_server_pub, dh);
        !           245: #ifdef DEBUG_KEXDH
        !           246:         dump_digest("shared secret", kbuf, kout);
        !           247: #endif
        !           248:        shared_secret = BN_new();
        !           249:        BN_bin2bn(kbuf, kout, shared_secret);
        !           250:        memset(kbuf, 0, klen);
        !           251:        xfree(kbuf);
        !           252:
        !           253:        if (datafellows & SSH_OLD_DHGEX) {
        !           254:                min = max = -1;
        !           255:        } else {
        !           256:                min = state->min;
        !           257:                max = state->max;
        !           258:        }
        !           259:
        !           260:        /* calc and verify H */
        !           261:        hash = kexgex_hash(
        !           262:            kex->client_version_string,
        !           263:            kex->server_version_string,
        !           264:            buffer_ptr(&kex->my), buffer_len(&kex->my),
        !           265:            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
        !           266:            server_host_key_blob, sbloblen,
        !           267:            min, state->nbits, max,
        !           268:            dh->p, dh->g,
        !           269:            dh->pub_key,
        !           270:            dh_server_pub,
        !           271:            shared_secret
        !           272:        );
        !           273:        xfree(server_host_key_blob);
        !           274:        BN_free(dh_server_pub);
        !           275:
        !           276:        if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
        !           277:                fatal("key_verify failed for server_host_key");
        !           278:        key_free(server_host_key);
        !           279:        xfree(signature);
        !           280:
        !           281:        kex_derive_keys(kex, hash, shared_secret);
        !           282:        BN_clear_free(shared_secret);
        !           283:        packet_set_kex(kex);
        !           284:
        !           285:        /* save session id */
        !           286:        session_id2_len = 20;
        !           287:        session_id2 = xmalloc(session_id2_len);
        !           288:        memcpy(session_id2, hash, session_id2_len);
        !           289:
        !           290:        kex_send_newkeys();
        !           291:
        !           292:        /* have keys, free DH */
        !           293:        DH_free(dh);
        !           294:        xfree(state);
        !           295:        kex->state = NULL;
        !           296: }
        !           297:
        !           298: /* server */
        !           299:
        !           300: void
        !           301: kexgex_server(Kex *kex)
        !           302: {
        !           303:        State *state;
        !           304:
        !           305:        state = xmalloc(sizeof(*state));
        !           306:        kex->state = state;
        !           307:
        !           308:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST, &kexgex_input_request);
        !           309:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, &kexgex_input_request);
        !           310: }
        !           311:
        !           312: void
        !           313: kexgex_input_request(int type, int plen, void *ctxt)
        !           314: {
        !           315:        Kex *kex = (Kex*) ctxt;
        !           316:        State *state = (State *) kex->state;
        !           317:        int min = -1, max = -1;
        !           318:
        !           319:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST, &kex_protocol_error);
        !           320:        dispatch_set(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, &kex_protocol_error);
        !           321:        dispatch_set(SSH2_MSG_KEX_DH_GEX_INIT, &kexgex_input_init);
        !           322:
        !           323:        switch(type){
        !           324:        case SSH2_MSG_KEX_DH_GEX_REQUEST:
        !           325:                debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
        !           326:                min = packet_get_int();
        !           327:                state->nbits = packet_get_int();
        !           328:                max = packet_get_int();
        !           329:                min = MAX(DH_GRP_MIN, min);
        !           330:                max = MIN(DH_GRP_MAX, max);
        !           331:                state->min = min;
        !           332:                state->max = max;
        !           333:                break;
        !           334:        case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
        !           335:                debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
        !           336:                state->nbits = packet_get_int();
        !           337:                min = DH_GRP_MIN;
        !           338:                max = DH_GRP_MAX;
        !           339:                /* unused for old GEX */
        !           340:                state->min = -1;
        !           341:                state->max = -1;
        !           342:                break;
        !           343:        }
        !           344:        packet_done();
        !           345:
        !           346:        if (max < min || state->nbits < min || max < state->nbits)
        !           347:                fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
        !           348:                    min, state->nbits, max);
        !           349:
        !           350:        state->dh = choose_dh(min, state->nbits, max);
        !           351:        if (state->dh == NULL)
        !           352:                packet_disconnect("Protocol error: no matching DH grp found");
        !           353:
        !           354:        debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
        !           355:        packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
        !           356:        packet_put_bignum2(state->dh->p);
        !           357:        packet_put_bignum2(state->dh->g);
        !           358:        packet_send();
        !           359:
        !           360:        /* flush */
        !           361:        packet_write_wait();
        !           362:
        !           363:        /* Compute our exchange value in parallel with the client */
        !           364:        dh_gen_key(state->dh, kex->we_need * 8);
        !           365: }
        !           366:
        !           367: void
        !           368: kexgex_input_init(int type, int plen, void *ctxt)
        !           369: {
        !           370:        BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
        !           371:        Key *server_host_key;
        !           372:        Kex *kex = (Kex*) ctxt;
        !           373:        State *state = (State *) kex->state;
        !           374:        DH *dh = state->dh;
        !           375:        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
        !           376:        u_int sbloblen, klen, kout;
        !           377:        int dlen, slen;
        !           378:
        !           379:        if (kex->load_host_key == NULL)
        !           380:                fatal("Cannot load hostkey");
        !           381:        server_host_key = kex->load_host_key(kex->hostkey_type);
        !           382:        if (server_host_key == NULL)
        !           383:                fatal("Unsupported hostkey type %d", kex->hostkey_type);
        !           384:
        !           385:        dispatch_set(SSH2_MSG_KEX_DH_GEX_INIT, &kex_protocol_error);
        !           386:        debug("SSH2_MSG_KEX_DH_GEX_INIT received");
        !           387:
        !           388:        /* key, cert */
        !           389:        dh_client_pub = BN_new();
        !           390:        if (dh_client_pub == NULL)
        !           391:                fatal("dh_client_pub == NULL");
        !           392:        packet_get_bignum2(dh_client_pub, &dlen);
        !           393:
        !           394: #ifdef DEBUG_KEXDH
        !           395:        fprintf(stderr, "dh_client_pub= ");
        !           396:        BN_print_fp(stderr, dh_client_pub);
        !           397:        fprintf(stderr, "\n");
        !           398:        debug("bits %d", BN_num_bits(dh_client_pub));
        !           399: #endif
        !           400:
        !           401: #ifdef DEBUG_KEXDH
        !           402:        DHparams_print_fp(stderr, dh);
        !           403:        fprintf(stderr, "pub= ");
        !           404:        BN_print_fp(stderr, dh->pub_key);
        !           405:        fprintf(stderr, "\n");
        !           406: #endif
        !           407:        if (!dh_pub_is_valid(dh, dh_client_pub))
        !           408:                packet_disconnect("bad client public DH value");
        !           409:
        !           410:        klen = DH_size(dh);
        !           411:        kbuf = xmalloc(klen);
        !           412:        kout = DH_compute_key(kbuf, dh_client_pub, dh);
        !           413: #ifdef DEBUG_KEXDH
        !           414:         dump_digest("shared secret", kbuf, kout);
        !           415: #endif
        !           416:        shared_secret = BN_new();
        !           417:        BN_bin2bn(kbuf, kout, shared_secret);
        !           418:        memset(kbuf, 0, klen);
        !           419:        xfree(kbuf);
        !           420:
        !           421:        key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
        !           422:
        !           423:        /* calc H */                    /* XXX depends on 'kex' */
        !           424:        hash = kexgex_hash(
        !           425:            kex->client_version_string,
        !           426:            kex->server_version_string,
        !           427:            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
        !           428:            buffer_ptr(&kex->my), buffer_len(&kex->my),
        !           429:            (char *)server_host_key_blob, sbloblen,
        !           430:            state->min, state->nbits, state->max,
        !           431:            dh->p, dh->g,
        !           432:            dh_client_pub,
        !           433:            dh->pub_key,
        !           434:            shared_secret
        !           435:        );
        !           436:        BN_free(dh_client_pub);
        !           437:
        !           438:        /* save session id := H */
        !           439:        /* XXX hashlen depends on KEX */
        !           440:        session_id2_len = 20;
        !           441:        session_id2 = xmalloc(session_id2_len);
        !           442:        memcpy(session_id2, hash, session_id2_len);
        !           443:
        !           444:        /* sign H */
        !           445:        /* XXX hashlen depends on KEX */
        !           446:        key_sign(server_host_key, &signature, &slen, hash, 20);
        !           447:
        !           448:        /* destroy_sensitive_data(); */
        !           449:
        !           450:        /* send server hostkey, DH pubkey 'f' and singed H */
        !           451:        debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
        !           452:        packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
        !           453:        packet_put_string((char *)server_host_key_blob, sbloblen);
        !           454:        packet_put_bignum2(dh->pub_key);        /* f */
        !           455:        packet_put_string((char *)signature, slen);
        !           456:        packet_send();
        !           457:        xfree(signature);
        !           458:        xfree(server_host_key_blob);
        !           459:        /* packet_write_wait(); */
        !           460:
        !           461:        kex_derive_keys(kex, hash, shared_secret);
        !           462:        BN_clear_free(shared_secret);
        !           463:        packet_set_kex(kex);
        !           464:
        !           465:        kex_send_newkeys();
        !           466:
        !           467:        /* have keys, free DH */
        !           468:        DH_free(dh);
        !           469:        xfree(state);
        !           470:        kex->state = NULL;
        !           471: }
        !           472:
        !           473: void
        !           474: kexgex(Kex *kex)
        !           475: {
        !           476:        if (kex->server)
        !           477:                kexgex_server(kex);
        !           478:        else
        !           479:                kexgex_client(kex);
        !           480: }