client_keyexchange.c 5.62 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
27
28
29
30
31
32
33
34
#include "atoms.h"
#include "format.h"
#include "ssh.h"
#include "werror.h"
#include "xalloc.h"

struct install_keys *make_client_install_keys(void **algorithms);

static int do_handle_dh_reply(struct packet_handler *c,
Niels Möller's avatar
Niels Möller committed
35
			       struct ssh_connection *connection,
36
			       struct lsh_string *packet)
Niels Möller's avatar
Niels Möller committed
37
38
39
{
  struct dh_client *closure = (struct dh_client *) c;
  struct verifier *v;
40
  struct hash_instance *hash;
41
  struct lsh_string *s;
42
  int res;
Niels Möller's avatar
Niels Möller committed
43
44
  
  if (!dh_process_server_msg(&closure->dh, packet))
45
46
47
48
49
50
    {
      disconnect_kex_failed(connection, "Bad dh-reply\r\n");
      return WRITE_CLOSED;
    }
    
  v = LOOKUP_VERIFIER(closure->verifier, closure->dh.server_key);
Niels Möller's avatar
Niels Möller committed
51
52
53
54
55

  if (!v)
    /* FIXME: Use a more appropriate error code. Should probably have
     * a separate file for sending and recieving various types of
     * disconnects. */
56
57
58
59
60
    {
      disconnect_kex_failed(connection, "Bad server host key\r\n");
      return WRITE_CLOSED;
    }
  
Niels Möller's avatar
Niels Möller committed
61
62
  if (!dh_verify_server_msg(&closure->dh, v))
    /* FIXME: Same here */
63
    return disconnect_kex_failed(connection, "Bad server host key\r\n");
Niels Möller's avatar
Niels Möller committed
64
    
65
66
67
  /* Key exchange successful! Send a newkeys message, and install a
   * handler for recieving the newkeys message. */

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

72
73
  /* Record session id */
  if (!connection->session_id)
Niels Möller's avatar
Niels Möller committed
74
75
76
77
    {
      connection->session_id = closure->dh.exchange_hash;
      closure->dh.exchange_hash = NULL; /* For gc */
    }
Niels Möller's avatar
Niels Möller committed
78
  
79
  /* A hash instance initialized with the key, to be used for key generation */
Niels Möller's avatar
Niels Möller committed
80
  
81
82
  hash = MAKE_HASH(closure->dh.method->H);
  s = ssh_format("%n", closure->dh.K);
83
84
  HASH_UPDATE(hash, s->length, s->data);
  lsh_string_free(s);
85
86
  
  res = INSTALL_KEYS(closure->install, connection, hash);
87
88
89

  lsh_free(hash);

90
91
92
  /* Reinstall keyexchange handler */
  connection->dispatch[SSH_MSG_KEXINIT] = closure->saved_kexinit_handler;
  
93
  return res;
Niels Möller's avatar
Niels Möller committed
94
95
}

96
97
98
99
100
static int do_init_dh(struct keyexchange_algorithm *c,
		       struct ssh_connection *connection,
		       int hostkey_algorithm_atom,
		       struct signature_algorithm *ignored,
		       void **algorithms)
Niels Möller's avatar
Niels Möller committed
101
{
102
  struct dh_client_exchange *closure = (struct dh_client_exchange *) c;
Niels Möller's avatar
Niels Möller committed
103
104
  struct dh_client *dh = xalloc(sizeof(struct dh_client));

105
106
107
108
  /* 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
109
110
111
112
  /* Initialize */
  dh->super.handler = do_handle_dh_reply;
  init_diffie_hellman_instance(closure->dh, &dh->dh, connection);

113
  dh->verifier = closure->verifier;
Niels Möller's avatar
Niels Möller committed
114

115
116
  dh->install = make_client_install_keys(algorithms);
  
Niels Möller's avatar
Niels Möller committed
117
118
  /* Send client's message */
  A_WRITE(connection->write, dh_make_client_msg(&dh->dh));
119
  
Niels Möller's avatar
Niels Möller committed
120
121
122
123
124
125
126
127
128
129
  /* Install handler */
  connection->dispatch[SSH_MSG_KEXDH_REPLY] = &dh->super;

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

  return WRITE_OK;
}

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

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

  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,
	       struct ssh_connection *connection,
	       struct hash_instance *secret)
158
159
160
161
162
{
  /* FIXME: For DES, instantiating a crypto may fail, if the key
   * happens to be weak. */
  /* FIXME: No IV:s */

163
164
165
166
167
168
169
170
171
172
173
174
175
176
  struct client_install_keys *closure = (struct client_install_keys *) c;
  
  /* 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
177
		       KEX_ENCRYPTION_CLIENT_TO_SERVER, connection);
178
  
179
180
181
  connection->send_mac 
    = kex_make_mac(secret, closure->algorithms,
		   KEX_MAC_CLIENT_TO_SERVER, connection);
182

183
184
185
186
187
188
189
190
191
192
193
194
  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;
}