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