server_keyexchange.c 6.67 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* server_keyexchange.c
 *
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 Mller
 *
 * 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
 */

24
25
26
#include "server_keyexchange.h"

#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
#include "server_keyexchange.c.x"

/* CLASS:
   (class
     (name dh_server_exchange)
     (super keyexchange_algorithm)
     (vars
       (dh object diffie_hellman_method)
       (server_key string)
       (signer object signer)))
*/

#if 0
46
47
48
49
50
51
52
struct dh_server_exchange
{
  struct keyexchange_algorithm super;
  struct diffie_hellman_method *dh;
  struct lsh_string *server_key;
  struct signer *signer;
};
53
#endif
54
55

/* Handler for the kex_dh_reply message */
56
57
58
59
60
61
62
63
64
65
66
67
68
/* CLASS:
   (class
     (name dh_server)
     (super packet_handler)
     (vars
       (dh struct diffie_hellman_instance)
       ;; (server_key string)
       (signer object signer)
       (install object install_keys)
       (finished object ssh_service)))
*/

#if 0
69
70
71
72
73
74
75
struct dh_server
{
  struct packet_handler super;
  struct diffie_hellman_instance dh;
  /* struct lsh_string *server_key; */
  struct signer *signer;
  struct install_keys *install;
76
77
  
  struct ssh_service *finished;
78
};
79
#endif
80
81

static int do_handle_dh_init(struct packet_handler *c,
82
83
			     struct ssh_connection *connection,
			     struct lsh_string *packet)
84
{
85
  CAST(dh_server, closure, c);
86
87
88
  struct hash_instance *hash;
  struct lsh_string *s;
  int res;
89
90

  verbose("handle_dh_init()\n");
91
92
93
94
  
  if (!dh_process_client_msg(&closure->dh, packet))
    {
      disconnect_kex_failed(connection, "Bad dh-init\r\n");
95
      return LSH_FAIL | LSH_CLOSE;
96
97
98
99
100
101
    }
  
  /* Send server's message, to complete key exchange */
  res = A_WRITE(connection->write, dh_make_server_msg(&closure->dh,
						      closure->signer));

102
  if (LSH_CLOSEDP(res))
103
104
105
106
107
    return res;
  
  /* Send a newkeys message, and install a handler for recieving the
   * newkeys message. */

108
109
  res |= A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
  if (LSH_CLOSEDP(res))
110
    return res;
111
  
112
113
114
115
116
117
118
119
120
121
122
123
124
  /* Record session id */
  if (!connection->session_id)
    {
      connection->session_id = closure->dh.exchange_hash;
      closure->dh.exchange_hash = NULL; /* For gc */
    }
  
  /* A hash instance initialized with the key, to be used for key generation */
  
  hash = MAKE_HASH(closure->dh.method->H);
  s = ssh_format("%n", closure->dh.K);
  HASH_UPDATE(hash, s->length, s->data);
  lsh_string_free(s);
125
126
127

  /* FIXME: Return value is ignored */
  (void) INSTALL_KEYS(closure->install, connection, hash);
128

129
  KILL(hash);
130

131
132
  connection->kex_state = KEX_STATE_NEWKEYS;
  connection->dispatch[SSH_MSG_KEXDH_INIT] = connection->fail;
133

134
135
  res |= send_verbose(connection->write, "Key exchange successful!", 0);
  if (LSH_CLOSEDP(res))
136
    return res;
137
  
138
  return res | SERVICE_INIT(closure->finished, connection);
139
140
141
142
}

static int do_init_dh(struct keyexchange_algorithm *c,
		      struct ssh_connection *connection,
143
		      struct ssh_service *finished,
144
145
		      int hostkey_algorithm_atom,
		      struct signature_algorithm *ignored,
146
		      struct object_list *algorithms)
147
{
148
149
  CAST(dh_server_exchange, closure, c);
  NEW(dh_server, dh);
150

151
152
153
  CHECK_TYPE(ssh_connection, connection);
  CHECK_SUBTYPE(ssh_service, finished);
  CHECK_SUBTYPE(signature_algorithm, ignored);
154
  
155
156
157
158
159
160
161
162
  /* FIXME: Use this value to choose a signer function */
  if (hostkey_algorithm_atom != ATOM_SSH_DSS)
    fatal("Internal error\n");
  
  /* Initialize */
  dh->super.handler = do_handle_dh_init;
  init_diffie_hellman_instance(closure->dh, &dh->dh, connection);

163
  dh->dh.server_key = lsh_string_dup(closure->server_key);
164
165
  dh->signer = closure->signer;
  dh->install = make_server_install_keys(algorithms);
166
167
  dh->finished = finished;
  
168
169
170
  /* Generate server's secret exponent */
  dh_make_server_secret(&dh->dh);
  
171
172
173
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXDH_INIT] = &dh->super;

174
  connection->kex_state = KEX_STATE_IN_PROGRESS;
175

Niels Möller's avatar
Niels Möller committed
176
  return LSH_OK  | LSH_GOON;
177
178
179
180
181
182
183
}


/* FIXME: This assumes that there's only one hostkey-algorithm. To
 * fix, this constructor should take a mapping
 * algorithm->signer-function. The init-method should use this
 * mapping to find an appropriate signer function. */
Niels Möller's avatar
Niels Möller committed
184

185
186
struct keyexchange_algorithm *
make_dh_server(struct diffie_hellman_method *dh,
187
	       struct lsh_string *server_key,
188
189
	       struct signer *signer)
{
190
  NEW(dh_server_exchange, self);
191
192
193

  self->super.init = do_init_dh;
  self->dh = dh;
194
  self->server_key = server_key;
195
196
197
198
199
  self->signer = signer;

  return &self->super;
}

200
201
202
203
204
205
206
207
208
209
210
211
/* FIXME: This is identical to the client_install_keys structure in
 * client_keyexchange.c. It should probably be moved somewhere else. */

/* CLASS:
   (class
     (name server_install_keys)
     (super install_keys)
     (vars
       (algorithms object object_list)))
*/

#if 0
212
213
214
struct server_install_keys
{
  struct install_keys super;
215
  struct object_list *algorithms;
216
};
217
#endif
218
219
220
221
222
223
224
225
226

static int do_install(struct install_keys *c,
		      struct ssh_connection *connection,
		      struct hash_instance *secret)
{
  /* FIXME: For DES, instantiating a crypto may fail, if the key
   * happens to be weak. */
  /* FIXME: No IV:s */

227
  CAST(server_install_keys, closure, c);
Niels Möller's avatar
Niels Möller committed
228
  
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  /* Keys for recieving */
  connection->dispatch[SSH_MSG_NEWKEYS] = make_newkeys_handler
    (kex_make_encrypt(secret, closure->algorithms,
		      KEX_ENCRYPTION_CLIENT_TO_SERVER, connection),
     kex_make_mac(secret, closure->algorithms,
		  KEX_MAC_CLIENT_TO_SERVER, 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,
		       KEX_ENCRYPTION_SERVER_TO_CLIENT, connection);
  
  connection->send_mac 
    = kex_make_mac(secret, closure->algorithms,
		   KEX_MAC_SERVER_TO_CLIENT, connection);

  return 1;
}

250
struct install_keys *make_server_install_keys(struct object_list *algorithms)
251
{
252
  NEW(server_install_keys, self);
253
254
255
256
257
258

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

  return &self->super;
}