server_keyexchange.c 8.98 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
 * $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
J.H.M. Dassen's avatar
J.H.M. Dassen committed
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Niels Möller's avatar
Niels Möller committed
22
23
 */

24
25
26
#include "server_keyexchange.h"

#include "atoms.h"
27
#include "command.h"
28
#include "debug.h"
29
#include "dsa.h"
30
#include "format.h"
31
32
#include "sexp_commands.h"
#include "srp.h"
33
34
35
36
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

37
38
#include <assert.h>

39
40
#include "server_keyexchange.c.x"

41
/* GABA:
42
43
44
45
   (class
     (name dh_server_exchange)
     (super keyexchange_algorithm)
     (vars
46
       (dh object dh_method)))
47
48
*/

49
/* Handler for the kex_dh_reply message */
50
/* GABA:
51
52
53
54
   (class
     (name dh_server)
     (super packet_handler)
     (vars
55
       (dh struct dh_instance)
56
       (hostkey_algorithm . int)
57
       (server_key string)
58
       (signer object signer)
59
       (algorithms object object_list)))
60
61
*/

Niels Möller's avatar
Niels Möller committed
62
63
64
65
static void
do_handle_dh_init(struct packet_handler *c,
		  struct ssh_connection *connection,
		  struct lsh_string *packet)
66
{
67
  CAST(dh_server, closure, c);
68
69
  int res;
  
70
  trace("handle_dh_init\n");
71
72

  res = dh_process_client_msg(&closure->dh, packet);
73
  
74
  if (!res)
75
76
    {
      disconnect_kex_failed(connection, "Bad dh-init\r\n");
Niels Möller's avatar
Niels Möller committed
77
      return;
78
79
80
    }
  
  /* Send server's message, to complete key exchange */
Niels Möller's avatar
Niels Möller committed
81
82
  C_WRITE(connection,
	  dh_make_server_msg(&closure->dh,
83
			     closure->server_key,
84
			     closure->hostkey_algorithm,
Niels Möller's avatar
Niels Möller committed
85
			     closure->signer));
86

87
  connection->dispatch[SSH_MSG_KEXDH_INIT] = &connection_fail_handler;
88

89
  keyexchange_finish(connection, closure->algorithms,
90
		     closure->dh.method->H,
91
92
93
94
95
96
		     closure->dh.exchange_hash,
		     closure->dh.K);

  /* For gc */
  closure->dh.K = NULL;
  closure->dh.exchange_hash = NULL;
97
98
99

  /* Try to purge information about the key exchange */
  KILL(closure);
100
101
}

Niels Möller's avatar
Niels Möller committed
102
103
104
static void
do_init_server_dh(struct keyexchange_algorithm *c,
		  struct ssh_connection *connection,
105
		  int hostkey_algorithm,
106
		  struct lsh_object *extra,
Niels Möller's avatar
Niels Möller committed
107
		  struct object_list *algorithms)
108
{
109
  CAST(dh_server_exchange, closure, c);
110
111
  CAST_SUBTYPE(alist, keys, extra);
  CAST(keypair, key, ALIST_GET(keys,
112
			       hostkey_algorithm));
113
114

  if (!key)
115
116
    {
      werror("Keypair for for selected signature-algorithm not found!\n");
117
      disconnect_kex_failed(connection, "Configuration error");
Niels Möller's avatar
Niels Möller committed
118
      return;
119
    }
120
121
122
123
124
125
126
  else
    {
      NEW(dh_server, dh);
      
      /* Initialize */
      dh->super.handler = do_handle_dh_init;
      init_dh_instance(closure->dh, &dh->dh, connection);
127

128
      dh->server_key = lsh_string_dup(key->public);
129
      dh->signer = key->private;
Balázs Scheidler's avatar
Balázs Scheidler committed
130
131

#if DATAFELLOWS_WORKAROUNDS
132
      if ( (hostkey_algorithm == ATOM_SSH_DSS)
133
134
	   && (connection->peer_flags & PEER_SSH_DSS_KLUDGE))
	{
135
	  hostkey_algorithm = ATOM_SSH_DSS_KLUDGE_LOCAL;
136
	}
Balázs Scheidler's avatar
Balázs Scheidler committed
137
#endif
138
      dh->hostkey_algorithm = hostkey_algorithm;
Balázs Scheidler's avatar
Balázs Scheidler committed
139

140
      dh->algorithms = algorithms;
141
  
142
143
      /* Generate server's secret exponent */
      dh_make_server_secret(&dh->dh);
144
  
145
146
147
      /* Install handler */
      connection->dispatch[SSH_MSG_KEXDH_INIT] = &dh->super;
    }
148
149
150
151
}


struct keyexchange_algorithm *
152
make_dh_server(struct dh_method *dh)
153
{
154
  NEW(dh_server_exchange, self);
155

156
  self->super.init = do_init_server_dh;
157
158
159
160
161
  self->dh = dh;

  return &self->super;
}

162
163
164
165
166
167
168
169
170

#if WITH_SRP
/* SRP key exchange */

/* GABA:
   (class
     (name srp_server_instance)
     (vars
       (dh struct dh_instance)
171
       (algorithms object object_list)
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
       (db object user_db)
       (user object lsh_user)
       (entry object srp_entry)))
*/

/* GABA:
   (class
     (name srp_server_handler)
     (super packet_handler)
     (vars
       (srp object srp_server_instance)))
*/

static void
do_srp_server_proof_handler(struct packet_handler *s,
			    struct ssh_connection *connection,
			    struct lsh_string *packet)
{
  CAST(srp_server_handler, self, s);

