client_keyexchange.c 5.99 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* client_keyexchange.c
 *
Niels Möller's avatar
Niels Möller committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Möller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
22
23
 */

Niels Möller's avatar
Niels Möller committed
24
25
#include "client_keyexchange.h"

26
#include "atoms.h"
27
#include "debug.h"
28
29
30
31
32
#include "format.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
struct dh_client_exchange
{
  struct keyexchange_algorithm super;
  struct diffie_hellman_method *dh;
  struct lookup_verifier *verifier;
};

/* Handler for the kex_dh_reply message */
struct dh_client
{
  struct packet_handler super;
  struct diffie_hellman_instance dh;
  struct lookup_verifier *verifier;
  struct install_keys *install;
};
48
49

static int do_handle_dh_reply(struct packet_handler *c,
Niels Möller's avatar
Niels Möller committed
50
51
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
52
53
54
{
  struct dh_client *closure = (struct dh_client *) c;
  struct verifier *v;
55
  struct hash_instance *hash;
56
  struct lsh_string *s;
57
  int res;
Niels Möller's avatar
Niels Möller committed
58

Niels Möller's avatar
Niels Möller committed
59
60
  MDEBUG(closure);
  
Niels Möller's avatar
Niels Möller committed
61
  verbose("handle_dh_reply()\n");
Niels Möller's avatar
Niels Möller committed
62
63
  
  if (!dh_process_server_msg(&closure->dh, packet))
64
65
    {
      disconnect_kex_failed(connection, "Bad dh-reply\r\n");
Niels Möller's avatar
Niels Möller committed
66
      return LSH_FAILURE | LSH_CLOSE;
67
68
69
    }
    
  v = LOOKUP_VERIFIER(closure->verifier, closure->dh.server_key);
Niels Möller's avatar
Niels Möller committed
70
71

  if (!v)
Niels Möller's avatar
Niels Möller committed
72
    /* FIXME: Use a more appropriate error code? */
73
74
    {
      disconnect_kex_failed(connection, "Bad server host key\r\n");
Niels Möller's avatar
Niels Möller committed
75
      return LSH_FAILURE | LSH_CLOSE;
76
77
    }
  
Niels Möller's avatar
Niels Möller committed
78
79
  if (!dh_verify_server_msg(&closure->dh, v))
    /* FIXME: Same here */
Niels Möller's avatar
Niels Möller committed
80
    return disconnect_kex_failed(connection, "Invalid server signature\r\n");
Niels Möller's avatar
Niels Möller committed
81
    
82
83
84
  /* Key exchange successful! Send a newkeys message, and install a
   * handler for recieving the newkeys message. */

85
  res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
Niels Möller's avatar
Niels Möller committed
86
  if (LSH_PROBLEMP(res))
87
88
    return res;

89
90
  /* Record session id */
  if (!connection->session_id)
Niels Möller's avatar
Niels Möller committed
91
92
93
94
    {
      connection->session_id = closure->dh.exchange_hash;
      closure->dh.exchange_hash = NULL; /* For gc */
    }
Niels Möller's avatar
Niels Möller committed
95
  
96
  /* A hash instance initialized with the key, to be used for key generation */
Niels Möller's avatar
Niels Möller committed
97
  
98
99
  hash = MAKE_HASH(closure->dh.method->H);
  s = ssh_format("%n", closure->dh.K);
100
101
  HASH_UPDATE(hash, s->length, s->data);
  lsh_string_free(s);
102
103
  
  res = INSTALL_KEYS(closure->install, connection, hash);
104
105
106

  lsh_free(hash);

107
108
  connection->dispatch[SSH_MSG_KEXDH_REPLY] = connection->fail;
  connection->kex_state = KEX_STATE_NEWKEYS;
109
  
110
  return send_verbose(connection->write, "Key exchange successful!", 0);
Niels Möller's avatar
Niels Möller committed
111
112
}

113
static int do_init_dh(struct keyexchange_algorithm *c,
Niels Möller's avatar
Niels Möller committed
114
115
116
117
		      struct ssh_connection *connection,
		      int hostkey_algorithm_atom,
		      struct signature_algorithm *ignored,
		      void **algorithms)
Niels Möller's avatar
Niels Möller committed
118
{
119
  struct dh_client_exchange *closure = (struct dh_client_exchange *) c;
Niels Möller's avatar
Niels Möller committed
120
121
  struct dh_client *dh = xalloc(sizeof(struct dh_client));

Niels Möller's avatar
Niels Möller committed
122
  int res;
Niels Möller's avatar
Niels Möller committed
123
124
125
126

  MDEBUG(c);
  MDEBUG(connection);
  MDEBUG(ignored);
Niels Möller's avatar
Niels Möller committed
127
  
128
129
130
131
  /* FIXME: Use this value to choose a verifier function */
  if (hostkey_algorithm_atom != ATOM_SSH_DSS)
    fatal("Internal error\n");
  
Niels Möller's avatar
Niels Möller committed
132
133
134
135
  /* Initialize */
  dh->super.handler = do_handle_dh_reply;
  init_diffie_hellman_instance(closure->dh, &dh->dh, connection);

136
  dh->verifier = closure->verifier;
Niels Möller's avatar
Niels Möller committed
137

138
139
  dh->install = make_client_install_keys(algorithms);
  
Niels Möller's avatar
Niels Möller committed
140
  /* Send client's message */
Niels Möller's avatar
Niels Möller committed
141
142
  res = A_WRITE(connection->write, dh_make_client_msg(&dh->dh));

Niels Möller's avatar
Niels Möller committed
143
  if (LSH_PROBLEMP(res))
Niels Möller's avatar
Niels Möller committed
144
    return res;
145
  
Niels Möller's avatar
Niels Möller committed
146
147
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXDH_REPLY] = &dh->super;
148
149
150
  
  connection->kex_state = KEX_STATE_IN_PROGRESS;
  
Niels Möller's avatar
Niels Möller committed
151
  return LSH_OK | LSH_GOON;
Niels Möller's avatar
Niels Möller committed
152
153
}

