1*9469f4f1Schristos /* $NetBSD: kexgen.c,v 1.8 2024/09/24 21:32:18 christos Exp $ */ 2*9469f4f1Schristos /* $OpenBSD: kexgen.c,v 1.10 2024/09/09 02:39:57 djm Exp $ */ 3*9469f4f1Schristos 47afc6c7eSchristos /* 57afc6c7eSchristos * Copyright (c) 2019 Markus Friedl. All rights reserved. 67afc6c7eSchristos * 77afc6c7eSchristos * Redistribution and use in source and binary forms, with or without 87afc6c7eSchristos * modification, are permitted provided that the following conditions 97afc6c7eSchristos * are met: 107afc6c7eSchristos * 1. Redistributions of source code must retain the above copyright 117afc6c7eSchristos * notice, this list of conditions and the following disclaimer. 127afc6c7eSchristos * 2. Redistributions in binary form must reproduce the above copyright 137afc6c7eSchristos * notice, this list of conditions and the following disclaimer in the 147afc6c7eSchristos * documentation and/or other materials provided with the distribution. 157afc6c7eSchristos * 167afc6c7eSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 177afc6c7eSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 187afc6c7eSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 197afc6c7eSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 207afc6c7eSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 217afc6c7eSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 227afc6c7eSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 237afc6c7eSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 247afc6c7eSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 257afc6c7eSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 267afc6c7eSchristos */ 27aa36fcacSchristos #include "includes.h" 28aa36fcacSchristos __RCSID("$NetBSD"); 297afc6c7eSchristos 307afc6c7eSchristos #include <sys/types.h> 317afc6c7eSchristos 327afc6c7eSchristos #include <stdio.h> 337afc6c7eSchristos #include <string.h> 347afc6c7eSchristos #include <signal.h> 357afc6c7eSchristos 367afc6c7eSchristos #include "sshkey.h" 377afc6c7eSchristos #include "kex.h" 387afc6c7eSchristos #include "log.h" 397afc6c7eSchristos #include "packet.h" 407afc6c7eSchristos #include "ssh2.h" 417afc6c7eSchristos #include "sshbuf.h" 427afc6c7eSchristos #include "digest.h" 437afc6c7eSchristos #include "ssherr.h" 447afc6c7eSchristos 457afc6c7eSchristos static int input_kex_gen_init(int, u_int32_t, struct ssh *); 467afc6c7eSchristos static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh); 477afc6c7eSchristos 487afc6c7eSchristos static int 497afc6c7eSchristos kex_gen_hash( 507afc6c7eSchristos int hash_alg, 517afc6c7eSchristos const struct sshbuf *client_version, 527afc6c7eSchristos const struct sshbuf *server_version, 537afc6c7eSchristos const struct sshbuf *client_kexinit, 547afc6c7eSchristos const struct sshbuf *server_kexinit, 557afc6c7eSchristos const struct sshbuf *server_host_key_blob, 567afc6c7eSchristos const struct sshbuf *client_pub, 577afc6c7eSchristos const struct sshbuf *server_pub, 587afc6c7eSchristos const struct sshbuf *shared_secret, 597afc6c7eSchristos u_char *hash, size_t *hashlen) 607afc6c7eSchristos { 617afc6c7eSchristos struct sshbuf *b; 627afc6c7eSchristos int r; 637afc6c7eSchristos 647afc6c7eSchristos if (*hashlen < ssh_digest_bytes(hash_alg)) 657afc6c7eSchristos return SSH_ERR_INVALID_ARGUMENT; 667afc6c7eSchristos if ((b = sshbuf_new()) == NULL) 677afc6c7eSchristos return SSH_ERR_ALLOC_FAIL; 687afc6c7eSchristos if ((r = sshbuf_put_stringb(b, client_version)) != 0 || 697afc6c7eSchristos (r = sshbuf_put_stringb(b, server_version)) != 0 || 707afc6c7eSchristos /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ 717afc6c7eSchristos (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 || 727afc6c7eSchristos (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 737afc6c7eSchristos (r = sshbuf_putb(b, client_kexinit)) != 0 || 747afc6c7eSchristos (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 || 757afc6c7eSchristos (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || 767afc6c7eSchristos (r = sshbuf_putb(b, server_kexinit)) != 0 || 777afc6c7eSchristos (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 || 787afc6c7eSchristos (r = sshbuf_put_stringb(b, client_pub)) != 0 || 797afc6c7eSchristos (r = sshbuf_put_stringb(b, server_pub)) != 0 || 807afc6c7eSchristos (r = sshbuf_putb(b, shared_secret)) != 0) { 817afc6c7eSchristos sshbuf_free(b); 827afc6c7eSchristos return r; 837afc6c7eSchristos } 847afc6c7eSchristos #ifdef DEBUG_KEX 857afc6c7eSchristos sshbuf_dump(b, stderr); 867afc6c7eSchristos #endif 877afc6c7eSchristos if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { 887afc6c7eSchristos sshbuf_free(b); 897afc6c7eSchristos return SSH_ERR_LIBCRYPTO_ERROR; 907afc6c7eSchristos } 917afc6c7eSchristos sshbuf_free(b); 927afc6c7eSchristos *hashlen = ssh_digest_bytes(hash_alg); 937afc6c7eSchristos #ifdef DEBUG_KEX 947afc6c7eSchristos dump_digest("hash", hash, *hashlen); 957afc6c7eSchristos #endif 967afc6c7eSchristos return 0; 977afc6c7eSchristos } 987afc6c7eSchristos 997afc6c7eSchristos int 1007afc6c7eSchristos kex_gen_client(struct ssh *ssh) 1017afc6c7eSchristos { 1027afc6c7eSchristos struct kex *kex = ssh->kex; 1037afc6c7eSchristos int r; 1047afc6c7eSchristos 1057afc6c7eSchristos switch (kex->kex_type) { 106cd4ada6aSchristos #ifdef WITH_OPENSSL 1077afc6c7eSchristos case KEX_DH_GRP1_SHA1: 1087afc6c7eSchristos case KEX_DH_GRP14_SHA1: 1097afc6c7eSchristos case KEX_DH_GRP14_SHA256: 1107afc6c7eSchristos case KEX_DH_GRP16_SHA512: 1117afc6c7eSchristos case KEX_DH_GRP18_SHA512: 1127afc6c7eSchristos r = kex_dh_keypair(kex); 1137afc6c7eSchristos break; 1147afc6c7eSchristos case KEX_ECDH_SHA2: 1157afc6c7eSchristos r = kex_ecdh_keypair(kex); 1167afc6c7eSchristos break; 117cd4ada6aSchristos #endif /* WITH_OPENSSL */ 1187afc6c7eSchristos case KEX_C25519_SHA256: 1197afc6c7eSchristos r = kex_c25519_keypair(kex); 1207afc6c7eSchristos break; 12117418e98Schristos case KEX_KEM_SNTRUP761X25519_SHA512: 12217418e98Schristos r = kex_kem_sntrup761x25519_keypair(kex); 1237afc6c7eSchristos break; 124*9469f4f1Schristos case KEX_KEM_MLKEM768X25519_SHA256: 125*9469f4f1Schristos r = kex_kem_mlkem768x25519_keypair(kex); 126*9469f4f1Schristos break; 1277afc6c7eSchristos default: 1287afc6c7eSchristos r = SSH_ERR_INVALID_ARGUMENT; 1297afc6c7eSchristos break; 1307afc6c7eSchristos } 1317afc6c7eSchristos if (r != 0) 1327afc6c7eSchristos return r; 1337afc6c7eSchristos if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 || 1347afc6c7eSchristos (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 || 1357afc6c7eSchristos (r = sshpkt_send(ssh)) != 0) 1367afc6c7eSchristos return r; 1377afc6c7eSchristos debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); 1387afc6c7eSchristos ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply); 1397afc6c7eSchristos return 0; 1407afc6c7eSchristos } 1417afc6c7eSchristos 1427afc6c7eSchristos static int 1437afc6c7eSchristos input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) 1447afc6c7eSchristos { 1457afc6c7eSchristos struct kex *kex = ssh->kex; 1467afc6c7eSchristos struct sshkey *server_host_key = NULL; 1477afc6c7eSchristos struct sshbuf *shared_secret = NULL; 1487afc6c7eSchristos struct sshbuf *server_blob = NULL; 1497afc6c7eSchristos struct sshbuf *tmp = NULL, *server_host_key_blob = NULL; 1507afc6c7eSchristos u_char *signature = NULL; 1517afc6c7eSchristos u_char hash[SSH_DIGEST_MAX_LENGTH]; 1527afc6c7eSchristos size_t slen, hashlen; 1537afc6c7eSchristos int r; 1547afc6c7eSchristos 15517418e98Schristos debug("SSH2_MSG_KEX_ECDH_REPLY received"); 15617418e98Schristos ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error); 15717418e98Schristos 1587afc6c7eSchristos /* hostkey */ 1597afc6c7eSchristos if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) 1607afc6c7eSchristos goto out; 1617afc6c7eSchristos /* sshkey_fromb() consumes its buffer, so make a copy */ 1627afc6c7eSchristos if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) { 1637afc6c7eSchristos r = SSH_ERR_ALLOC_FAIL; 1647afc6c7eSchristos goto out; 1657afc6c7eSchristos } 1667afc6c7eSchristos if ((r = sshkey_fromb(tmp, &server_host_key)) != 0) 1677afc6c7eSchristos goto out; 1687afc6c7eSchristos if ((r = kex_verify_host_key(ssh, server_host_key)) != 0) 1697afc6c7eSchristos goto out; 1707afc6c7eSchristos 1717afc6c7eSchristos /* Q_S, server public key */ 1727afc6c7eSchristos /* signed H */ 1737afc6c7eSchristos if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || 1747afc6c7eSchristos (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || 1757afc6c7eSchristos (r = sshpkt_get_end(ssh)) != 0) 1767afc6c7eSchristos goto out; 1777afc6c7eSchristos 1787afc6c7eSchristos /* compute shared secret */ 1797afc6c7eSchristos switch (kex->kex_type) { 180cd4ada6aSchristos #ifdef WITH_OPENSSL 1817afc6c7eSchristos case KEX_DH_GRP1_SHA1: 1827afc6c7eSchristos case KEX_DH_GRP14_SHA1: 1837afc6c7eSchristos case KEX_DH_GRP14_SHA256: 1847afc6c7eSchristos case KEX_DH_GRP16_SHA512: 1857afc6c7eSchristos case KEX_DH_GRP18_SHA512: 1867afc6c7eSchristos r = kex_dh_dec(kex, server_blob, &shared_secret); 1877afc6c7eSchristos break; 1887afc6c7eSchristos case KEX_ECDH_SHA2: 1897afc6c7eSchristos r = kex_ecdh_dec(kex, server_blob, &shared_secret); 1907afc6c7eSchristos break; 191cd4ada6aSchristos #endif /* WITH_OPENSSL */ 1927afc6c7eSchristos case KEX_C25519_SHA256: 1937afc6c7eSchristos r = kex_c25519_dec(kex, server_blob, &shared_secret); 1947afc6c7eSchristos break; 19517418e98Schristos case KEX_KEM_SNTRUP761X25519_SHA512: 19617418e98Schristos r = kex_kem_sntrup761x25519_dec(kex, server_blob, 1977afc6c7eSchristos &shared_secret); 1987afc6c7eSchristos break; 199*9469f4f1Schristos case KEX_KEM_MLKEM768X25519_SHA256: 200*9469f4f1Schristos r = kex_kem_mlkem768x25519_dec(kex, server_blob, 201*9469f4f1Schristos &shared_secret); 202*9469f4f1Schristos break; 2037afc6c7eSchristos default: 2047afc6c7eSchristos r = SSH_ERR_INVALID_ARGUMENT; 2057afc6c7eSchristos break; 2067afc6c7eSchristos } 2077afc6c7eSchristos if (r !=0 ) 2087afc6c7eSchristos goto out; 2097afc6c7eSchristos 2107afc6c7eSchristos /* calc and verify H */ 2117afc6c7eSchristos hashlen = sizeof(hash); 2127afc6c7eSchristos if ((r = kex_gen_hash( 2137afc6c7eSchristos kex->hash_alg, 2147afc6c7eSchristos kex->client_version, 2157afc6c7eSchristos kex->server_version, 2167afc6c7eSchristos kex->my, 2177afc6c7eSchristos kex->peer, 2187afc6c7eSchristos server_host_key_blob, 2197afc6c7eSchristos kex->client_pub, 2207afc6c7eSchristos server_blob, 2217afc6c7eSchristos shared_secret, 2227afc6c7eSchristos hash, &hashlen)) != 0) 2237afc6c7eSchristos goto out; 2247afc6c7eSchristos 2257afc6c7eSchristos if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, 226ed75d7a8Schristos kex->hostkey_alg, ssh->compat, NULL)) != 0) 2277afc6c7eSchristos goto out; 2287afc6c7eSchristos 229a03ec00cSchristos if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 || 230a03ec00cSchristos (r = kex_send_newkeys(ssh)) != 0) 231a03ec00cSchristos goto out; 232a03ec00cSchristos 233a03ec00cSchristos /* save initial signature and hostkey */ 234a03ec00cSchristos if ((kex->flags & KEX_INITIAL) != 0) { 235a03ec00cSchristos if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) { 236a03ec00cSchristos r = SSH_ERR_INTERNAL_ERROR; 237a03ec00cSchristos goto out; 238a03ec00cSchristos } 239a03ec00cSchristos if ((kex->initial_sig = sshbuf_new()) == NULL) { 240a03ec00cSchristos r = SSH_ERR_ALLOC_FAIL; 241a03ec00cSchristos goto out; 242a03ec00cSchristos } 243a03ec00cSchristos if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0) 244a03ec00cSchristos goto out; 245a03ec00cSchristos kex->initial_hostkey = server_host_key; 246a03ec00cSchristos server_host_key = NULL; 247a03ec00cSchristos } 248a03ec00cSchristos /* success */ 2497afc6c7eSchristos out: 2507afc6c7eSchristos explicit_bzero(hash, sizeof(hash)); 2517afc6c7eSchristos explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); 25217418e98Schristos explicit_bzero(kex->sntrup761_client_key, 25317418e98Schristos sizeof(kex->sntrup761_client_key)); 254*9469f4f1Schristos explicit_bzero(kex->mlkem768_client_key, 255*9469f4f1Schristos sizeof(kex->mlkem768_client_key)); 2567afc6c7eSchristos sshbuf_free(server_host_key_blob); 2577afc6c7eSchristos free(signature); 2587afc6c7eSchristos sshbuf_free(tmp); 2597afc6c7eSchristos sshkey_free(server_host_key); 2607afc6c7eSchristos sshbuf_free(server_blob); 2617afc6c7eSchristos sshbuf_free(shared_secret); 2627afc6c7eSchristos sshbuf_free(kex->client_pub); 2637afc6c7eSchristos kex->client_pub = NULL; 2647afc6c7eSchristos return r; 2657afc6c7eSchristos } 2667afc6c7eSchristos 2677afc6c7eSchristos int 2687afc6c7eSchristos kex_gen_server(struct ssh *ssh) 2697afc6c7eSchristos { 2707afc6c7eSchristos debug("expecting SSH2_MSG_KEX_ECDH_INIT"); 2717afc6c7eSchristos ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init); 2727afc6c7eSchristos return 0; 2737afc6c7eSchristos } 2747afc6c7eSchristos 2757afc6c7eSchristos static int 2767afc6c7eSchristos input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) 2777afc6c7eSchristos { 2787afc6c7eSchristos struct kex *kex = ssh->kex; 2797afc6c7eSchristos struct sshkey *server_host_private, *server_host_public; 2807afc6c7eSchristos struct sshbuf *shared_secret = NULL; 2817afc6c7eSchristos struct sshbuf *server_pubkey = NULL; 2827afc6c7eSchristos struct sshbuf *client_pubkey = NULL; 2837afc6c7eSchristos struct sshbuf *server_host_key_blob = NULL; 2847afc6c7eSchristos u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH]; 2857afc6c7eSchristos size_t slen, hashlen; 2867afc6c7eSchristos int r; 2877afc6c7eSchristos 28817418e98Schristos debug("SSH2_MSG_KEX_ECDH_INIT received"); 28917418e98Schristos ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error); 29017418e98Schristos 2917afc6c7eSchristos if ((r = kex_load_hostkey(ssh, &server_host_private, 2927afc6c7eSchristos &server_host_public)) != 0) 2937afc6c7eSchristos goto out; 2947afc6c7eSchristos 2957afc6c7eSchristos if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || 2967afc6c7eSchristos (r = sshpkt_get_end(ssh)) != 0) 2977afc6c7eSchristos goto out; 2987afc6c7eSchristos 2997afc6c7eSchristos /* compute shared secret */ 3007afc6c7eSchristos switch (kex->kex_type) { 301cd4ada6aSchristos #ifdef WITH_OPENSSL 3027afc6c7eSchristos case KEX_DH_GRP1_SHA1: 3037afc6c7eSchristos case KEX_DH_GRP14_SHA1: 3047afc6c7eSchristos case KEX_DH_GRP14_SHA256: 3057afc6c7eSchristos case KEX_DH_GRP16_SHA512: 3067afc6c7eSchristos case KEX_DH_GRP18_SHA512: 3077afc6c7eSchristos r = kex_dh_enc(kex, client_pubkey, &server_pubkey, 3087afc6c7eSchristos &shared_secret); 3097afc6c7eSchristos break; 3107afc6c7eSchristos case KEX_ECDH_SHA2: 3117afc6c7eSchristos r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, 3127afc6c7eSchristos &shared_secret); 3137afc6c7eSchristos break; 314cd4ada6aSchristos #endif /* WITH_OPENSSL */ 3157afc6c7eSchristos case KEX_C25519_SHA256: 3167afc6c7eSchristos r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, 3177afc6c7eSchristos &shared_secret); 3187afc6c7eSchristos break; 31917418e98Schristos case KEX_KEM_SNTRUP761X25519_SHA512: 32017418e98Schristos r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, 3217afc6c7eSchristos &server_pubkey, &shared_secret); 3227afc6c7eSchristos break; 323*9469f4f1Schristos case KEX_KEM_MLKEM768X25519_SHA256: 324*9469f4f1Schristos r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, 325*9469f4f1Schristos &server_pubkey, &shared_secret); 326*9469f4f1Schristos break; 3277afc6c7eSchristos default: 3287afc6c7eSchristos r = SSH_ERR_INVALID_ARGUMENT; 3297afc6c7eSchristos break; 3307afc6c7eSchristos } 3317afc6c7eSchristos if (r !=0 ) 3327afc6c7eSchristos goto out; 3337afc6c7eSchristos 3347afc6c7eSchristos /* calc H */ 3357afc6c7eSchristos if ((server_host_key_blob = sshbuf_new()) == NULL) { 3367afc6c7eSchristos r = SSH_ERR_ALLOC_FAIL; 3377afc6c7eSchristos goto out; 3387afc6c7eSchristos } 3397afc6c7eSchristos if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0) 3407afc6c7eSchristos goto out; 3417afc6c7eSchristos hashlen = sizeof(hash); 3427afc6c7eSchristos if ((r = kex_gen_hash( 3437afc6c7eSchristos kex->hash_alg, 3447afc6c7eSchristos kex->client_version, 3457afc6c7eSchristos kex->server_version, 3467afc6c7eSchristos kex->peer, 3477afc6c7eSchristos kex->my, 3487afc6c7eSchristos server_host_key_blob, 3497afc6c7eSchristos client_pubkey, 3507afc6c7eSchristos server_pubkey, 3517afc6c7eSchristos shared_secret, 3527afc6c7eSchristos hash, &hashlen)) != 0) 3537afc6c7eSchristos goto out; 3547afc6c7eSchristos 3557afc6c7eSchristos /* sign H */ 3567afc6c7eSchristos if ((r = kex->sign(ssh, server_host_private, server_host_public, 3577afc6c7eSchristos &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0) 3587afc6c7eSchristos goto out; 3597afc6c7eSchristos 3607afc6c7eSchristos /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ 3617afc6c7eSchristos if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || 3627afc6c7eSchristos (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 || 3637afc6c7eSchristos (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 || 3647afc6c7eSchristos (r = sshpkt_put_string(ssh, signature, slen)) != 0 || 3657afc6c7eSchristos (r = sshpkt_send(ssh)) != 0) 3667afc6c7eSchristos goto out; 3677afc6c7eSchristos 368a03ec00cSchristos if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 || 369a03ec00cSchristos (r = kex_send_newkeys(ssh)) != 0) 370a03ec00cSchristos goto out; 371a03ec00cSchristos /* retain copy of hostkey used at initial KEX */ 372a03ec00cSchristos if (kex->initial_hostkey == NULL && 373a03ec00cSchristos (r = sshkey_from_private(server_host_public, 374a03ec00cSchristos &kex->initial_hostkey)) != 0) 375a03ec00cSchristos goto out; 376a03ec00cSchristos /* success */ 3777afc6c7eSchristos out: 3787afc6c7eSchristos explicit_bzero(hash, sizeof(hash)); 3797afc6c7eSchristos sshbuf_free(server_host_key_blob); 3807afc6c7eSchristos free(signature); 3817afc6c7eSchristos sshbuf_free(shared_secret); 3827afc6c7eSchristos sshbuf_free(client_pubkey); 3837afc6c7eSchristos sshbuf_free(server_pubkey); 3847afc6c7eSchristos return r; 3857afc6c7eSchristos } 386