server_keyexchange.c 4.87 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
#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)))
*/

45
/* Handler for the kex_dh_reply message */
46
47
48
49
50
51
52
53
54
55
56
57
/* 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)))
*/

58
static int do_handle_dh_init(struct packet_handler *c,
59
60
			     struct ssh_connection *connection,
			     struct lsh_string *packet)
61
{
62
  CAST(dh_server, closure, c);
63
64
65
  struct hash_instance *hash;
  struct lsh_string *s;
  int res;
66
67

  verbose("handle_dh_init()\n");
68
69
70
71
  
  if (!dh_process_client_msg(&closure->dh, packet))
    {
      disconnect_kex_failed(connection, "Bad dh-init\r\n");
72
      return LSH_FAIL | LSH_CLOSE;
73
74
75
76
77
78
    }
  
  /* Send server's message, to complete key exchange */
  res = A_WRITE(connection->write, dh_make_server_msg(&closure->dh,
						      closure->signer));

79
  if (LSH_CLOSEDP(res))
80
81
    return res;
  
Niels Möller's avatar
Niels Möller committed
82
  /* Send a newkeys message, and install a handler for receiving the
83
84
   * newkeys message. */

85
86
  res |= A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
  if (LSH_CLOSEDP(res))
87
    return res;
88
  
89
90
91
92
93
94
95
96
97
98
99
100
101
  /* 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);
102

103
104
105
106
107
108
109
  if (!INSTALL_KEYS(closure->install, connection, hash))
    {
      werror("Installing new keys failed. Hanging up.\n");
      KILL(hash);
      /* FIXME: Send a disconnect message */
      return LSH_FAIL | LSH_DIE;
    }
110

111
  KILL(hash);
112

113
114
  connection->kex_state = KEX_STATE_NEWKEYS;
  connection->dispatch[SSH_MSG_KEXDH_INIT] = connection->fail;
115

116
117
  res |= send_verbose(connection->write, "Key exchange successful!", 0);
  if (LSH_CLOSEDP(res))
118
    return res;
119
  
120
  return res | SERVICE_INIT(closure->finished, connection);
121
122
123
124
}

static int do_init_dh(struct keyexchange_algorithm *c,
		      struct ssh_connection *connection,
125
		      struct ssh_service *finished,
126
127
		      int hostkey_algorithm_atom,
		      struct signature_algorithm *ignored,
128
		      struct object_list *algorithms)
129
{
130
131
  CAST(dh_server_exchange, closure, c);
  NEW(dh_server, dh);
132

133
134
135
  CHECK_TYPE(ssh_connection, connection);
  CHECK_SUBTYPE(ssh_service, finished);
  CHECK_SUBTYPE(signature_algorithm, ignored);
136
  
137
138
139
140
141
142
143
144
  /* 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);

145
  dh->dh.server_key = lsh_string_dup(closure->server_key);
146
  dh->signer = closure->signer;
147
  dh->install = make_install_new_keys(1, algorithms);
148
149
  dh->finished = finished;
  
150
151
152
  /* Generate server's secret exponent */
  dh_make_server_secret(&dh->dh);
  
153
154
155
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXDH_INIT] = &dh->super;

156
  connection->kex_state = KEX_STATE_IN_PROGRESS;
157

Niels Möller's avatar
Niels Möller committed
158
  return LSH_OK  | LSH_GOON;
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->signer-function. The init-method should use this
 * mapping to find an appropriate signer function. */
Niels Möller's avatar
Niels Möller committed
166

167
168
struct keyexchange_algorithm *
make_dh_server(struct diffie_hellman_method *dh,
169
	       struct lsh_string *server_key,
170
171
	       struct signer *signer)
{
172
  NEW(dh_server_exchange, self);
173
174
175

  self->super.init = do_init_dh;
  self->dh = dh;
176
  self->server_key = server_key;
177
178
179
180
181
  self->signer = signer;

  return &self->super;
}