summaryrefslogtreecommitdiff
path: root/kexgexs.c
diff options
context:
space:
mode:
authormarkus@openbsd.org <markus@openbsd.org>2015-01-19 20:16:15 +0000
committerDamien Miller <djm@mindrot.org>2015-01-20 09:19:39 +1100
commit57d10cbe861a235dd269c74fb2fe248469ecee9d (patch)
treec65deed24700490bd3b20300c4829d4d5466ff6d /kexgexs.c
parent3fdc88a0def4f86aa88a5846ac079dc964c0546a (diff)
upstream commit
adapt kex to sshbuf and struct ssh; ok djm@
Diffstat (limited to 'kexgexs.c')
-rw-r--r--kexgexs.c257
1 files changed, 161 insertions, 96 deletions
diff --git a/kexgexs.c b/kexgexs.c
index 1021e0bf6..6e2b009b5 100644
--- a/kexgexs.c
+++ b/kexgexs.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexgexs.c,v 1.20 2015/01/19 19:52:16 markus Exp $ */ 1/* $OpenBSD: kexgexs.c,v 1.21 2015/01/19 20:16:15 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Niels Provos. All rights reserved. 3 * Copyright (c) 2000 Niels Provos. All rights reserved.
4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -37,10 +37,9 @@
37 37
38#include <openssl/dh.h> 38#include <openssl/dh.h>
39 39
40#include "xmalloc.h" 40#include "sshkey.h"
41#include "buffer.h"
42#include "key.h"
43#include "cipher.h" 41#include "cipher.h"
42#include "digest.h"
44#include "kex.h" 43#include "kex.h"
45#include "log.h" 44#include "log.h"
46#include "packet.h" 45#include "packet.h"
@@ -51,33 +50,43 @@
51#include "ssh-gss.h" 50#include "ssh-gss.h"
52#endif 51#endif
53#include "monitor_wrap.h" 52#include "monitor_wrap.h"
53#include "dispatch.h"
54#include "ssherr.h"
55#include "sshbuf.h"
54 56
55void 57static int input_kex_dh_gex_request(int, u_int32_t, void *);
56kexgex_server(Kex *kex) 58static int input_kex_dh_gex_init(int, u_int32_t, void *);
59
60int
61kexgex_server(struct ssh *ssh)
57{ 62{
58 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; 63 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD,
59 Key *server_host_public, *server_host_private; 64 &input_kex_dh_gex_request);
60 DH *dh; 65 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST,
61 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; 66 &input_kex_dh_gex_request);
62 u_int sbloblen, klen, slen, hashlen; 67 debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST");
63 int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; 68 return 0;
64 int type, kout; 69}
70
71static int
72input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
73{
74 struct ssh *ssh = ctxt;
75 struct kex *kex = ssh->kex;
76 int r;
77 u_int min = 0, max = 0, nbits = 0;
65 78
66 if (kex->load_host_public_key == NULL ||
67 kex->load_host_private_key == NULL)
68 fatal("Cannot load hostkey");
69 server_host_public = kex->load_host_public_key(kex->hostkey_type);
70 if (server_host_public == NULL)
71 fatal("Unsupported hostkey type %d", kex->hostkey_type);
72 server_host_private = kex->load_host_private_key(kex->hostkey_type);
73
74 type = packet_read();
75 switch (type) { 79 switch (type) {
76 case SSH2_MSG_KEX_DH_GEX_REQUEST: 80 case SSH2_MSG_KEX_DH_GEX_REQUEST:
77 debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); 81 debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
78 omin = min = packet_get_int(); 82 if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
79 onbits = nbits = packet_get_int(); 83 (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
80 omax = max = packet_get_int(); 84 (r = sshpkt_get_u32(ssh, &max)) != 0 ||
85 (r = sshpkt_get_end(ssh)) != 0)
86 goto out;
87 kex->nbits = nbits;
88 kex->min = min;
89 kex->max = max;
81 min = MAX(DH_GRP_MIN, min); 90 min = MAX(DH_GRP_MIN, min);
82 max = MIN(DH_GRP_MAX, max); 91 max = MIN(DH_GRP_MAX, max);
83 nbits = MAX(DH_GRP_MIN, nbits); 92 nbits = MAX(DH_GRP_MIN, nbits);
@@ -85,45 +94,88 @@ kexgex_server(Kex *kex)
85 break; 94 break;
86 case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: 95 case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
87 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); 96 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
88 onbits = nbits = packet_get_int(); 97 if ((r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
98 (r = sshpkt_get_end(ssh)) != 0)
99 goto out;
100 kex->nbits = nbits;
89 /* unused for old GEX */ 101 /* unused for old GEX */
90 omin = min = DH_GRP_MIN; 102 kex->min = min = DH_GRP_MIN;
91 omax = max = DH_GRP_MAX; 103 kex->max = max = DH_GRP_MAX;
92 break; 104 break;
93 default: 105 default:
94 fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); 106 r = SSH_ERR_INVALID_ARGUMENT;
107 goto out;
95 } 108 }
96 packet_check_eom();
97 109
98 if (omax < omin || onbits < omin || omax < onbits) 110 if (kex->max < kex->min || kex->nbits < kex->min ||
99 fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", 111 kex->max < kex->nbits) {
100 omin, onbits, omax); 112 r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
113 goto out;
114 }
101 115
102 /* Contact privileged parent */ 116 /* Contact privileged parent */
103 dh = PRIVSEP(choose_dh(min, nbits, max)); 117 kex->dh = PRIVSEP(choose_dh(min, nbits, max));
104 if (dh == NULL) 118 if (kex->dh == NULL) {
105 packet_disconnect("Protocol error: no matching DH grp found"); 119 sshpkt_disconnect(ssh, "no matching DH grp found");
106 120 r = SSH_ERR_ALLOC_FAIL;
121 goto out;
122 }
107 debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); 123 debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
108 packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); 124 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
109 packet_put_bignum2(dh->p); 125 (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
110 packet_put_bignum2(dh->g); 126 (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
111 packet_send(); 127 (r = sshpkt_send(ssh)) != 0)
112 128 goto out;
113 /* flush */
114 packet_write_wait();
115 129
116 /* Compute our exchange value in parallel with the client */ 130 /* Compute our exchange value in parallel with the client */
117 dh_gen_key(dh, kex->we_need * 8); 131 if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
132 goto out;
133
134 /* old KEX does not use min/max in kexgex_hash() */
135 if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
136 kex->min = kex->max = -1;
118 137
119 debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); 138 debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
120 packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); 139 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
140 r = 0;
141 out:
142 return r;
143}
144
145static int
146input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
147{
148 struct ssh *ssh = ctxt;
149 struct kex *kex = ssh->kex;
150 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
151 struct sshkey *server_host_public, *server_host_private;
152 u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
153 u_char hash[SSH_DIGEST_MAX_LENGTH];
154 size_t sbloblen, slen;
155 size_t klen = 0, hashlen;
156 int kout, r;
157
158 if (kex->load_host_public_key == NULL ||
159 kex->load_host_private_key == NULL) {
160 r = SSH_ERR_INVALID_ARGUMENT;
161 goto out;
162 }
163 if ((server_host_public = kex->load_host_public_key(kex->hostkey_type,
164 ssh)) == NULL ||
165 (server_host_private = kex->load_host_private_key(kex->hostkey_type,
166 ssh)) == NULL) {
167 r = SSH_ERR_NO_HOSTKEY_LOADED;
168 goto out;
169 }
121 170
122 /* key, cert */ 171 /* key, cert */
123 if ((dh_client_pub = BN_new()) == NULL) 172 if ((dh_client_pub = BN_new()) == NULL) {
124 fatal("dh_client_pub == NULL"); 173 r = SSH_ERR_ALLOC_FAIL;
125 packet_get_bignum2(dh_client_pub); 174 goto out;
126 packet_check_eom(); 175 }
176 if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
177 (r = sshpkt_get_end(ssh)) != 0)
178 goto out;
127 179
128#ifdef DEBUG_KEXDH 180#ifdef DEBUG_KEXDH
129 fprintf(stderr, "dh_client_pub= "); 181 fprintf(stderr, "dh_client_pub= ");
@@ -133,79 +185,92 @@ kexgex_server(Kex *kex)
133#endif 185#endif
134 186
135#ifdef DEBUG_KEXDH 187#ifdef DEBUG_KEXDH
136 DHparams_print_fp(stderr, dh); 188 DHparams_print_fp(stderr, kex->dh);
137 fprintf(stderr, "pub= "); 189 fprintf(stderr, "pub= ");
138 BN_print_fp(stderr, dh->pub_key); 190 BN_print_fp(stderr, kex->dh->pub_key);
139 fprintf(stderr, "\n"); 191 fprintf(stderr, "\n");
140#endif 192#endif
141 if (!dh_pub_is_valid(dh, dh_client_pub)) 193 if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
142 packet_disconnect("bad client public DH value"); 194 sshpkt_disconnect(ssh, "bad client public DH value");
195 r = SSH_ERR_MESSAGE_INCOMPLETE;
196 goto out;
197 }
143 198
144 klen = DH_size(dh); 199 klen = DH_size(kex->dh);
145 kbuf = xmalloc(klen); 200 if ((kbuf = malloc(klen)) == NULL ||
146 if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) 201 (shared_secret = BN_new()) == NULL) {
147 fatal("DH_compute_key: failed"); 202 r = SSH_ERR_ALLOC_FAIL;
203 goto out;
204 }
205 if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
206 BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
207 r = SSH_ERR_LIBCRYPTO_ERROR;
208 goto out;
209 }
148#ifdef DEBUG_KEXDH 210#ifdef DEBUG_KEXDH
149 dump_digest("shared secret", kbuf, kout); 211 dump_digest("shared secret", kbuf, kout);
150#endif 212#endif
151 if ((shared_secret = BN_new()) == NULL) 213 if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
152 fatal("kexgex_server: BN_new failed"); 214 &sbloblen)) != 0)
153 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) 215 goto out;
154 fatal("kexgex_server: BN_bin2bn failed");
155 explicit_bzero(kbuf, klen);
156 free(kbuf);
157
158 key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
159
160 if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
161 omin = min = omax = max = -1;
162
163 /* calc H */ 216 /* calc H */
164 kexgex_hash( 217 hashlen = sizeof(hash);
218 if ((r = kexgex_hash(
165 kex->hash_alg, 219 kex->hash_alg,
166 kex->client_version_string, 220 kex->client_version_string,
167 kex->server_version_string, 221 kex->server_version_string,
168 buffer_ptr(kex->peer), buffer_len(kex->peer), 222 sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
169 buffer_ptr(kex->my), buffer_len(kex->my), 223 sshbuf_ptr(kex->my), sshbuf_len(kex->my),
170 server_host_key_blob, sbloblen, 224 server_host_key_blob, sbloblen,
171 omin, onbits, omax, 225 kex->min, kex->nbits, kex->max,
172 dh->p, dh->g, 226 kex->dh->p, kex->dh->g,
173 dh_client_pub, 227 dh_client_pub,
174 dh->pub_key, 228 kex->dh->pub_key,
175 shared_secret, 229 shared_secret,
176 &hash, &hashlen 230 hash, &hashlen)) != 0)
177 ); 231 goto out;
178 BN_clear_free(dh_client_pub);
179 232
180 /* save session id := H */ 233 /* save session id := H */
181 if (kex->session_id == NULL) { 234 if (kex->session_id == NULL) {
182 kex->session_id_len = hashlen; 235 kex->session_id_len = hashlen;
183 kex->session_id = xmalloc(kex->session_id_len); 236 kex->session_id = malloc(kex->session_id_len);
237 if (kex->session_id == NULL) {
238 r = SSH_ERR_ALLOC_FAIL;
239 goto out;
240 }
184 memcpy(kex->session_id, hash, kex->session_id_len); 241 memcpy(kex->session_id, hash, kex->session_id_len);
185 } 242 }
186 243
187 /* sign H */ 244 /* sign H */
188 kex->sign(server_host_private, server_host_public, &signature, &slen, 245 if ((r = kex->sign(server_host_private, server_host_public,
189 hash, hashlen); 246 &signature, &slen, hash, hashlen, ssh->compat)) < 0)
247 goto out;
190 248
191 /* destroy_sensitive_data(); */ 249 /* destroy_sensitive_data(); */
192 250
193 /* send server hostkey, DH pubkey 'f' and singed H */ 251 /* send server hostkey, DH pubkey 'f' and singed H */
194 debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); 252 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
195 packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); 253 (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
196 packet_put_string(server_host_key_blob, sbloblen); 254 (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
197 packet_put_bignum2(dh->pub_key); /* f */ 255 (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
198 packet_put_string(signature, slen); 256 (r = sshpkt_send(ssh)) != 0)
199 packet_send(); 257 goto out;
200 258
201 free(signature); 259 if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
260 r = kex_send_newkeys(ssh);
261 out:
262 DH_free(kex->dh);
263 kex->dh = NULL;
264 if (dh_client_pub)
265 BN_clear_free(dh_client_pub);
266 if (kbuf) {
267 explicit_bzero(kbuf, klen);
268 free(kbuf);
269 }
270 if (shared_secret)
271 BN_clear_free(shared_secret);
202 free(server_host_key_blob); 272 free(server_host_key_blob);
203 /* have keys, free DH */ 273 free(signature);
204 DH_free(dh); 274 return r;
205
206 kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
207 BN_clear_free(shared_secret);
208
209 kex_finish(kex);
210} 275}
211#endif /* WITH_OPENSSL */ 276#endif /* WITH_OPENSSL */