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

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

1.1     ! markus      1: /*
        !             2:  * Copyright (c) 2001 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:  *
        !            13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            14:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            15:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            16:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            17:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            18:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            19:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            20:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            21:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            22:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            23:  */
        !            24:
        !            25: #include "includes.h"
        !            26: RCSID("$OpenBSD: kex.c,v 1.24 2001/03/28 21:59:40 provos Exp $");
        !            27:
        !            28: #include <openssl/crypto.h>
        !            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:
        !            42: extern u_char *session_id2;
        !            43: extern int session_id2_len;
        !            44:
        !            45: dispatch_fn kexdh_input_init;          /* C -> S */
        !            46: dispatch_fn kexdh_input_reply;         /* S -> C */
        !            47:
        !            48: typedef struct State State;
        !            49: struct State {
        !            50:        DH *dh;
        !            51: };
        !            52:
        !            53: u_char *
        !            54: kex_dh_hash(
        !            55:     char *client_version_string,
        !            56:     char *server_version_string,
        !            57:     char *ckexinit, int ckexinitlen,
        !            58:     char *skexinit, int skexinitlen,
        !            59:     char *serverhostkeyblob, int sbloblen,
        !            60:     BIGNUM *client_dh_pub,
        !            61:     BIGNUM *server_dh_pub,
        !            62:     BIGNUM *shared_secret)
        !            63: {
        !            64:        Buffer b;
        !            65:        static u_char digest[EVP_MAX_MD_SIZE];
        !            66:        EVP_MD *evp_md = EVP_sha1();
        !            67:        EVP_MD_CTX md;
        !            68:
        !            69:        buffer_init(&b);
        !            70:        buffer_put_string(&b, client_version_string, strlen(client_version_string));
        !            71:        buffer_put_string(&b, server_version_string, strlen(server_version_string));
        !            72:
        !            73:        /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
        !            74:        buffer_put_int(&b, ckexinitlen+1);
        !            75:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
        !            76:        buffer_append(&b, ckexinit, ckexinitlen);
        !            77:        buffer_put_int(&b, skexinitlen+1);
        !            78:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
        !            79:        buffer_append(&b, skexinit, skexinitlen);
        !            80:
        !            81:        buffer_put_string(&b, serverhostkeyblob, sbloblen);
        !            82:        buffer_put_bignum2(&b, client_dh_pub);
        !            83:        buffer_put_bignum2(&b, server_dh_pub);
        !            84:        buffer_put_bignum2(&b, shared_secret);
        !            85:
        !            86: #ifdef DEBUG_KEX
        !            87:        buffer_dump(&b);
        !            88: #endif
        !            89:        EVP_DigestInit(&md, evp_md);
        !            90:        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
        !            91:        EVP_DigestFinal(&md, digest, NULL);
        !            92:
        !            93:        buffer_free(&b);
        !            94:
        !            95: #ifdef DEBUG_KEX
        !            96:        dump_digest("hash", digest, evp_md->md_size);
        !            97: #endif
        !            98:        return digest;
        !            99: }
        !           100:
        !           101: /* client */
        !           102:
        !           103: void
        !           104: kexdh_client(Kex *kex)
        !           105: {
        !           106:        State *state;
        !           107:
        !           108:        dispatch_set(SSH2_MSG_KEXDH_REPLY, &kexdh_input_reply);
        !           109:
        !           110:        state = xmalloc(sizeof(State));
        !           111:        kex->state = state;
        !           112:
        !           113:        /* generate and send 'e', client DH public key */
        !           114:        state->dh = dh_new_group1();
        !           115:        dh_gen_key(state->dh, kex->we_need * 8);
        !           116:        packet_start(SSH2_MSG_KEXDH_INIT);
        !           117:        packet_put_bignum2(state->dh->pub_key);
        !           118:        packet_send();
        !           119:
        !           120:        debug("SSH2_MSG_KEXDH_INIT sent");
        !           121: #ifdef DEBUG_KEXDH
        !           122:        DHparams_print_fp(stderr, state->dh);
        !           123:        fprintf(stderr, "pub= ");
        !           124:        BN_print_fp(stderr, state->dh->pub_key);
        !           125:        fprintf(stderr, "\n");
        !           126: #endif
        !           127: }
        !           128:
        !           129: void
        !           130: kexdh_input_reply(int type, int plen, void *ctxt)
        !           131: {
        !           132:        BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
        !           133:        Key *server_host_key;
        !           134:        char *server_host_key_blob = NULL, *signature = NULL;
        !           135:        u_char *kbuf, *hash;
        !           136:        u_int klen, kout, slen, sbloblen;
        !           137:        int dlen;
        !           138:        Kex *kex = (Kex *)ctxt;
        !           139:        State *state = (State *)kex->state;
        !           140:
        !           141:        debug("SSH2_MSG_KEXDH_REPLY received");
        !           142:        dispatch_set(SSH2_MSG_KEXDH_REPLY, &kex_protocol_error);
        !           143:
        !           144:        /* key, cert */
        !           145:        server_host_key_blob = packet_get_string(&sbloblen);
        !           146:        server_host_key = key_from_blob(server_host_key_blob, sbloblen);
        !           147:        if (server_host_key == NULL)
        !           148:                fatal("cannot decode server_host_key_blob");
        !           149:
        !           150:        if (kex->check_host_key == NULL)
        !           151:                fatal("cannot check server_host_key");
        !           152:        kex->check_host_key(server_host_key);
        !           153:
        !           154:        /* DH paramter f, server public DH key */
        !           155:        dh_server_pub = BN_new();
        !           156:        if (dh_server_pub == NULL)
        !           157:                fatal("dh_server_pub == NULL");
        !           158:        packet_get_bignum2(dh_server_pub, &dlen);
        !           159:
        !           160: #ifdef DEBUG_KEXDH
        !           161:        fprintf(stderr, "dh_server_pub= ");
        !           162:        BN_print_fp(stderr, dh_server_pub);
        !           163:        fprintf(stderr, "\n");
        !           164:        debug("bits %d", BN_num_bits(dh_server_pub));
        !           165: #endif
        !           166:
        !           167:        /* signed H */
        !           168:        signature = packet_get_string(&slen);
        !           169:        packet_done();
        !           170:
        !           171:        if (!dh_pub_is_valid(state->dh, dh_server_pub))
        !           172:                packet_disconnect("bad server public DH value");
        !           173:
        !           174:        klen = DH_size(state->dh);
        !           175:        kbuf = xmalloc(klen);
        !           176:        kout = DH_compute_key(kbuf, dh_server_pub, state->dh);
        !           177: #ifdef DEBUG_KEXDH
        !           178:        dump_digest("shared secret", kbuf, kout);
        !           179: #endif
        !           180:        shared_secret = BN_new();
        !           181:        BN_bin2bn(kbuf, kout, shared_secret);
        !           182:        memset(kbuf, 0, klen);
        !           183:        xfree(kbuf);
        !           184:
        !           185:        /* calc and verify H */
        !           186:        hash = kex_dh_hash(
        !           187:            kex->client_version_string,
        !           188:            kex->server_version_string,
        !           189:            buffer_ptr(&kex->my), buffer_len(&kex->my),
        !           190:            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
        !           191:            server_host_key_blob, sbloblen,
        !           192:            state->dh->pub_key,
        !           193:            dh_server_pub,
        !           194:            shared_secret
        !           195:        );
        !           196:        xfree(server_host_key_blob);
        !           197:        DH_free(state->dh);
        !           198:        BN_free(dh_server_pub);
        !           199:
        !           200:        if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1)
        !           201:                fatal("key_verify failed for server_host_key");
        !           202:        key_free(server_host_key);
        !           203:        xfree(signature);
        !           204:
        !           205:        kex_derive_keys(kex, hash, shared_secret);
        !           206:        BN_clear_free(shared_secret);
        !           207:        packet_set_kex(kex);
        !           208:        kex_send_newkeys();
        !           209:
        !           210:        /* save session id */
        !           211:        session_id2_len = 20;
        !           212:        session_id2 = xmalloc(session_id2_len);
        !           213:        memcpy(session_id2, hash, session_id2_len);
        !           214:
        !           215:        xfree(state);
        !           216:        kex->state = NULL;
        !           217: }
        !           218:
        !           219: /* server */
        !           220:
        !           221: void
        !           222: kexdh_server(Kex *kex)
        !           223: {
        !           224:        State *state;
        !           225:
        !           226:        dispatch_set(SSH2_MSG_KEXDH_INIT, &kexdh_input_init);
        !           227:
        !           228:        state = xmalloc(sizeof(*state));
        !           229:        kex->state = state;
        !           230:
        !           231:        /* generate server DH public key */
        !           232:        state->dh = dh_new_group1();
        !           233:        dh_gen_key(state->dh, kex->we_need * 8);
        !           234: }
        !           235:
        !           236: void
        !           237: kexdh_input_init(int type, int plen, void *ctxt)
        !           238: {
        !           239:        BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
        !           240:        Key *server_host_key;
        !           241:        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
        !           242:        u_int sbloblen, klen, kout;
        !           243:        int dlen, slen;
        !           244:        Kex *kex = (Kex*) ctxt;
        !           245:        State *state = (State*) kex->state;
        !           246:        DH *dh = state->dh;
        !           247:
        !           248:        debug("SSH2_MSG_KEXDH_INIT received");
        !           249:        dispatch_set(SSH2_MSG_KEXDH_INIT, &kex_protocol_error);
        !           250:
        !           251:        if (kex->load_host_key == NULL)
        !           252:                fatal("Cannot load hostkey");
        !           253:        server_host_key = kex->load_host_key(kex->hostkey_type);
        !           254:        if (server_host_key == NULL)
        !           255:                fatal("Unsupported hostkey type %d", kex->hostkey_type);
        !           256:
        !           257:        /* key, cert */
        !           258:        dh_client_pub = BN_new();
        !           259:        if (dh_client_pub == NULL)
        !           260:                fatal("dh_client_pub == NULL");
        !           261:        packet_get_bignum2(dh_client_pub, &dlen);
        !           262:
        !           263: #ifdef DEBUG_KEXDH
        !           264:        fprintf(stderr, "dh_client_pub= ");
        !           265:        BN_print_fp(stderr, dh_client_pub);
        !           266:        fprintf(stderr, "\n");
        !           267:        debug("bits %d", BN_num_bits(dh_client_pub));
        !           268: #endif
        !           269:
        !           270: #ifdef DEBUG_KEXDH
        !           271:        DHparams_print_fp(stderr, dh);
        !           272:        fprintf(stderr, "pub= ");
        !           273:        BN_print_fp(stderr, dh->pub_key);
        !           274:        fprintf(stderr, "\n");
        !           275: #endif
        !           276:        if (!dh_pub_is_valid(dh, dh_client_pub))
        !           277:                packet_disconnect("bad client public DH value");
        !           278:
        !           279:        klen = DH_size(dh);
        !           280:        kbuf = xmalloc(klen);
        !           281:        kout = DH_compute_key(kbuf, dh_client_pub, dh);
        !           282: #ifdef DEBUG_KEXDH
        !           283:        dump_digest("shared secret", kbuf, kout);
        !           284: #endif
        !           285:        shared_secret = BN_new();
        !           286:        BN_bin2bn(kbuf, kout, shared_secret);
        !           287:        memset(kbuf, 0, klen);
        !           288:        xfree(kbuf);
        !           289:
        !           290:        key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
        !           291:
        !           292:        /* calc H */
        !           293:        hash = kex_dh_hash(
        !           294:            kex->client_version_string,
        !           295:            kex->server_version_string,
        !           296:            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
        !           297:            buffer_ptr(&kex->my), buffer_len(&kex->my),
        !           298:            (char *)server_host_key_blob, sbloblen,
        !           299:            dh_client_pub,
        !           300:            dh->pub_key,
        !           301:            shared_secret
        !           302:        );
        !           303:        BN_free(dh_client_pub);
        !           304:
        !           305:        /* save session id := H */
        !           306:        /* XXX hashlen depends on KEX */
        !           307:        session_id2_len = 20;
        !           308:        session_id2 = xmalloc(session_id2_len);
        !           309:        memcpy(session_id2, hash, session_id2_len);
        !           310:
        !           311:        /* sign H */
        !           312:        /* XXX hashlen depends on KEX */
        !           313:        key_sign(server_host_key, &signature, &slen, hash, 20);
        !           314:
        !           315:        /* destroy_sensitive_data(); */
        !           316:
        !           317:        /* send server hostkey, DH pubkey 'f' and singed H */
        !           318:        packet_start(SSH2_MSG_KEXDH_REPLY);
        !           319:        packet_put_string((char *)server_host_key_blob, sbloblen);
        !           320:        packet_put_bignum2(dh->pub_key);        /* f */
        !           321:        packet_put_string((char *)signature, slen);
        !           322:        packet_send();
        !           323:        xfree(signature);
        !           324:        xfree(server_host_key_blob);
        !           325:
        !           326:        kex_derive_keys(kex, hash, shared_secret);
        !           327:        BN_clear_free(shared_secret);
        !           328:        packet_set_kex(kex);
        !           329:        kex_send_newkeys();
        !           330:
        !           331:        /* have keys, free DH */
        !           332:        DH_free(dh);
        !           333:        xfree(state);
        !           334:        kex->state = NULL;
        !           335: }
        !           336:
        !           337: void
        !           338: kexdh(Kex *kex)
        !           339: {
        !           340:        if (kex->server)
        !           341:                kexdh_server(kex);
        !           342:        else
        !           343:                kexdh_client(kex);
        !           344: }