  struct lsh_string *response = srp_process_client_proof(&self->srp->dh, packet);

194
  connection->dispatch[SSH_MSG_KEXSRP_PROOF] = &connection_fail_handler;
195
196
197
198
199
  
  if (response)
    {
      C_WRITE(connection, response);

200
201
      /* Remember that a user was authenticated. */
      connection->user = self->srp->user;
202
      connection->flags |= CONNECTION_SRP;
203
      
204
      keyexchange_finish(connection, self->srp->algorithms,
205
			 self->srp->dh.method->H,
206
207
208
209
210
			 self->srp->dh.exchange_hash,
			 self->srp->dh.K);
      /* For gc */
      self->srp->dh.K = NULL;
      self->srp->dh.exchange_hash = NULL;
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
    }
  else
    PROTOCOL_ERROR(connection->e, "Invalid SSH_MSG_KEXSRP_PROOF message");

  /* Try to purge information about the key exchange */
  KILL(self->srp);
  KILL(self);
}

static struct packet_handler *
make_srp_server_proof_handler(struct srp_server_instance *srp)
{
  NEW(srp_server_handler, self);
  self->super.handler = do_srp_server_proof_handler;
  self->srp = srp;

  return &self->super;
}

static void
do_exc_srp(struct exception_handler *e,
	   const struct exception *x)
{
234
235
  /* FIXME: Filter the error messages. E.g. "No more sexps" doesn't
   * make much sense to the client. */
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  EXCEPTION_RAISE(e->parent,
		  make_protocol_exception(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
					  x->msg));
}

/* Invoked after that we have read an sexp that represents a user's verifier */
/* GABA:
   (class
     (name srp_init_continuation)
     (super command_continuation)
     (vars
       (srp object srp_server_instance)
       (connection object ssh_connection)))
*/

static void
do_srp_init_continuation(struct command_continuation *s,
			 struct lsh_object *a)
{
  CAST(srp_init_continuation, self, s);
  CAST_SUBTYPE(sexp, e, a);

  self->srp->entry = make_srp_entry(self->srp->user->name, e);

  if (!self->srp->entry)
    {
      disconnect_kex_failed(self->connection, "Invalid SRP verifier");
      return;
    }

  C_WRITE(self->connection, srp_make_reply_msg(&self->srp->dh, self->srp->entry));
  self->connection->dispatch[SSH_MSG_KEXSRP_PROOF] = make_srp_server_proof_handler(self->srp);
}

static struct command_continuation *
make_server_srp_continuation(struct srp_server_instance *srp,
			     struct ssh_connection *connection)
{
  NEW(srp_init_continuation, self);
  self->super.c = do_srp_init_continuation;
  self->srp = srp;
  self->connection = connection;

  return &self->super;
}

282
283
#define MAX_SRP_SIZE 2000

284
285
286
287
288
289
290
291
292
static void
do_handle_srp_init(struct packet_handler *s,
		   struct ssh_connection *connection,
		   struct lsh_string *packet)
{
  CAST(srp_server_handler, self, s);
  struct lsh_string *name = srp_process_init_msg(&self->srp->dh, packet);
  struct exception_handler *e;
  
293
  connection->dispatch[SSH_MSG_KEXSRP_INIT] = &connection_fail_handler;
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  
  if (!name)
    {
      PROTOCOL_ERROR(connection->e, "Invalid SSH_MSG_KEXSRP_INIT message");
      return;
    }

  self->srp->user = USER_LOOKUP(self->srp->db, name, 1);
  if (!self->srp->user)
    {
      EXCEPTION_RAISE(connection->e,
		      make_protocol_exception(SSH_DISCONNECT_ILLEGAL_USER_NAME, NULL));
      return;
    }

  /* Try opening the user's ~/.lsh/srp-verifier */
  e = make_exception_handler(do_exc_srp, connection->e, HANDLER_CONTEXT);
  
  USER_READ_FILE(self->srp->user, "srp-verifier", 1,		 
313
		 make_apply(make_read_sexp_command(SEXP_CANONICAL, 0, MAX_SRP_SIZE),
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
			    make_server_srp_continuation(self->srp, connection),
			    e),
		 e);
}

static struct packet_handler *
make_srp_init_handler(struct srp_server_instance *srp)
{
  NEW(srp_server_handler, self);
  self->super.handler = do_handle_srp_init;
  self->srp = srp;

  return &self->super;
}

/* GABA:
   (class
     (name srp_server_exchange)
     (super keyexchange_algorithm)
     (vars
       (dh object dh_method)
       (db object user_db)))
*/

static void
do_init_server_srp(struct keyexchange_algorithm *s,
		   struct ssh_connection *connection,
341
		   int hostkey_algorithm UNUSED,
342
343
344
345
346
347
348
349
350
351
		   struct lsh_object *extra UNUSED,
		   struct object_list *algorithms)
{
  CAST(srp_server_exchange, self, s);

  NEW(srp_server_instance, srp);

  /* Initialize */
  init_dh_instance(self->dh, &srp->dh, connection);

352
  srp->algorithms = algorithms;
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  srp->db = self->db;
  srp->user = NULL;
  srp->entry = NULL;
  
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXSRP_INIT] = make_srp_init_handler(srp);
}

struct keyexchange_algorithm *
make_srp_server(struct dh_method *dh,
		struct user_db *db)
{
  NEW(srp_server_exchange, self);

367
368
369
  assert(dh->G->add);
  assert(dh->G->subtract);
  
370
371
372
373
374
375
376
377
  self->super.init = do_init_server_srp;
  self->dh = dh;
  self->db = db;
  
  return &self->super;
}

#endif /* WITH_SRP */