client_keyexchange.c 4.66 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* client_keyexchange.c
 *
3
 */
Niels Möller's avatar
Niels Möller committed
4
5
6

/* lsh, an implementation of the ssh protocol
 *
7
 * Copyright (C) 1998, 2005 Niels Mller
Niels Möller's avatar
Niels Möller committed
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * 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
27
28
29
#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <assert.h>

30
#include "keyexchange.h"
Niels Möller's avatar
Niels Möller committed
31

32
#include "atoms.h"
33
#include "crypto.h"
34
#include "format.h"
35
#include "lsh_string.h"
36
#include "parse.h"
37
#include "ssh.h"
38
#include "transport.h"
39
40
41
#include "werror.h"
#include "xalloc.h"

42
43
#include "client_keyexchange.c.x"

44
/* GABA:
45
   (class
46
     (name client_dh_exchange)
47
48
     (super keyexchange_algorithm)
     (vars
49
50
       (params const object dh_params)
       (db object lookup_verifier)))
51
52
*/

53
/* Handler for the KEXDH_REPLY message */
54
/* GABA:
55
   (class
56
57
     (name client_dh_handler)
     (super transport_handler)
58
     (vars
59
60
61
       (dh struct dh_state)
       (db object lookup_verifier)
       (hostkey_algorithm . int)))
62
*/
63

Niels Möller's avatar
Niels Möller committed
64
static void
65
66
67
client_dh_handler(struct transport_handler *s,
		  struct transport_connection *connection,
		  uint32_t length, const uint8_t *packet)
Niels Möller's avatar
Niels Möller committed
68
{
69
70
71
72
73
74
  CAST(client_dh_handler, self, s);
  struct simple_buffer buffer;
  uint32_t key_length;
  const uint8_t *key;
  uint32_t signature_length;
  const uint8_t *signature;
75
  
76
  trace("client_dh_handler\n");
Niels Möller's avatar
Niels Möller committed
77

78
79
  assert(length > 0);
  if (packet[0] != SSH_MSG_KEXDH_REPLY)
Niels Möller's avatar
Niels Möller committed
80
    {
81
82
      transport_disconnect(connection, SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
			   "No KEXDH_REPLY message.");
Niels Möller's avatar
Niels Möller committed
83
84
      return;
    }
Niels Möller's avatar
Niels Möller committed
85

86
87
88
89
90
91
92
  simple_buffer_init(&buffer, length-1, packet+1);
  if (parse_string(&buffer, &key_length, &key)
      && parse_bignum(&buffer, self->dh.f, self->dh.params->limit)
      && (mpz_cmp_ui(self->dh.f, 1) > 0)
      && (mpz_cmp(self->dh.f, self->dh.params->modulo) < 0)
      && parse_string(&buffer, &signature_length, &signature)
      && parse_eod(&buffer))
Niels Möller's avatar
Niels Möller committed
93
    {
94
95
96
97
98
99
100
101
102
103
      mpz_t tmp;
      
      struct verifier *v = LOOKUP_VERIFIER(self->db, self->hostkey_algorithm,
					   key_length, key);
      if (!v)
	{
	  transport_disconnect(connection, SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
			       "Unknown server host key");
	  return;
	}
104

105
106
      /* Construct key */
      mpz_init(tmp);
107

108
109
110
      mpz_powm(tmp, self->dh.f, self->dh.secret, self->dh.params->modulo);
      self->dh.K = ssh_format("%ln", tmp);
      mpz_clear(tmp);
111

112
      debug("Session key: %xS\n", self->dh.K);
113

114
115
      dh_hash_update(&self->dh, ssh_format("%s", key_length, key), 1);
      dh_hash_digest(&self->dh);
116

117
      debug("Exchange hash: %xS\n", self->dh.exchange_hash);
118
      
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
      if (!VERIFY(v, self->hostkey_algorithm,
		  lsh_string_length(self->dh.exchange_hash),
		  lsh_string_data(self->dh.exchange_hash),
		  signature_length, signature))
	{
	  transport_disconnect(connection, SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
			       "Invalid server signature");
	  return;	 
	}

      transport_keyexchange_finish(connection,
				   self->dh.params->H,
				   self->dh.exchange_hash,
				   self->dh.K);
      self->dh.exchange_hash = NULL;
      self->dh.K = NULL;      
135
136
    }
  else
137
138
    transport_disconnect(connection, SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
			 "Invalid KEXDH_REPLY message");
139
140
}

141
142
143
static struct transport_handler *
client_dh_init(struct keyexchange_algorithm *s,
	       struct transport_connection *connection)
144
{
145
146
  CAST(client_dh_exchange, self, s);
  NEW(client_dh_handler, handler);
147
148

  /* Initialize */
149
  init_dh_state(&handler->dh, self->params, &connection->kex);  
150

151
152
153
  handler->super.handler = client_dh_handler;
  handler->db = self->db;
  handler->hostkey_algorithm = connection->kex.hostkey_algorithm;
154
  
155
  /* Generate clients 's secret exponent */
156
  dh_generate_secret(self->params, handler->dh.secret, handler->dh.e);
157

158
  /* Send client's message */
159
160
  transport_send_packet(connection, 1,
			ssh_format("%c%n", SSH_MSG_KEXDH_INIT, handler->dh.e));
161
162

  /* Install handler */
163
  return &handler->super;
164
165
}

166

167
struct keyexchange_algorithm *
168
169
make_client_dh_exchange(const struct dh_params *params,
			struct lookup_verifier *db)
170
{
171
  NEW(client_dh_exchange, self);
172

173
174
175
  self->super.init = client_dh_init;
  self->params = params;
  self->db = db;
176
177
178
  
  return &self->super;
}