source: trunk/third/openssh/kexdh.c @ 18759

Revision 18759, 8.4 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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"
26RCSID("$OpenBSD: kexdh.c,v 1.18 2002/03/18 17:50:31 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 "packet.h"
38#include "dh.h"
39#include "ssh2.h"
40#include "monitor_wrap.h"
41
42static u_char *
43kex_dh_hash(
44    char *client_version_string,
45    char *server_version_string,
46    char *ckexinit, int ckexinitlen,
47    char *skexinit, int skexinitlen,
48    u_char *serverhostkeyblob, int sbloblen,
49    BIGNUM *client_dh_pub,
50    BIGNUM *server_dh_pub,
51    BIGNUM *shared_secret)
52{
53        Buffer b;
54        static u_char digest[EVP_MAX_MD_SIZE];
55        const EVP_MD *evp_md = EVP_sha1();
56        EVP_MD_CTX md;
57
58        buffer_init(&b);
59        buffer_put_cstring(&b, client_version_string);
60        buffer_put_cstring(&b, server_version_string);
61
62        /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
63        buffer_put_int(&b, ckexinitlen+1);
64        buffer_put_char(&b, SSH2_MSG_KEXINIT);
65        buffer_append(&b, ckexinit, ckexinitlen);
66        buffer_put_int(&b, skexinitlen+1);
67        buffer_put_char(&b, SSH2_MSG_KEXINIT);
68        buffer_append(&b, skexinit, skexinitlen);
69
70        buffer_put_string(&b, serverhostkeyblob, sbloblen);
71        buffer_put_bignum2(&b, client_dh_pub);
72        buffer_put_bignum2(&b, server_dh_pub);
73        buffer_put_bignum2(&b, shared_secret);
74
75#ifdef DEBUG_KEX
76        buffer_dump(&b);
77#endif
78        EVP_DigestInit(&md, evp_md);
79        EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
80        EVP_DigestFinal(&md, digest, NULL);
81
82        buffer_free(&b);
83
84#ifdef DEBUG_KEX
85        dump_digest("hash", digest, EVP_MD_size(evp_md));
86#endif
87        return digest;
88}
89
90/* client */
91
92static void
93kexdh_client(Kex *kex)
94{
95        BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
96        DH *dh;
97        Key *server_host_key;
98        u_char *server_host_key_blob = NULL, *signature = NULL;
99        u_char *kbuf, *hash;
100        u_int klen, kout, slen, sbloblen;
101
102        /* generate and send 'e', client DH public key */
103        dh = dh_new_group1();
104        dh_gen_key(dh, kex->we_need * 8);
105        packet_start(SSH2_MSG_KEXDH_INIT);
106        packet_put_bignum2(dh->pub_key);
107        packet_send();
108
109        debug("sending SSH2_MSG_KEXDH_INIT");
110#ifdef DEBUG_KEXDH
111        DHparams_print_fp(stderr, dh);
112        fprintf(stderr, "pub= ");
113        BN_print_fp(stderr, dh->pub_key);
114        fprintf(stderr, "\n");
115#endif
116
117        debug("expecting SSH2_MSG_KEXDH_REPLY");
118        packet_read_expect(SSH2_MSG_KEXDH_REPLY);
119
120        /* key, cert */
121        server_host_key_blob = packet_get_string(&sbloblen);
122        server_host_key = key_from_blob(server_host_key_blob, sbloblen);
123        if (server_host_key == NULL)
124                fatal("cannot decode server_host_key_blob");
125        if (server_host_key->type != kex->hostkey_type)
126                fatal("type mismatch for decoded server_host_key_blob");
127        if (kex->verify_host_key == NULL)
128                fatal("cannot verify server_host_key");
129        if (kex->verify_host_key(server_host_key) == -1)
130                fatal("server_host_key verification failed");
131
132        /* DH paramter f, server public DH key */
133        if ((dh_server_pub = BN_new()) == NULL)
134                fatal("dh_server_pub == NULL");
135        packet_get_bignum2(dh_server_pub);
136
137#ifdef DEBUG_KEXDH
138        fprintf(stderr, "dh_server_pub= ");
139        BN_print_fp(stderr, dh_server_pub);
140        fprintf(stderr, "\n");
141        debug("bits %d", BN_num_bits(dh_server_pub));
142#endif
143
144        /* signed H */
145        signature = packet_get_string(&slen);
146        packet_check_eom();
147
148        if (!dh_pub_is_valid(dh, dh_server_pub))
149                packet_disconnect("bad server public DH value");
150
151        klen = DH_size(dh);
152        kbuf = xmalloc(klen);
153        kout = DH_compute_key(kbuf, dh_server_pub, dh);
154#ifdef DEBUG_KEXDH
155        dump_digest("shared secret", kbuf, kout);
156#endif
157        if ((shared_secret = BN_new()) == NULL)
158                fatal("kexdh_client: BN_new failed");
159        BN_bin2bn(kbuf, kout, shared_secret);
160        memset(kbuf, 0, klen);
161        xfree(kbuf);
162
163        /* calc and verify H */
164        hash = kex_dh_hash(
165            kex->client_version_string,
166            kex->server_version_string,
167            buffer_ptr(&kex->my), buffer_len(&kex->my),
168            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
169            server_host_key_blob, sbloblen,
170            dh->pub_key,
171            dh_server_pub,
172            shared_secret
173        );
174        xfree(server_host_key_blob);
175        BN_clear_free(dh_server_pub);
176        DH_free(dh);
177
178        if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
179                fatal("key_verify failed for server_host_key");
180        key_free(server_host_key);
181        xfree(signature);
182
183        /* save session id */
184        if (kex->session_id == NULL) {
185                kex->session_id_len = 20;
186                kex->session_id = xmalloc(kex->session_id_len);
187                memcpy(kex->session_id, hash, kex->session_id_len);
188        }
189
190        kex_derive_keys(kex, hash, shared_secret);
191        BN_clear_free(shared_secret);
192        kex_finish(kex);
193}
194
195/* server */
196
197static void
198kexdh_server(Kex *kex)
199{
200        BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
201        DH *dh;
202        Key *server_host_key;
203        u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
204        u_int sbloblen, klen, kout;
205        u_int slen;
206
207        /* generate server DH public key */
208        dh = dh_new_group1();
209        dh_gen_key(dh, kex->we_need * 8);
210
211        debug("expecting SSH2_MSG_KEXDH_INIT");
212        packet_read_expect(SSH2_MSG_KEXDH_INIT);
213
214        if (kex->load_host_key == NULL)
215                fatal("Cannot load hostkey");
216        server_host_key = kex->load_host_key(kex->hostkey_type);
217        if (server_host_key == NULL)
218                fatal("Unsupported hostkey type %d", kex->hostkey_type);
219
220        /* key, cert */
221        if ((dh_client_pub = BN_new()) == NULL)
222                fatal("dh_client_pub == NULL");
223        packet_get_bignum2(dh_client_pub);
224        packet_check_eom();
225
226#ifdef DEBUG_KEXDH
227        fprintf(stderr, "dh_client_pub= ");
228        BN_print_fp(stderr, dh_client_pub);
229        fprintf(stderr, "\n");
230        debug("bits %d", BN_num_bits(dh_client_pub));
231#endif
232
233#ifdef DEBUG_KEXDH
234        DHparams_print_fp(stderr, dh);
235        fprintf(stderr, "pub= ");
236        BN_print_fp(stderr, dh->pub_key);
237        fprintf(stderr, "\n");
238#endif
239        if (!dh_pub_is_valid(dh, dh_client_pub))
240                packet_disconnect("bad client public DH value");
241
242        klen = DH_size(dh);
243        kbuf = xmalloc(klen);
244        kout = DH_compute_key(kbuf, dh_client_pub, dh);
245#ifdef DEBUG_KEXDH
246        dump_digest("shared secret", kbuf, kout);
247#endif
248        if ((shared_secret = BN_new()) == NULL)
249                fatal("kexdh_server: BN_new failed");
250        BN_bin2bn(kbuf, kout, shared_secret);
251        memset(kbuf, 0, klen);
252        xfree(kbuf);
253
254        key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
255
256        /* calc H */
257        hash = kex_dh_hash(
258            kex->client_version_string,
259            kex->server_version_string,
260            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
261            buffer_ptr(&kex->my), buffer_len(&kex->my),
262            server_host_key_blob, sbloblen,
263            dh_client_pub,
264            dh->pub_key,
265            shared_secret
266        );
267        BN_clear_free(dh_client_pub);
268
269        /* save session id := H */
270        /* XXX hashlen depends on KEX */
271        if (kex->session_id == NULL) {
272                kex->session_id_len = 20;
273                kex->session_id = xmalloc(kex->session_id_len);
274                memcpy(kex->session_id, hash, kex->session_id_len);
275        }
276
277        /* sign H */
278        /* XXX hashlen depends on KEX */
279        PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
280
281        /* destroy_sensitive_data(); */
282
283        /* send server hostkey, DH pubkey 'f' and singed H */
284        packet_start(SSH2_MSG_KEXDH_REPLY);
285        packet_put_string(server_host_key_blob, sbloblen);
286        packet_put_bignum2(dh->pub_key);        /* f */
287        packet_put_string(signature, slen);
288        packet_send();
289
290        xfree(signature);
291        xfree(server_host_key_blob);
292        /* have keys, free DH */
293        DH_free(dh);
294
295        kex_derive_keys(kex, hash, shared_secret);
296        BN_clear_free(shared_secret);
297        kex_finish(kex);
298}
299
300void
301kexdh(Kex *kex)
302{
303        if (kex->server)
304                kexdh_server(kex);
305        else
306                kexdh_client(kex);
307}
Note: See TracBrowser for help on using the repository browser.