summaryrefslogtreecommitdiff
path: root/kexgexc.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 /kexgexc.c
parent3fdc88a0def4f86aa88a5846ac079dc964c0546a (diff)
upstream commit
adapt kex to sshbuf and struct ssh; ok djm@
Diffstat (limited to 'kexgexc.c')
-rw-r--r--kexgexc.c287
1 files changed, 175 insertions, 112 deletions
diff --git a/kexgexc.c b/kexgexc.c
index 18d09cfb0..0898824f3 100644
--- a/kexgexc.c
+++ b/kexgexc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: kexgexc.c,v 1.18 2015/01/19 19:52:16 markus Exp $ */ 1/* $OpenBSD: kexgexc.c,v 1.19 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,174 +37,237 @@
37#include <string.h> 37#include <string.h>
38#include <signal.h> 38#include <signal.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"
47#include "dh.h" 46#include "dh.h"
48#include "ssh2.h" 47#include "ssh2.h"
49#include "compat.h" 48#include "compat.h"
49#include "dispatch.h"
50#include "ssherr.h"
51#include "sshbuf.h"
50 52
51void 53static int input_kex_dh_gex_group(int, u_int32_t, void *);
52kexgex_client(Kex *kex) 54static int input_kex_dh_gex_reply(int, u_int32_t, void *);
55
56int
57kexgex_client(struct ssh *ssh)
53{ 58{
54 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; 59 struct kex *kex = ssh->kex;
55 BIGNUM *p = NULL, *g = NULL; 60 int r;
56 Key *server_host_key; 61 u_int nbits;
57 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
58 u_int klen, slen, sbloblen, hashlen;
59 int kout;
60 int min, max, nbits;
61 DH *dh;
62 62
63 nbits = dh_estimate(kex->dh_need * 8); 63 nbits = dh_estimate(kex->dh_need * 8);
64 64
65 if (datafellows & SSH_OLD_DHGEX) { 65 kex->min = DH_GRP_MIN;
66 kex->max = DH_GRP_MAX;
67 kex->nbits = nbits;
68 if (ssh->compat & SSH_OLD_DHGEX) {
66 /* Old GEX request */ 69 /* Old GEX request */
67 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); 70 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD))
68 packet_put_int(nbits); 71 != 0 ||
69 min = DH_GRP_MIN; 72 (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
70 max = DH_GRP_MAX; 73 (r = sshpkt_send(ssh)) != 0)
71 74 goto out;
72 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); 75 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", kex->nbits);
73 } else { 76 } else {
74 /* New GEX request */ 77 /* New GEX request */
75 min = DH_GRP_MIN; 78 if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
76 max = DH_GRP_MAX; 79 (r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
77 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); 80 (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
78 packet_put_int(min); 81 (r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
79 packet_put_int(nbits); 82 (r = sshpkt_send(ssh)) != 0)
80 packet_put_int(max); 83 goto out;
81
82 debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", 84 debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
83 min, nbits, max); 85 kex->min, kex->nbits, kex->max);
84 } 86 }
85#ifdef DEBUG_KEXDH 87#ifdef DEBUG_KEXDH
86 fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", 88 fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
87 min, nbits, max); 89 kex->min, kex->nbits, kex->max);
88#endif 90#endif
89 packet_send(); 91 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
90 92 &input_kex_dh_gex_group);
91 debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); 93 r = 0;
92 packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); 94 out:
95 return r;
96}
93 97
94 if ((p = BN_new()) == NULL) 98static int
95 fatal("BN_new"); 99input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
96 packet_get_bignum2(p); 100{
97 if ((g = BN_new()) == NULL) 101 struct ssh *ssh = ctxt;
98 fatal("BN_new"); 102 struct kex *kex = ssh->kex;
99 packet_get_bignum2(g); 103 BIGNUM *p = NULL, *g = NULL;
100 packet_check_eom(); 104 int r, bits;
101 105
102 if (BN_num_bits(p) < min || BN_num_bits(p) > max) 106 debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
103 fatal("DH_GEX group out of range: %d !< %d !< %d",
104 min, BN_num_bits(p), max);
105 107
106 dh = dh_new_group(g, p); 108 if ((p = BN_new()) == NULL ||
107 dh_gen_key(dh, kex->we_need * 8); 109 (g = BN_new()) == NULL) {
110 r = SSH_ERR_ALLOC_FAIL;
111 goto out;
112 }
113 if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
114 (r = sshpkt_get_bignum2(ssh, g)) != 0 ||
115 (r = sshpkt_get_end(ssh)) != 0)
116 goto out;
117 if ((bits = BN_num_bits(p)) < 0 ||
118 (u_int)bits < kex->min || (u_int)bits > kex->max) {
119 r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
120 goto out;
121 }
122 if ((kex->dh = dh_new_group(g, p)) == NULL) {
123 r = SSH_ERR_ALLOC_FAIL;
124 goto out;
125 }
126 p = g = NULL; /* belong to kex->dh now */
108 127
128 /* generate and send 'e', client DH public key */
129 if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
130 (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
131 (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
132 (r = sshpkt_send(ssh)) != 0)
133 goto out;
134 debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
109#ifdef DEBUG_KEXDH 135#ifdef DEBUG_KEXDH
110 DHparams_print_fp(stderr, dh); 136 DHparams_print_fp(stderr, kex->dh);
111 fprintf(stderr, "pub= "); 137 fprintf(stderr, "pub= ");
112 BN_print_fp(stderr, dh->pub_key); 138 BN_print_fp(stderr, kex->dh->pub_key);
113 fprintf(stderr, "\n"); 139 fprintf(stderr, "\n");
114#endif 140#endif
141 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
142 ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
143 r = 0;
144out:
145 if (p)
146 BN_clear_free(p);
147 if (g)
148 BN_clear_free(g);
149 return r;
150}
115 151
116 debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); 152static int
117 /* generate and send 'e', client DH public key */ 153input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
118 packet_start(SSH2_MSG_KEX_DH_GEX_INIT); 154{
119 packet_put_bignum2(dh->pub_key); 155 struct ssh *ssh = ctxt;
120 packet_send(); 156 struct kex *kex = ssh->kex;
121 157 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
122 debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); 158 struct sshkey *server_host_key = NULL;
123 packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); 159 u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
160 u_char hash[SSH_DIGEST_MAX_LENGTH];
161 size_t klen = 0, slen, sbloblen, hashlen;
162 int kout, r;
124 163
164 debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
165 if (kex->verify_host_key == NULL) {
166 r = SSH_ERR_INVALID_ARGUMENT;
167 goto out;
168 }
125 /* key, cert */ 169 /* key, cert */
126 server_host_key_blob = packet_get_string(&sbloblen); 170 if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
127 server_host_key = key_from_blob(server_host_key_blob, sbloblen); 171 &sbloblen)) != 0 ||
128 if (server_host_key == NULL) 172 (r = sshkey_from_blob(server_host_key_blob, sbloblen,
129 fatal("cannot decode server_host_key_blob"); 173 &server_host_key)) != 0)
130 if (server_host_key->type != kex->hostkey_type) 174 goto out;
131 fatal("type mismatch for decoded server_host_key_blob"); 175 if (server_host_key->type != kex->hostkey_type) {
132 if (kex->verify_host_key == NULL) 176 r = SSH_ERR_KEY_TYPE_MISMATCH;
133 fatal("cannot verify server_host_key"); 177 goto out;
134 if (kex->verify_host_key(server_host_key) == -1) 178 }
135 fatal("server_host_key verification failed"); 179 if (kex->verify_host_key(server_host_key, ssh) == -1) {
136 180 r = SSH_ERR_SIGNATURE_INVALID;
181 goto out;
182 }
137 /* DH parameter f, server public DH key */ 183 /* DH parameter f, server public DH key */
138 if ((dh_server_pub = BN_new()) == NULL) 184 if ((dh_server_pub = BN_new()) == NULL) {
139 fatal("dh_server_pub == NULL"); 185 r = SSH_ERR_ALLOC_FAIL;
140 packet_get_bignum2(dh_server_pub); 186 goto out;
141 187 }
188 /* signed H */
189 if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
190 (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
191 (r = sshpkt_get_end(ssh)) != 0)
192 goto out;
142#ifdef DEBUG_KEXDH 193#ifdef DEBUG_KEXDH
143 fprintf(stderr, "dh_server_pub= "); 194 fprintf(stderr, "dh_server_pub= ");
144 BN_print_fp(stderr, dh_server_pub); 195 BN_print_fp(stderr, dh_server_pub);
145 fprintf(stderr, "\n"); 196 fprintf(stderr, "\n");
146 debug("bits %d", BN_num_bits(dh_server_pub)); 197 debug("bits %d", BN_num_bits(dh_server_pub));
147#endif 198#endif
199 if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
200 sshpkt_disconnect(ssh, "bad server public DH value");
201 r = SSH_ERR_MESSAGE_INCOMPLETE;
202 goto out;
203 }
148 204
149 /* signed H */ 205 klen = DH_size(kex->dh);
150 signature = packet_get_string(&slen); 206 if ((kbuf = malloc(klen)) == NULL ||
151 packet_check_eom(); 207 (shared_secret = BN_new()) == NULL) {
152 208 r = SSH_ERR_ALLOC_FAIL;
153 if (!dh_pub_is_valid(dh, dh_server_pub)) 209 goto out;
154 packet_disconnect("bad server public DH value"); 210 }
155 211 if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
156 klen = DH_size(dh); 212 BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
157 kbuf = xmalloc(klen); 213 r = SSH_ERR_LIBCRYPTO_ERROR;
158 if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) 214 goto out;
159 fatal("DH_compute_key: failed"); 215 }
160#ifdef DEBUG_KEXDH 216#ifdef DEBUG_KEXDH
161 dump_digest("shared secret", kbuf, kout); 217 dump_digest("shared secret", kbuf, kout);
162#endif 218#endif
163 if ((shared_secret = BN_new()) == NULL) 219 if (ssh->compat & SSH_OLD_DHGEX)
164 fatal("kexgex_client: BN_new failed"); 220 kex->min = kex->max = -1;
165 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
166 fatal("kexgex_client: BN_bin2bn failed");
167 explicit_bzero(kbuf, klen);
168 free(kbuf);
169
170 if (datafellows & SSH_OLD_DHGEX)
171 min = max = -1;
172 221
173 /* calc and verify H */ 222 /* calc and verify H */
174 kexgex_hash( 223 hashlen = sizeof(hash);
224 if ((r = kexgex_hash(
175 kex->hash_alg, 225 kex->hash_alg,
176 kex->client_version_string, 226 kex->client_version_string,
177 kex->server_version_string, 227 kex->server_version_string,
178 buffer_ptr(kex->my), buffer_len(kex->my), 228 sshbuf_ptr(kex->my), sshbuf_len(kex->my),
179 buffer_ptr(kex->peer), buffer_len(kex->peer), 229 sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
180 server_host_key_blob, sbloblen, 230 server_host_key_blob, sbloblen,
181 min, nbits, max, 231 kex->min, kex->nbits, kex->max,
182 dh->p, dh->g, 232 kex->dh->p, kex->dh->g,
183 dh->pub_key, 233 kex->dh->pub_key,
184 dh_server_pub, 234 dh_server_pub,
185 shared_secret, 235 shared_secret,
186 &hash, &hashlen 236 hash, &hashlen)) != 0)
187 ); 237 goto out;
188
189 /* have keys, free DH */
190 DH_free(dh);
191 free(server_host_key_blob);
192 BN_clear_free(dh_server_pub);
193 238
194 if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) 239 if ((r = sshkey_verify(server_host_key, signature, slen, hash,
195 fatal("key_verify failed for server_host_key"); 240 hashlen, ssh->compat)) != 0)
196 key_free(server_host_key); 241 goto out;
197 free(signature);
198 242
199 /* save session id */ 243 /* save session id */
200 if (kex->session_id == NULL) { 244 if (kex->session_id == NULL) {
201 kex->session_id_len = hashlen; 245 kex->session_id_len = hashlen;
202 kex->session_id = xmalloc(kex->session_id_len); 246 kex->session_id = malloc(kex->session_id_len);
247 if (kex->session_id == NULL) {
248 r = SSH_ERR_ALLOC_FAIL;
249 goto out;
250 }
203 memcpy(kex->session_id, hash, kex->session_id_len); 251 memcpy(kex->session_id, hash, kex->session_id_len);
204 } 252 }
205 kex_derive_keys_bn(kex, hash, hashlen, shared_secret);
206 BN_clear_free(shared_secret);
207 253
208 kex_finish(kex); 254 if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
255 r = kex_send_newkeys(ssh);
256 out:
257 explicit_bzero(hash, sizeof(hash));
258 DH_free(kex->dh);
259 kex->dh = NULL;
260 if (dh_server_pub)
261 BN_clear_free(dh_server_pub);
262 if (kbuf) {
263 explicit_bzero(kbuf, klen);
264 free(kbuf);
265 }
266 if (shared_secret)
267 BN_clear_free(shared_secret);
268 sshkey_free(server_host_key);
269 free(server_host_key_blob);
270 free(signature);
271 return r;
209} 272}
210#endif /* WITH_OPENSSL */ 273#endif /* WITH_OPENSSL */