1 /*
2  * Client side of key exchange for the SSH-2 transport protocol (RFC 4253).
3  */
4 
5 #include <assert.h>
6 
7 #include "putty.h"
8 #include "ssh.h"
9 #include "sshbpp.h"
10 #include "sshppl.h"
11 #include "sshcr.h"
12 #include "storage.h"
13 #include "ssh2transport.h"
14 #include "mpint.h"
15 
16 /*
17  * Another copy of the symbol defined in mpunsafe.c. See the comment
18  * there.
19  */
20 const int deliberate_symbol_clash = 12345;
21 
ssh2kex_coroutine(struct ssh2_transport_state * s,bool * aborted)22 void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
23 {
24     PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
25     PktIn *pktin;
26     PktOut *pktout;
27 
28     crBegin(s->crStateKex);
29 
30     if (s->kex_alg->main_type == KEXTYPE_DH) {
31         /*
32          * Work out the number of bits of key we will need from the
33          * key exchange. We start with the maximum key length of
34          * either cipher...
35          */
36         {
37             int csbits, scbits;
38 
39             csbits = s->out.cipher ? s->out.cipher->real_keybits : 0;
40             scbits = s->in.cipher ? s->in.cipher->real_keybits : 0;
41             s->nbits = (csbits > scbits ? csbits : scbits);
42         }
43         /* The keys only have hlen-bit entropy, since they're based on
44          * a hash. So cap the key size at hlen bits. */
45         if (s->nbits > s->kex_alg->hash->hlen * 8)
46             s->nbits = s->kex_alg->hash->hlen * 8;
47 
48         /*
49          * If we're doing Diffie-Hellman group exchange, start by
50          * requesting a group.
51          */
52         if (dh_is_gex(s->kex_alg)) {
53             ppl_logevent("Doing Diffie-Hellman group exchange");
54             s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGEX;
55             /*
56              * Work out how big a DH group we will need to allow that
57              * much data.
58              */
59             s->pbits = 512 << ((s->nbits - 1) / 64);
60             if (s->pbits < DH_MIN_SIZE)
61                 s->pbits = DH_MIN_SIZE;
62             if (s->pbits > DH_MAX_SIZE)
63                 s->pbits = DH_MAX_SIZE;
64             if ((s->ppl.remote_bugs & BUG_SSH2_OLDGEX)) {
65                 pktout = ssh_bpp_new_pktout(
66                     s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
67                 put_uint32(pktout, s->pbits);
68             } else {
69                 pktout = ssh_bpp_new_pktout(
70                     s->ppl.bpp, SSH2_MSG_KEX_DH_GEX_REQUEST);
71                 put_uint32(pktout, DH_MIN_SIZE);
72                 put_uint32(pktout, s->pbits);
73                 put_uint32(pktout, DH_MAX_SIZE);
74             }
75             pq_push(s->ppl.out_pq, pktout);
76 
77             crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL);
78             if (pktin->type != SSH2_MSG_KEX_DH_GEX_GROUP) {
79                 ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
80                                 "expecting Diffie-Hellman group, type %d (%s)",
81                                 pktin->type,
82                                 ssh2_pkt_type(s->ppl.bpp->pls->kctx,
83                                               s->ppl.bpp->pls->actx,
84                                               pktin->type));
85                 *aborted = true;
86                 return;
87             }
88             s->p = get_mp_ssh2(pktin);
89             s->g = get_mp_ssh2(pktin);
90             if (get_err(pktin)) {
91                 ssh_proto_error(s->ppl.ssh,
92                                 "Unable to parse Diffie-Hellman group packet");
93                 *aborted = true;
94                 return;
95             }
96             s->dh_ctx = dh_setup_gex(s->p, s->g);
97             s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
98             s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;
99 
100             fzprintf(sftpKexAlgorithm, "%d-bit Diffie-Hellman with server-supplied group", dh_modulus_bit_size(s->dh_ctx));
101             fzprintf(sftpKexHash, ssh_hash_alg(s->exhash)->text_name);
102             ppl_logevent("Doing Diffie-Hellman key exchange using %d-bit "
103                          "modulus and hash %s with a server-supplied group",
104                          dh_modulus_bit_size(s->dh_ctx),
105                          ssh_hash_alg(s->exhash)->text_name);
106         } else {
107             s->ppl.bpp->pls->kctx = SSH2_PKTCTX_DHGROUP;
108             s->dh_ctx = dh_setup_group(s->kex_alg);
109             s->kex_init_value = SSH2_MSG_KEXDH_INIT;
110             s->kex_reply_value = SSH2_MSG_KEXDH_REPLY;
111 
112             fzprintf(sftpKexAlgorithm, "%d-bit Diffie-Hellman with standard group", dh_modulus_bit_size(s->dh_ctx), s->kex_alg->groupname);
113             fzprintf(sftpKexHash, ssh_hash_alg(s->exhash)->text_name);
114             ppl_logevent("Doing Diffie-Hellman key exchange using %d-bit "
115                          "modulus and hash %s with standard group \"%s\"",
116                          dh_modulus_bit_size(s->dh_ctx),
117                          ssh_hash_alg(s->exhash)->text_name,
118                          s->kex_alg->groupname);
119         }
120 
121         /*
122          * Now generate and send e for Diffie-Hellman.
123          */
124         seat_set_busy_status(s->ppl.seat, BUSY_CPU);
125         s->e = dh_create_e(s->dh_ctx, s->nbits * 2);
126         pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value);
127         put_mp_ssh2(pktout, s->e);
128         pq_push(s->ppl.out_pq, pktout);
129 
130         seat_set_busy_status(s->ppl.seat, BUSY_WAITING);
131         crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL);
132         if (pktin->type != s->kex_reply_value) {
133             ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
134                             "expecting Diffie-Hellman reply, type %d (%s)",
135                             pktin->type,
136                             ssh2_pkt_type(s->ppl.bpp->pls->kctx,
137                                           s->ppl.bpp->pls->actx,
138                                           pktin->type));
139             *aborted = true;
140             return;
141         }
142         seat_set_busy_status(s->ppl.seat, BUSY_CPU);
143         s->hostkeydata = get_string(pktin);
144         s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata);
145         s->f = get_mp_ssh2(pktin);
146         s->sigdata = get_string(pktin);
147         if (get_err(pktin)) {
148             ssh_proto_error(s->ppl.ssh,
149                             "Unable to parse Diffie-Hellman reply packet");
150             *aborted = true;
151             return;
152         }
153 
154         {
155             const char *err = dh_validate_f(s->dh_ctx, s->f);
156             if (err) {
157                 ssh_proto_error(s->ppl.ssh, "Diffie-Hellman reply failed "
158                                 "validation: %s", err);
159                 *aborted = true;
160                 return;
161             }
162         }
163         s->K = dh_find_K(s->dh_ctx, s->f);
164 
165         /* We assume everything from now on will be quick, and it might
166          * involve user interaction. */
167         seat_set_busy_status(s->ppl.seat, BUSY_NOT);
168 
169         put_stringpl(s->exhash, s->hostkeydata);
170         if (dh_is_gex(s->kex_alg)) {
171             if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX))
172                 put_uint32(s->exhash, DH_MIN_SIZE);
173             put_uint32(s->exhash, s->pbits);
174             if (!(s->ppl.remote_bugs & BUG_SSH2_OLDGEX))
175                 put_uint32(s->exhash, DH_MAX_SIZE);
176             put_mp_ssh2(s->exhash, s->p);
177             put_mp_ssh2(s->exhash, s->g);
178         }
179         put_mp_ssh2(s->exhash, s->e);
180         put_mp_ssh2(s->exhash, s->f);
181 
182         dh_cleanup(s->dh_ctx);
183         s->dh_ctx = NULL;
184         mp_free(s->f); s->f = NULL;
185         if (dh_is_gex(s->kex_alg)) {
186             mp_free(s->g); s->g = NULL;
187             mp_free(s->p); s->p = NULL;
188         }
189     } else if (s->kex_alg->main_type == KEXTYPE_ECDH) {
190 
191         fzprintf(sftpKexAlgorithm, "ECDH");
192         fzprintf(sftpKexHash, ssh_hash_alg(s->exhash)->text_name);
193         fzprintf(sftpKexCurve, ssh_ecdhkex_curve_textname(s->kex_alg));
194         ppl_logevent("Doing ECDH key exchange with curve %s and hash %s",
195                      ssh_ecdhkex_curve_textname(s->kex_alg),
196                      ssh_hash_alg(s->exhash)->text_name);
197         s->ppl.bpp->pls->kctx = SSH2_PKTCTX_ECDHKEX;
198 
199         s->ecdh_key = ssh_ecdhkex_newkey(s->kex_alg);
200         if (!s->ecdh_key) {
201             ssh_sw_abort(s->ppl.ssh, "Unable to generate key for ECDH");
202             *aborted = true;
203             return;
204         }
205 
206         pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEX_ECDH_INIT);
207         {
208             strbuf *pubpoint = strbuf_new();
209             ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint));
210             put_stringsb(pktout, pubpoint);
211         }
212 
213         pq_push(s->ppl.out_pq, pktout);
214 
215         crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL);
216         if (pktin->type != SSH2_MSG_KEX_ECDH_REPLY) {
217             ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
218                             "expecting ECDH reply, type %d (%s)", pktin->type,
219                             ssh2_pkt_type(s->ppl.bpp->pls->kctx,
220                                           s->ppl.bpp->pls->actx,
221                                           pktin->type));
222             *aborted = true;
223             return;
224         }
225 
226         s->hostkeydata = get_string(pktin);
227         put_stringpl(s->exhash, s->hostkeydata);
228         s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata);
229 
230         {
231             strbuf *pubpoint = strbuf_new();
232             ssh_ecdhkex_getpublic(s->ecdh_key, BinarySink_UPCAST(pubpoint));
233             put_string(s->exhash, pubpoint->u, pubpoint->len);
234             strbuf_free(pubpoint);
235         }
236 
237         {
238             ptrlen keydata = get_string(pktin);
239             put_stringpl(s->exhash, keydata);
240             s->K = ssh_ecdhkex_getkey(s->ecdh_key, keydata);
241             if (!get_err(pktin) && !s->K) {
242                 ssh_proto_error(s->ppl.ssh, "Received invalid elliptic curve "
243                                 "point in ECDH reply");
244                 *aborted = true;
245                 return;
246             }
247         }
248 
249         s->sigdata = get_string(pktin);
250         if (get_err(pktin)) {
251             ssh_proto_error(s->ppl.ssh, "Unable to parse ECDH reply packet");
252             *aborted = true;
253             return;
254         }
255 
256         ssh_ecdhkex_freekey(s->ecdh_key);
257         s->ecdh_key = NULL;
258 #ifndef NO_GSSAPI
259     } else if (s->kex_alg->main_type == KEXTYPE_GSS) {
260         ptrlen data;
261 
262         s->ppl.bpp->pls->kctx = SSH2_PKTCTX_GSSKEX;
263         s->init_token_sent = false;
264         s->complete_rcvd = false;
265         s->hkey = NULL;
266         s->keystr = NULL;
267 
268         /*
269          * Work out the number of bits of key we will need from the
270          * key exchange. We start with the maximum key length of
271          * either cipher...
272          *
273          * This is rote from the KEXTYPE_DH section above.
274          */
275         {
276             int csbits, scbits;
277 
278             csbits = s->out.cipher->real_keybits;
279             scbits = s->in.cipher->real_keybits;
280             s->nbits = (csbits > scbits ? csbits : scbits);
281         }
282         /* The keys only have hlen-bit entropy, since they're based on
283          * a hash. So cap the key size at hlen bits. */
284         if (s->nbits > s->kex_alg->hash->hlen * 8)
285             s->nbits = s->kex_alg->hash->hlen * 8;
286 
287         if (dh_is_gex(s->kex_alg)) {
288             /*
289              * Work out how big a DH group we will need to allow that
290              * much data.
291              */
292             s->pbits = 512 << ((s->nbits - 1) / 64);
293             ppl_logevent("Doing GSSAPI (with Kerberos V5) Diffie-Hellman "
294                          "group exchange, with minimum %d bits", s->pbits);
295             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXGSS_GROUPREQ);
296             put_uint32(pktout, s->pbits); /* min */
297             put_uint32(pktout, s->pbits); /* preferred */
298             put_uint32(pktout, s->pbits * 2); /* max */
299             pq_push(s->ppl.out_pq, pktout);
300 
301             crMaybeWaitUntilV(
302                 (pktin = ssh2_transport_pop(s)) != NULL);
303             if (pktin->type != SSH2_MSG_KEXGSS_GROUP) {
304                 ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
305                                 "expecting Diffie-Hellman group, type %d (%s)",
306                                 pktin->type,
307                                 ssh2_pkt_type(s->ppl.bpp->pls->kctx,
308                                               s->ppl.bpp->pls->actx,
309                                               pktin->type));
310                 *aborted = true;
311                 return;
312             }
313             s->p = get_mp_ssh2(pktin);
314             s->g = get_mp_ssh2(pktin);
315             if (get_err(pktin)) {
316                 ssh_proto_error(s->ppl.ssh,
317                                 "Unable to parse Diffie-Hellman group packet");
318                 *aborted = true;
319                 return;
320             }
321             s->dh_ctx = dh_setup_gex(s->p, s->g);
322         } else {
323             s->dh_ctx = dh_setup_group(s->kex_alg);
324             ppl_logevent("Using GSSAPI (with Kerberos V5) Diffie-Hellman with"
325                          " standard group \"%s\"", s->kex_alg->groupname);
326         }
327 
328         ppl_logevent("Doing GSSAPI (with Kerberos V5) Diffie-Hellman key "
329                      "exchange with hash %s", ssh_hash_alg(s->exhash)->text_name);
330         /* Now generate e for Diffie-Hellman. */
331         seat_set_busy_status(s->ppl.seat, BUSY_CPU);
332         s->e = dh_create_e(s->dh_ctx, s->nbits * 2);
333 
334         if (s->shgss->lib->gsslogmsg)
335             ppl_logevent("%s", s->shgss->lib->gsslogmsg);
336 
337         /* initial tokens are empty */
338         SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);
339         SSH_GSS_CLEAR_BUF(&s->gss_sndtok);
340         SSH_GSS_CLEAR_BUF(&s->mic);
341         s->gss_stat = s->shgss->lib->acquire_cred(
342             s->shgss->lib, &s->shgss->ctx, &s->gss_cred_expiry);
343         if (s->gss_stat != SSH_GSS_OK) {
344             ssh_sw_abort(s->ppl.ssh,
345                          "GSSAPI key exchange failed to initialise");
346             *aborted = true;
347             return;
348         }
349 
350         /* now enter the loop */
351         assert(s->shgss->srv_name);
352         do {
353             /*
354              * When acquire_cred yields no useful expiration, go with the
355              * service ticket expiration.
356              */
357             s->gss_stat = s->shgss->lib->init_sec_context(
358                 s->shgss->lib, &s->shgss->ctx, s->shgss->srv_name,
359                 s->gss_delegate, &s->gss_rcvtok, &s->gss_sndtok,
360                 (s->gss_cred_expiry == GSS_NO_EXPIRATION ?
361                  &s->gss_cred_expiry : NULL), NULL);
362             SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);
363 
364             if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd)
365                 break; /* MIC is verified after the loop */
366 
367             if (s->gss_stat != SSH_GSS_S_COMPLETE &&
368                 s->gss_stat != SSH_GSS_S_CONTINUE_NEEDED) {
369                 if (s->shgss->lib->display_status(
370                         s->shgss->lib, s->shgss->ctx,
371                         &s->gss_buf) == SSH_GSS_OK) {
372                     char *err = s->gss_buf.value;
373                     ssh_sw_abort(s->ppl.ssh,
374                                  "GSSAPI key exchange failed to initialise "
375                                  "context: %s", err);
376                     sfree(err);
377                     *aborted = true;
378                     return;
379                 }
380             }
381             assert(s->gss_stat == SSH_GSS_S_COMPLETE ||
382                    s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED);
383 
384             if (!s->init_token_sent) {
385                 s->init_token_sent = true;
386                 pktout = ssh_bpp_new_pktout(s->ppl.bpp,
387                                             SSH2_MSG_KEXGSS_INIT);
388                 if (s->gss_sndtok.length == 0) {
389                     ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange failed: "
390                                  "no initial context token");
391                     *aborted = true;
392                     return;
393                 }
394                 put_string(pktout,
395                            s->gss_sndtok.value, s->gss_sndtok.length);
396                 put_mp_ssh2(pktout, s->e);
397                 pq_push(s->ppl.out_pq, pktout);
398                 s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok);
399                 ppl_logevent("GSSAPI key exchange initialised");
400             } else if (s->gss_sndtok.length != 0) {
401                 pktout = ssh_bpp_new_pktout(
402                     s->ppl.bpp, SSH2_MSG_KEXGSS_CONTINUE);
403                 put_string(pktout,
404                            s->gss_sndtok.value, s->gss_sndtok.length);
405                 pq_push(s->ppl.out_pq, pktout);
406                 s->shgss->lib->free_tok(s->shgss->lib, &s->gss_sndtok);
407             }
408 
409             if (s->gss_stat == SSH_GSS_S_COMPLETE && s->complete_rcvd)
410                 break;
411 
412           wait_for_gss_token:
413             crMaybeWaitUntilV(
414                 (pktin = ssh2_transport_pop(s)) != NULL);
415             switch (pktin->type) {
416               case SSH2_MSG_KEXGSS_CONTINUE:
417                 data = get_string(pktin);
418                 s->gss_rcvtok.value = (char *)data.ptr;
419                 s->gss_rcvtok.length = data.len;
420                 continue;
421               case SSH2_MSG_KEXGSS_COMPLETE:
422                 s->complete_rcvd = true;
423                 s->f = get_mp_ssh2(pktin);
424                 data = get_string(pktin);
425                 s->mic.value = (char *)data.ptr;
426                 s->mic.length = data.len;
427                 /* If there's a final token we loop to consume it */
428                 if (get_bool(pktin)) {
429                     data = get_string(pktin);
430                     s->gss_rcvtok.value = (char *)data.ptr;
431                     s->gss_rcvtok.length = data.len;
432                     continue;
433                 }
434                 break;
435               case SSH2_MSG_KEXGSS_HOSTKEY:
436                 s->hostkeydata = get_string(pktin);
437                 if (s->hostkey_alg) {
438                     s->hkey = ssh_key_new_pub(s->hostkey_alg,
439                                               s->hostkeydata);
440                     put_stringpl(s->exhash, s->hostkeydata);
441                 }
442                 /*
443                  * Can't loop as we have no token to pass to
444                  * init_sec_context.
445                  */
446                 goto wait_for_gss_token;
447               case SSH2_MSG_KEXGSS_ERROR:
448                 /*
449                  * We have no use for the server's major and minor
450                  * status.  The minor status is really only
451                  * meaningful to the server, and with luck the major
452                  * status means something to us (but not really all
453                  * that much).  The string is more meaningful, and
454                  * hopefully the server sends any error tokens, as
455                  * that will produce the most useful information for
456                  * us.
457                  */
458                 get_uint32(pktin); /* server's major status */
459                 get_uint32(pktin); /* server's minor status */
460                 data = get_string(pktin);
461                 ppl_logevent("GSSAPI key exchange failed; "
462                              "server's message: %.*s", PTRLEN_PRINTF(data));
463                 /* Language tag, but we have no use for it */
464                 get_string(pktin);
465                 /*
466                  * Wait for an error token, if there is one, or the
467                  * server's disconnect.  The error token, if there
468                  * is one, must follow the SSH2_MSG_KEXGSS_ERROR
469                  * message, per the RFC.
470                  */
471                 goto wait_for_gss_token;
472               default:
473                 ssh_proto_error(s->ppl.ssh, "Received unexpected packet "
474                                 "during GSSAPI key exchange, type %d (%s)",
475                                 pktin->type,
476                                 ssh2_pkt_type(s->ppl.bpp->pls->kctx,
477                                               s->ppl.bpp->pls->actx,
478                                               pktin->type));
479                 *aborted = true;
480                 return;
481             }
482         } while (s->gss_rcvtok.length ||
483                  s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED ||
484                  !s->complete_rcvd);
485 
486         {
487             const char *err = dh_validate_f(s->dh_ctx, s->f);
488             if (err) {
489                 ssh_proto_error(s->ppl.ssh, "GSSAPI reply failed "
490                                 "validation: %s", err);
491                 *aborted = true;
492                 return;
493             }
494         }
495         s->K = dh_find_K(s->dh_ctx, s->f);
496 
497         /* We assume everything from now on will be quick, and it might
498          * involve user interaction. */
499         seat_set_busy_status(s->ppl.seat, BUSY_NOT);
500 
501         if (!s->hkey)
502             put_stringz(s->exhash, "");
503         if (dh_is_gex(s->kex_alg)) {
504             /* min,  preferred, max */
505             put_uint32(s->exhash, s->pbits);
506             put_uint32(s->exhash, s->pbits);
507             put_uint32(s->exhash, s->pbits * 2);
508 
509             put_mp_ssh2(s->exhash, s->p);
510             put_mp_ssh2(s->exhash, s->g);
511         }
512         put_mp_ssh2(s->exhash, s->e);
513         put_mp_ssh2(s->exhash, s->f);
514 
515         /*
516          * MIC verification is done below, after we compute the hash
517          * used as the MIC input.
518          */
519 
520         dh_cleanup(s->dh_ctx);
521         s->dh_ctx = NULL;
522         mp_free(s->f); s->f = NULL;
523         if (dh_is_gex(s->kex_alg)) {
524             mp_free(s->g); s->g = NULL;
525             mp_free(s->p); s->p = NULL;
526         }
527 #endif
528     } else {
529         ptrlen rsakeydata;
530 
531         fzprintf(sftpKexAlgorithm, "RSA");
532         fzprintf(sftpKexHash, ssh_hash_alg(s->exhash)->text_name);
533         assert(s->kex_alg->main_type == KEXTYPE_RSA);
534         ppl_logevent("Doing RSA key exchange with hash %s",
535                      ssh_hash_alg(s->exhash)->text_name);
536         s->ppl.bpp->pls->kctx = SSH2_PKTCTX_RSAKEX;
537         /*
538          * RSA key exchange. First expect a KEXRSA_PUBKEY packet
539          * from the server.
540          */
541         crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL);
542         if (pktin->type != SSH2_MSG_KEXRSA_PUBKEY) {
543             ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
544                             "expecting RSA public key, type %d (%s)",
545                             pktin->type,
546                             ssh2_pkt_type(s->ppl.bpp->pls->kctx,
547                                           s->ppl.bpp->pls->actx,
548                                           pktin->type));
549             *aborted = true;
550             return;
551         }
552 
553         s->hostkeydata = get_string(pktin);
554         put_stringpl(s->exhash, s->hostkeydata);
555         s->hkey = ssh_key_new_pub(s->hostkey_alg, s->hostkeydata);
556 
557         rsakeydata = get_string(pktin);
558 
559         s->rsa_kex_key = ssh_rsakex_newkey(rsakeydata);
560         if (!s->rsa_kex_key) {
561             ssh_proto_error(s->ppl.ssh,
562                             "Unable to parse RSA public key packet");
563             *aborted = true;
564             return;
565         }
566         s->rsa_kex_key_needs_freeing = true;
567 
568         put_stringpl(s->exhash, rsakeydata);
569 
570         /*
571          * Next, set up a shared secret K, of precisely KLEN -
572          * 2*HLEN - 49 bits, where KLEN is the bit length of the
573          * RSA key modulus and HLEN is the bit length of the hash
574          * we're using.
575          */
576         {
577             int klen = ssh_rsakex_klen(s->rsa_kex_key);
578 
579             const struct ssh_rsa_kex_extra *extra =
580                 (const struct ssh_rsa_kex_extra *)s->kex_alg->extra;
581             if (klen < extra->minklen) {
582                 ssh_proto_error(s->ppl.ssh, "Server sent %d-bit RSA key, "
583                                 "less than the minimum size %d for %s "
584                                 "key exchange", klen, extra->minklen,
585                                 s->kex_alg->name);
586                 *aborted = true;
587                 return;
588             }
589 
590             int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49);
591             assert(nbits > 0);
592 
593             strbuf *buf, *outstr;
594 
595             mp_int *tmp = mp_random_bits(nbits - 1);
596             s->K = mp_power_2(nbits - 1);
597             mp_add_into(s->K, s->K, tmp);
598             mp_free(tmp);
599 
600             /*
601              * Encode this as an mpint.
602              */
603             buf = strbuf_new_nm();
604             put_mp_ssh2(buf, s->K);
605 
606             /*
607              * Encrypt it with the given RSA key.
608              */
609             outstr = ssh_rsakex_encrypt(s->rsa_kex_key, s->kex_alg->hash,
610                                         ptrlen_from_strbuf(buf));
611 
612             /*
613              * And send it off in a return packet.
614              */
615             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_KEXRSA_SECRET);
616             put_stringpl(pktout, ptrlen_from_strbuf(outstr));
617             pq_push(s->ppl.out_pq, pktout);
618 
619             put_stringsb(s->exhash, outstr); /* frees outstr */
620 
621             strbuf_free(buf);
622         }
623 
624         ssh_rsakex_freekey(s->rsa_kex_key);
625         s->rsa_kex_key = NULL;
626         s->rsa_kex_key_needs_freeing = false;
627 
628         crMaybeWaitUntilV((pktin = ssh2_transport_pop(s)) != NULL);
629         if (pktin->type != SSH2_MSG_KEXRSA_DONE) {
630             ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
631                             "expecting RSA kex signature, type %d (%s)",
632                             pktin->type,
633                             ssh2_pkt_type(s->ppl.bpp->pls->kctx,
634                                           s->ppl.bpp->pls->actx,
635                                           pktin->type));
636             *aborted = true;
637             return;
638         }
639 
640         s->sigdata = get_string(pktin);
641         if (get_err(pktin)) {
642             ssh_proto_error(s->ppl.ssh, "Unable to parse RSA kex signature");
643             *aborted = true;
644             return;
645         }
646     }
647 
648     ssh2transport_finalise_exhash(s);
649 
650 #ifndef NO_GSSAPI
651     if (s->kex_alg->main_type == KEXTYPE_GSS) {
652         Ssh_gss_buf gss_buf;
653         SSH_GSS_CLEAR_BUF(&s->gss_buf);
654 
655         gss_buf.value = s->exchange_hash;
656         gss_buf.length = s->kex_alg->hash->hlen;
657         s->gss_stat = s->shgss->lib->verify_mic(
658             s->shgss->lib, s->shgss->ctx, &gss_buf, &s->mic);
659         if (s->gss_stat != SSH_GSS_OK) {
660             if (s->shgss->lib->display_status(
661                     s->shgss->lib, s->shgss->ctx, &s->gss_buf) == SSH_GSS_OK) {
662                 char *err = s->gss_buf.value;
663                 ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was "
664                              "not valid: %s", err);
665                 sfree(err);
666             } else {
667                 ssh_sw_abort(s->ppl.ssh, "GSSAPI key exchange MIC was "
668                              "not valid");
669             }
670             *aborted = true;
671             return;
672         }
673 
674         s->gss_kex_used = true;
675 
676         /*-
677          * If this the first KEX, save the GSS context for "gssapi-keyex"
678          * authentication.
679          *
680          * http://tools.ietf.org/html/rfc4462#section-4
681          *
682          * This method may be used only if the initial key exchange was
683          * performed using a GSS-API-based key exchange method defined in
684          * accordance with Section 2.  The GSS-API context used with this
685          * method is always that established during an initial GSS-API-based
686          * key exchange.  Any context established during key exchange for the
687          * purpose of rekeying MUST NOT be used with this method.
688          */
689         if (s->got_session_id) {
690             s->shgss->lib->release_cred(s->shgss->lib, &s->shgss->ctx);
691         }
692         ppl_logevent("GSSAPI Key Exchange complete!");
693     }
694 #endif
695 
696     s->dh_ctx = NULL;
697 
698     /* In GSS keyex there's no hostkey signature to verify */
699     if (s->kex_alg->main_type != KEXTYPE_GSS) {
700         if (!s->hkey) {
701             ssh_proto_error(s->ppl.ssh, "Server's host key is invalid");
702             *aborted = true;
703             return;
704         }
705 
706         if (!ssh_key_verify(
707                 s->hkey, s->sigdata,
708                 make_ptrlen(s->exchange_hash, s->kex_alg->hash->hlen))) {
709 #ifndef FUZZING
710             ssh_proto_error(s->ppl.ssh, "Signature from server's host key "
711                             "is invalid");
712             *aborted = true;
713             return;
714 #endif
715         }
716     }
717 
718     s->keystr = (s->hkey ? ssh_key_cache_str(s->hkey) : NULL);
719 #ifndef NO_GSSAPI
720     if (s->gss_kex_used) {
721         /*
722          * In a GSS-based session, check the host key (if any) against
723          * the transient host key cache.
724          */
725         if (s->kex_alg->main_type == KEXTYPE_GSS) {
726 
727             /*
728              * We've just done a GSS key exchange. If it gave us a
729              * host key, store it.
730              */
731             if (s->hkey) {
732                 char *fingerprint = ssh2_fingerprint(
733                     s->hkey, SSH_FPTYPE_DEFAULT);
734                 ppl_logevent("GSS kex provided fallback host key:");
735                 ppl_logevent("%s", fingerprint);
736                 sfree(fingerprint);
737 
738                 ssh_transient_hostkey_cache_add(s->thc, s->hkey);
739             } else if (!ssh_transient_hostkey_cache_non_empty(s->thc)) {
740                 /*
741                  * But if it didn't, then we currently have no
742                  * fallback host key to use in subsequent non-GSS
743                  * rekeys. So we should immediately trigger a non-GSS
744                  * rekey of our own, to set one up, before the session
745                  * keys have been used for anything else.
746                  *
747                  * This is similar to the cross-certification done at
748                  * user request in the permanent host key cache, but
749                  * here we do it automatically, once, at session
750                  * startup, and only add the key to the transient
751                  * cache.
752                  */
753                 if (s->hostkey_alg) {
754                     s->need_gss_transient_hostkey = true;
755                 } else {
756                     /*
757                      * If we negotiated the "null" host key algorithm
758                      * in the key exchange, that's an indication that
759                      * no host key at all is available from the server
760                      * (both because we listed "null" last, and
761                      * because RFC 4462 section 5 says that a server
762                      * MUST NOT offer "null" as a host key algorithm
763                      * unless that is the only algorithm it provides
764                      * at all).
765                      *
766                      * In that case we actually _can't_ perform a
767                      * non-GSSAPI key exchange, so it's pointless to
768                      * attempt one proactively. This is also likely to
769                      * cause trouble later if a rekey is required at a
770                      * moment whne GSS credentials are not available,
771                      * but someone setting up a server in this
772                      * configuration presumably accepts that as a
773                      * consequence.
774                      */
775                     if (!s->warned_about_no_gss_transient_hostkey) {
776                         ppl_logevent("No fallback host key available");
777                         s->warned_about_no_gss_transient_hostkey = true;
778                     }
779                 }
780             }
781         } else {
782             /*
783              * We've just done a fallback key exchange, so make
784              * sure the host key it used is in the cache of keys
785              * we previously received in GSS kexes.
786              *
787              * An exception is if this was the non-GSS key exchange we
788              * triggered on purpose to populate the transient cache.
789              */
790             assert(s->hkey);  /* only KEXTYPE_GSS lets this be null */
791             char *fingerprint = ssh2_fingerprint(s->hkey, SSH_FPTYPE_DEFAULT);
792 
793             if (s->need_gss_transient_hostkey) {
794                 ppl_logevent("Post-GSS rekey provided fallback host key:");
795                 ppl_logevent("%s", fingerprint);
796                 ssh_transient_hostkey_cache_add(s->thc, s->hkey);
797                 s->need_gss_transient_hostkey = false;
798             } else if (!ssh_transient_hostkey_cache_verify(s->thc, s->hkey)) {
799                 ppl_logevent("Non-GSS rekey after initial GSS kex "
800                              "used host key:");
801                 ppl_logevent("%s", fingerprint);
802                 sfree(fingerprint);
803                 ssh_sw_abort(s->ppl.ssh, "Server's host key did not match any "
804                              "used in previous GSS kex");
805                 *aborted = true;
806                 return;
807             }
808 
809             sfree(fingerprint);
810         }
811     } else
812 #endif /* NO_GSSAPI */
813         if (!s->got_session_id) {
814             /*
815              * Make a note of any other host key formats that are available.
816              */
817             {
818                 int i, j, nkeys = 0;
819                 char *list = NULL;
820                 for (i = 0; i < lenof(ssh2_hostkey_algs); i++) {
821                     if (ssh2_hostkey_algs[i].alg == s->hostkey_alg)
822                         continue;
823 
824                     for (j = 0; j < s->n_uncert_hostkeys; j++)
825                         if (s->uncert_hostkeys[j] == i)
826                             break;
827 
828                     if (j < s->n_uncert_hostkeys) {
829                         char *newlist;
830                         if (list)
831                             newlist = dupprintf(
832                                 "%s/%s", list,
833                                 ssh2_hostkey_algs[i].alg->ssh_id);
834                         else
835                             newlist = dupprintf(
836                                 "%s", ssh2_hostkey_algs[i].alg->ssh_id);
837                         sfree(list);
838                         list = newlist;
839                         nkeys++;
840                     }
841                 }
842                 if (list) {
843                     ppl_logevent("Server also has %s host key%s, but we "
844                                  "don't know %s", list,
845                                  nkeys > 1 ? "s" : "",
846                                  nkeys > 1 ? "any of them" : "it");
847                     sfree(list);
848                 }
849             }
850 
851             /*
852              * Authenticate remote host: verify host key. (We've already
853              * checked the signature of the exchange hash.)
854              */
855             char **fingerprints = ssh2_all_fingerprints(s->hkey);
856             FingerprintType fptype_default =
857                 ssh2_pick_default_fingerprint(fingerprints);
858             ppl_logevent("Host key fingerprint is:");
859             ppl_logevent("%s", fingerprints[fptype_default]);
860             /* First check against manually configured host keys. */
861             s->dlgret = verify_ssh_manual_host_key(
862                 s->conf, fingerprints, s->hkey);
863             if (s->dlgret == 0) {          /* did not match */
864                 ssh2_free_all_fingerprints(fingerprints);
865                 ssh_sw_abort(s->ppl.ssh, "Host key did not appear in manually "
866                              "configured list");
867                 *aborted = true;
868                 return;
869             } else if (s->dlgret < 0) { /* none configured; use standard handling */
870                 ssh2_userkey uk = { .key = s->hkey, .comment = NULL };
871                 char *keydisp = ssh2_pubkey_openssh_str(&uk);
872                 fzprintf(sftpHostkey, fingerprints[fptype_default]);
873                 s->dlgret = seat_verify_ssh_host_key(
874                     s->ppl.seat, s->savedhost, s->savedport,
875                     ssh_key_cache_id(s->hkey), s->keystr, keydisp,
876                     fingerprints, ssh2_transport_dialog_callback, s);
877                 sfree(keydisp);
878                 ssh2_free_all_fingerprints(fingerprints);
879 #ifdef FUZZING
880                 s->dlgret = 1;
881 #endif
882                 crMaybeWaitUntilV(s->dlgret >= 0);
883                 if (s->dlgret == 0) {
884                     ssh_user_close(s->ppl.ssh,
885                                    "User aborted at host key verification");
886                     *aborted = true;
887                     return;
888                 }
889             }
890 
891             /*
892              * Save this host key, to check against the one presented in
893              * subsequent rekeys.
894              */
895             s->hostkey_str = s->keystr;
896             s->keystr = NULL;
897         } else if (s->cross_certifying) {
898             assert(s->hkey);
899             assert(ssh_key_alg(s->hkey) == s->cross_certifying);
900 
901             char *fingerprint = ssh2_fingerprint(s->hkey, SSH_FPTYPE_DEFAULT);
902             ppl_logevent("Storing additional host key for this host:");
903             ppl_logevent("%s", fingerprint);
904             sfree(fingerprint);
905 
906             store_host_key(s->savedhost, s->savedport,
907                            ssh_key_cache_id(s->hkey), s->keystr);
908             /*
909              * Don't forget to store the new key as the one we'll be
910              * re-checking in future normal rekeys.
911              */
912             s->hostkey_str = s->keystr;
913             s->keystr = NULL;
914         } else {
915             /*
916              * In a rekey, we never present an interactive host key
917              * verification request to the user. Instead, we simply
918              * enforce that the key we're seeing this time is identical to
919              * the one we saw before.
920              */
921             assert(s->keystr);         /* filled in by prior key exchange */
922             if (strcmp(s->hostkey_str, s->keystr)) {
923 #ifndef FUZZING
924                 ssh_sw_abort(s->ppl.ssh,
925                              "Host key was different in repeat key exchange");
926                 *aborted = true;
927                 return;
928 #endif
929             }
930         }
931 
932     sfree(s->keystr);
933     s->keystr = NULL;
934     if (s->hkey) {
935         ssh_key_free(s->hkey);
936         s->hkey = NULL;
937     }
938 
939     crFinishV;
940 }
941