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

Annotation of src/usr.bin/ssh/kex.c, Revision 1.4

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"
1.4     ! markus     31: RCSID("$Id: kex.c,v 1.3 2000/04/12 07:03:05 markus Exp $");
1.1       markus     32:
                     33: #include "ssh.h"
                     34: #include "ssh2.h"
                     35: #include "xmalloc.h"
                     36: #include "buffer.h"
                     37: #include "bufaux.h"
                     38: #include "cipher.h"
                     39: #include "compat.h"
                     40:
1.4     ! markus     41: #include <openssl/bn.h>
        !            42: #include <openssl/dh.h>
1.1       markus     43:
1.4     ! markus     44: #include <openssl/crypto.h>
        !            45: #include <openssl/bio.h>
        !            46: #include <openssl/bn.h>
        !            47: #include <openssl/dh.h>
        !            48: #include <openssl/pem.h>
1.1       markus     49:
                     50: #include "kex.h"
                     51:
                     52: Buffer *
                     53: kex_init(char *myproposal[PROPOSAL_MAX])
                     54: {
                     55:        char c = 0;
                     56:        unsigned char cookie[16];
                     57:        u_int32_t rand = 0;
                     58:        int i;
                     59:        Buffer *ki = xmalloc(sizeof(*ki));
                     60:        for (i = 0; i < 16; i++) {
                     61:                if (i % 4 == 0)
                     62:                        rand = arc4random();
                     63:                cookie[i] = rand & 0xff;
                     64:                rand >>= 8;
                     65:        }
                     66:        buffer_init(ki);
                     67:        buffer_append(ki, (char *)cookie, sizeof cookie);
                     68:        for (i = 0; i < PROPOSAL_MAX; i++)
                     69:                buffer_put_cstring(ki, myproposal[i]);
                     70:        buffer_append(ki, &c, 1); /* boolean   first_kex_packet_follows */
                     71:        buffer_put_int(ki, 0);    /* uint32    0 (reserved for future extension) */
                     72:        return ki;
                     73: }
                     74:
                     75: /* diffie-hellman-group1-sha1 */
                     76:
1.3       markus     77: int
                     78: dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
                     79: {
                     80:        int i;
                     81:        int n = BN_num_bits(dh_pub);
                     82:        int bits_set = 0;
                     83:
                     84:        /* we only accept g==2 */
                     85:        if (!BN_is_word(dh->g, 2)) {
                     86:                log("invalid DH base != 2");
                     87:                return 0;
                     88:        }
                     89:        if (dh_pub->neg) {
                     90:                log("invalid public DH value: negativ");
                     91:                return 0;
                     92:        }
                     93:        for (i = 0; i <= n; i++)
                     94:                if (BN_is_bit_set(dh_pub, i))
                     95:                        bits_set++;
                     96:        debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
                     97:
                     98:        /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
                     99:        if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
                    100:                return 1;
                    101:        log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
                    102:        return 0;
                    103: }
                    104:
