server_keyexchange.c 5.74 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 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
 */

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "server_keyexchange.h"

#include "atoms.h"
#include "format.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

struct install_keys *make_server_install_keys(void **algorithms);

static int do_handle_dh_init(struct packet_handler *c,
			      struct ssh_connection *connection,
			      struct lsh_string *packet)
{
  struct dh_server *closure = (struct dh_server *) c;
  struct hash_instance *hash;
  struct lsh_string *s;
  int res;
  
  if (!dh_process_client_msg(&closure->dh, packet))
    {
      disconnect_kex_failed(connection, "Bad dh-init\r\n");
      return WRITE_CLOSED;
    }
  
#if 0
  signer = LOOKUP_SIGNER(closure->signer, closure->dh.server_host_key);

  if (!signer)
    /* FIXME: Use a more appropriate error code. Should probably have
     * a separate file for sending and recieving various types of
     * disconnects. */
    return disconnect_kex_failed(connection, "Bad server host key\r\n");
#endif
  
#if 0
  if (!dh_verify_server_msg(&closure->dh, v))
    /* FIXME: Same here */
    return disconnect_kex_failed(connection, "Bad server host key\r\n");
#endif

  /* Send server's message, to complete key exchange */
  res = A_WRITE(connection->write, dh_make_server_msg(&closure->dh,
						      closure->signer));

  if (res != WRITE_OK)
    return res;
  
  /* Send a newkeys message, and install a handler for recieving the
   * newkeys message. */

  res = A_WRITE(connection->write, ssh_format("%c", SSH_MSG_NEWKEYS));
  if (res != WRITE_OK)
    return res;

  /* 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);
  
  res = INSTALL_KEYS(closure->install, connection, hash);

  lsh_free(hash);

  /* Reinstall keyexchange handler */
  connection->dispatch[SSH_MSG_KEXINIT] = closure->saved_kexinit_handler;
  
  return res;
}

static int do_init_dh(struct keyexchange_algorithm *c,
		      struct ssh_connection *connection,
		      int hostkey_algorithm_atom,
		      struct signature_algorithm *ignored,
		      void **algorithms)
{
  struct dh_server_exchange *closure = (struct dh_server_exchange *) c;
  struct dh_server *dh = xalloc(sizeof(struct dh_server));

  /* 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);

  dh->signer = closure->signer;

  dh->install = make_server_install_keys(algorithms);

#if 0
  /* Send server's message */
  A_WRITE(connection->write, dh_make_server_msg(&dh->dh));
#endif
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXDH_INIT] = &dh->super;

  /* Disable kexinit handler */
  dh->saved_kexinit_handler = connection->dispatch[SSH_MSG_KEXINIT];
  connection->dispatch[SSH_MSG_KEXINIT] = connection->fail;

  return WRITE_OK;
}


/* 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
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
struct keyexchange_algorithm *
make_dh_server(struct diffie_hellman_method *dh,
	       struct signer *signer)
{
  struct dh_server_exchange *self = xalloc(sizeof(struct dh_server_exchange));

  self->super.init = do_init_dh;
  self->dh = dh;
  self->signer = signer;

  return &self->super;
}

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

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 */

  struct server_install_keys *closure = (struct server_install_keys *) c;
Niels Möller's avatar
Niels Möller committed
172
  
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  /* 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;
}

struct install_keys *make_server_install_keys(void **algorithms)
{
  struct server_install_keys *self = xalloc(sizeof(struct server_install_keys));

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

  return &self->super;
}