154
155
156
157
158
159
160
161
162
163
164
165

/* FIXME: This assumes that there's only one hostkey-algorithm. To
 * fix, this constructor should take a mapping
 * algorithm->verifier-function. The init-method should use this
 * mapping to find an appropriate verifier function. */

struct keyexchange_algorithm *
make_dh_client(struct diffie_hellman_method *dh,
	       struct lookup_verifier *verifier)
{
  struct dh_client_exchange *self = xalloc(sizeof(struct dh_client_exchange));

Niels Möller's avatar
Niels Möller committed
166
167
  MDEBUG(dh);
  
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  self->super.init = do_init_dh;
  self->dh = dh;
  self->verifier = verifier;

  return &self->super;
}

struct client_install_keys
{
  struct install_keys super;
  void **algorithms;
};

static int do_install(struct install_keys *c,
Niels Möller's avatar
Niels Möller committed
182
183
		      struct ssh_connection *connection,
		      struct hash_instance *secret)
184
185
186
187
188
{
  /* FIXME: For DES, instantiating a crypto may fail, if the key
   * happens to be weak. */
  /* FIXME: No IV:s */

189
  struct client_install_keys *closure = (struct client_install_keys *) c;
Niels Möller's avatar
Niels Möller committed
190
191
192

  MDEBUG(closure);

193
194
195
196
197
198
199
200
201
202
203
204
  /* Keys for recieving */
  connection->dispatch[SSH_MSG_NEWKEYS] = make_newkeys_handler
    (kex_make_encrypt(secret, closure->algorithms,
		      KEX_ENCRYPTION_SERVER_TO_CLIENT, connection),
     kex_make_mac(secret, closure->algorithms,
		  KEX_MAC_SERVER_TO_CLIENT, connection));

  /* Keys for sending */
  /* NOTE: The NEWKEYS-message should have been sent before this
   * function is called */
  connection->send_crypto 
    = kex_make_decrypt(secret, closure->algorithms,
Niels Möller's avatar
Niels Möller committed
205
		       KEX_ENCRYPTION_CLIENT_TO_SERVER, connection);
206
  
207
208
209
  connection->send_mac 
    = kex_make_mac(secret, closure->algorithms,
		   KEX_MAC_CLIENT_TO_SERVER, connection);
210

211
212
213
214
215
216
217
218
219
220
221
222
  return 1;
}

struct install_keys *make_client_install_keys(void **algorithms)
{
  struct client_install_keys *self = xalloc(sizeof(struct client_install_keys));

  self->super.install = do_install;
  self->algorithms = algorithms;

  return &self->super;
}