1.1       markus    105: DH *
1.3       markus    106: dh_new_group1()
1.1       markus    107: {
                    108:        static char *group1 =
                    109:            "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
                    110:            "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
                    111:            "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
                    112:            "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
                    113:            "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
                    114:            "FFFFFFFF" "FFFFFFFF";
                    115:        DH *dh;
1.3       markus    116:        int ret, tries = 0;
1.1       markus    117:        dh = DH_new();
                    118:        if(dh == NULL)
                    119:                fatal("DH_new");
1.3       markus    120:        ret = BN_hex2bn(&dh->p, group1);
1.1       markus    121:        if(ret<0)
                    122:                fatal("BN_hex2bn");
                    123:        dh->g = BN_new();
                    124:        if(dh->g == NULL)
                    125:                fatal("DH_new g");
1.3       markus    126:        BN_set_word(dh->g, 2);
                    127:        do {
                    128:                if (DH_generate_key(dh) == 0)
                    129:                        fatal("DH_generate_key");
                    130:                if (tries++ > 10)
                    131:                        fatal("dh_new_group1: too many bad keys: giving up");
                    132:        } while (!dh_pub_is_valid(dh, dh->pub_key));
1.1       markus    133:        return dh;
                    134: }
                    135:
                    136: void
                    137: bignum_print(BIGNUM *b)
                    138: {
                    139:        BN_print_fp(stderr,b);
                    140: }
                    141:
                    142: void
                    143: dump_digest(unsigned char *digest, int len)
                    144: {
                    145:        int i;
                    146:         for (i = 0; i< len; i++){
                    147:                 fprintf(stderr, "%02x", digest[i]);
                    148:                if(i%2!=0)
                    149:                        fprintf(stderr, " ");
                    150:        }
                    151:         fprintf(stderr, "\n");
                    152: }
                    153:
                    154: unsigned char *
                    155: kex_hash(
                    156:     char *client_version_string,
                    157:     char *server_version_string,
                    158:     char *ckexinit, int ckexinitlen,
                    159:     char *skexinit, int skexinitlen,
                    160:     char *serverhostkeyblob, int sbloblen,
                    161:     BIGNUM *client_dh_pub,
                    162:     BIGNUM *server_dh_pub,
                    163:     BIGNUM *shared_secret)
                    164: {
                    165:        Buffer b;
                    166:        static unsigned char digest[EVP_MAX_MD_SIZE];
                    167:        EVP_MD *evp_md = EVP_sha1();
                    168:        EVP_MD_CTX md;
                    169:
                    170:        buffer_init(&b);
                    171:        buffer_put_string(&b, client_version_string, strlen(client_version_string));
                    172:        buffer_put_string(&b, server_version_string, strlen(server_version_string));
                    173:
                    174:        /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
                    175:        buffer_put_int(&b, ckexinitlen+1);
                    176:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
                    177:        buffer_append(&b, ckexinit, ckexinitlen);
                    178:        buffer_put_int(&b, skexinitlen+1);
                    179:        buffer_put_char(&b, SSH2_MSG_KEXINIT);
                    180:        buffer_append(&b, skexinit, skexinitlen);
                    181:
                    182:        buffer_put_string(&b, serverhostkeyblob, sbloblen);
                    183:        buffer_put_bignum2(&b, client_dh_pub);
                    184:        buffer_put_bignum2(&b, server_dh_pub);
                    185:        buffer_put_bignum2(&b, shared_secret);
                    186:
                    187: #ifdef DEBUG_KEX
                    188:        buffer_dump(&b);
                    189: #endif
                    190:
                    191:        EVP_DigestInit(&md, evp_md);
                    192:        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
                    193:        EVP_DigestFinal(&md, digest, NULL);
                    194:
                    195:        buffer_free(&b);
                    196:
                    197: #ifdef DEBUG_KEX
                    198:         dump_digest(digest, evp_md->md_size);
                    199: #endif
                    200:        return digest;
                    201: }
                    202:
                    203: unsigned char *
                    204: derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
                    205: {
                    206:        Buffer b;
                    207:        EVP_MD *evp_md = EVP_sha1();
                    208:        EVP_MD_CTX md;
                    209:        char c = id;
                    210:        int have;
                    211:        int mdsz = evp_md->md_size;
                    212:        unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
                    213:
                    214:        buffer_init(&b);
                    215:        buffer_put_bignum2(&b, shared_secret);
                    216:
                    217:        EVP_DigestInit(&md, evp_md);
                    218:        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));  /* shared_secret K */
                    219:        EVP_DigestUpdate(&md, hash, mdsz);              /* transport-06 */
                    220:        EVP_DigestUpdate(&md, &c, 1);                   /* key id */
                    221:        EVP_DigestUpdate(&md, hash, mdsz);              /* session id */
                    222:        EVP_DigestFinal(&md, digest, NULL);
                    223:
                    224:        /* expand */
                    225:        for (have = mdsz; need > have; have += mdsz) {
                    226:                EVP_DigestInit(&md, evp_md);
                    227:                EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
                    228:                EVP_DigestUpdate(&md, hash, mdsz);
                    229:                EVP_DigestUpdate(&md, digest, have);
                    230:                EVP_DigestFinal(&md, digest + have, NULL);
                    231:        }
                    232:        buffer_free(&b);
                    233: #ifdef DEBUG_KEX
                    234:        fprintf(stderr, "Digest '%c'== ", c);
                    235:        dump_digest(digest, need);
                    236: #endif
                    237:        return digest;
                    238: }
                    239:
                    240: #define NKEYS  6
                    241:
                    242: #define        MAX_PROP        20
                    243: #define        SEP     ","
                    244:
                    245: char *
                    246: get_match(char *client, char *server)
                    247: {
                    248:        char *sproposals[MAX_PROP];
                    249:        char *p;
                    250:        int i, j, nproposals;
                    251:
                    252:        for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
                    253:                if (i < MAX_PROP)
                    254:                        sproposals[i] = p;
                    255:                else
                    256:                        break;
                    257:        }
                    258:        nproposals = i;
                    259:
                    260:        for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
                    261:                for (j = 0; j < nproposals; j++)
                    262:                        if (strcmp(p, sproposals[j]) == 0)
                    263:                                return xstrdup(p);
                    264:        }
                    265:        return NULL;
                    266: }
                    267: void
                    268: choose_enc(Enc *enc, char *client, char *server)
                    269: {
                    270:        char *name = get_match(client, server);
                    271:        if (name == NULL)
                    272:                fatal("no matching cipher found: client %s server %s", client, server);
                    273:        enc->type = cipher_number(name);
                    274:
                    275:        switch (enc->type) {
                    276:        case SSH_CIPHER_3DES_CBC:
                    277:                enc->key_len = 24;
                    278:                enc->iv_len = 8;
                    279:                enc->block_size = 8;
                    280:                break;
                    281:        case SSH_CIPHER_BLOWFISH_CBC:
                    282:        case SSH_CIPHER_CAST128_CBC:
                    283:                enc->key_len = 16;
                    284:                enc->iv_len = 8;
                    285:                enc->block_size = 8;
                    286:                break;
                    287:        case SSH_CIPHER_ARCFOUR:
                    288:                enc->key_len = 16;
                    289:                enc->iv_len = 0;
                    290:                enc->block_size = 8;
                    291:                break;
                    292:        default:
                    293:                fatal("unsupported cipher %s", name);
                    294:        }
                    295:        enc->name = name;
                    296:        enc->enabled = 0;
                    297:        enc->iv = NULL;
                    298:        enc->key = NULL;
                    299: }
                    300: void
                    301: choose_mac(Mac *mac, char *client, char *server)
                    302: {
                    303:        char *name = get_match(client, server);
                    304:        if (name == NULL)
                    305:                fatal("no matching mac found: client %s server %s", client, server);
                    306:        if (strcmp(name, "hmac-md5") == 0) {
                    307:                mac->md = EVP_md5();
                    308:        } else if (strcmp(name, "hmac-sha1") == 0) {
                    309:                mac->md = EVP_sha1();
                    310:        } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
                    311:                mac->md = EVP_ripemd160();
                    312:        } else {
                    313:                fatal("unsupported mac %s", name);
                    314:        }
                    315:        mac->name = name;
                    316:        mac->mac_len = mac->md->md_size;
                    317:        mac->key_len = datafellows ? 16 : mac->mac_len;
                    318:        mac->key = NULL;
                    319:        mac->enabled = 0;
                    320: }
                    321: void
                    322: choose_comp(Comp *comp, char *client, char *server)
                    323: {
                    324:        char *name = get_match(client, server);
                    325:        if (name == NULL)
                    326:                fatal("no matching comp found: client %s server %s", client, server);
                    327:        if (strcmp(name, "zlib") == 0) {
                    328:                comp->type = 1;
                    329:        } else if (strcmp(name, "none") == 0) {
                    330:                comp->type = 0;
                    331:        } else {
                    332:                fatal("unsupported comp %s", name);
                    333:        }
                    334:        comp->name = name;
                    335: }
                    336: void
                    337: choose_kex(Kex *k, char *client, char *server)
                    338: {
                    339:        k->name = get_match(client, server);
                    340:        if (k->name == NULL)
                    341:                fatal("no kex alg");
                    342:        if (strcmp(k->name, KEX_DH1) != 0)
                    343:                fatal("bad kex alg %s", k->name);
                    344: }
                    345: void
                    346: choose_hostkeyalg(Kex *k, char *client, char *server)
                    347: {
                    348:        k->hostkeyalg = get_match(client, server);
                    349:        if (k->hostkeyalg == NULL)
                    350:                fatal("no hostkey alg");
                    351:        if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
                    352:                fatal("bad hostkey alg %s", k->hostkeyalg);
                    353: }
                    354:
                    355: Kex *
                    356: kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
                    357: {
                    358:        int i;
                    359:        int mode;
                    360:        int ctos;                               /* direction: if true client-to-server */
                    361:        int need;
                    362:        Kex *k;
                    363:
                    364:        k = xmalloc(sizeof(*k));
                    365:        memset(k, 0, sizeof(*k));
                    366:        k->server = server;
                    367:
                    368:        for (mode = 0; mode < MODE_MAX; mode++) {
                    369:                int nenc, nmac, ncomp;
                    370:                ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
                    371:                nenc  = ctos ? PROPOSAL_ENC_ALGS_CTOS  : PROPOSAL_ENC_ALGS_STOC;
                    372:                nmac  = ctos ? PROPOSAL_MAC_ALGS_CTOS  : PROPOSAL_MAC_ALGS_STOC;
                    373:                ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
                    374:                choose_enc (&k->enc [mode], cprop[nenc],  sprop[nenc]);
                    375:                choose_mac (&k->mac [mode], cprop[nmac],  sprop[nmac]);
                    376:                choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
1.2       markus    377:                debug("kex: %s %s %s %s",
1.1       markus    378:                    ctos ? "client->server" : "server->client",
                    379:                    k->enc[mode].name,
                    380:                    k->mac[mode].name,
                    381:                    k->comp[mode].name);
                    382:        }
                    383:        choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
                    384:        choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
                    385:            sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
                    386:        for (i = 0; i < PROPOSAL_MAX; i++) {
                    387:                xfree(cprop[i]);
                    388:                xfree(sprop[i]);
                    389:        }
                    390:        need = 0;
                    391:        for (mode = 0; mode < MODE_MAX; mode++) {
                    392:            if (need < k->enc[mode].key_len)
                    393:                    need = k->enc[mode].key_len;
                    394:            if (need < k->enc[mode].iv_len)
                    395:                    need = k->enc[mode].iv_len;
                    396:            if (need < k->mac[mode].key_len)
                    397:                    need = k->mac[mode].key_len;
                    398:        }
                    399:        /* need runden? */
                    400: #define WE_NEED 32
                    401:        k->we_need = WE_NEED;
                    402:        k->we_need = need;
                    403:        return k;
                    404: }
                    405:
                    406: int
                    407: kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
                    408: {
                    409:        int i;
                    410:        int mode;
                    411:        int ctos;
                    412:        unsigned char *keys[NKEYS];
                    413:
                    414:        for (i = 0; i < NKEYS; i++)
                    415:                keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
                    416:
                    417:        for (mode = 0; mode < MODE_MAX; mode++) {
                    418:                ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
                    419:                k->enc[mode].iv  = keys[ctos ? 0 : 1];
                    420:                k->enc[mode].key = keys[ctos ? 2 : 3];
                    421:                k->mac[mode].key = keys[ctos ? 4 : 5];
                    422:        }
                    423:        return 0;
                    424: }