1*664f4763Szrj /* $OpenBSD: ssh_api.c,v 1.15 2019/01/21 10:38:54 djm Exp $ */ 2e9778795SPeter Avalos /* 3e9778795SPeter Avalos * Copyright (c) 2012 Markus Friedl. All rights reserved. 4e9778795SPeter Avalos * 5e9778795SPeter Avalos * Permission to use, copy, modify, and distribute this software for any 6e9778795SPeter Avalos * purpose with or without fee is hereby granted, provided that the above 7e9778795SPeter Avalos * copyright notice and this permission notice appear in all copies. 8e9778795SPeter Avalos * 9e9778795SPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10e9778795SPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11e9778795SPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12e9778795SPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13e9778795SPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14e9778795SPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15e9778795SPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16e9778795SPeter Avalos */ 17e9778795SPeter Avalos 18e9778795SPeter Avalos #include "includes.h" 19e9778795SPeter Avalos 20e9778795SPeter Avalos #include "ssh_api.h" 21e9778795SPeter Avalos #include "compat.h" 22e9778795SPeter Avalos #include "log.h" 23e9778795SPeter Avalos #include "authfile.h" 24e9778795SPeter Avalos #include "sshkey.h" 25e9778795SPeter Avalos #include "misc.h" 26e9778795SPeter Avalos #include "ssh2.h" 27e9778795SPeter Avalos #include "version.h" 28e9778795SPeter Avalos #include "myproposal.h" 29e9778795SPeter Avalos #include "ssherr.h" 30e9778795SPeter Avalos #include "sshbuf.h" 31e9778795SPeter Avalos 32*664f4763Szrj #include "openbsd-compat/openssl-compat.h" 33*664f4763Szrj 34e9778795SPeter Avalos #include <string.h> 35e9778795SPeter Avalos 36e9778795SPeter Avalos int _ssh_exchange_banner(struct ssh *); 37*664f4763Szrj int _ssh_send_banner(struct ssh *, struct sshbuf *); 38*664f4763Szrj int _ssh_read_banner(struct ssh *, struct sshbuf *); 39e9778795SPeter Avalos int _ssh_order_hostkeyalgs(struct ssh *); 40e9778795SPeter Avalos int _ssh_verify_host_key(struct sshkey *, struct ssh *); 41e9778795SPeter Avalos struct sshkey *_ssh_host_public_key(int, int, struct ssh *); 42e9778795SPeter Avalos struct sshkey *_ssh_host_private_key(int, int, struct ssh *); 43*664f4763Szrj int _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *, 44*664f4763Szrj u_char **, size_t *, const u_char *, size_t, const char *); 45e9778795SPeter Avalos 46e9778795SPeter Avalos /* 47e9778795SPeter Avalos * stubs for the server side implementation of kex. 48e9778795SPeter Avalos * disable privsep so our stubs will never be called. 49e9778795SPeter Avalos */ 50e9778795SPeter Avalos int use_privsep = 0; 51e9778795SPeter Avalos int mm_sshkey_sign(struct sshkey *, u_char **, u_int *, 52e9778795SPeter Avalos u_char *, u_int, char *, u_int); 53e9778795SPeter Avalos DH *mm_choose_dh(int, int, int); 54e9778795SPeter Avalos 55e9778795SPeter Avalos /* Define these two variables here so that they are part of the library */ 56e9778795SPeter Avalos u_char *session_id2 = NULL; 57e9778795SPeter Avalos u_int session_id2_len = 0; 58e9778795SPeter Avalos 59e9778795SPeter Avalos int 60e9778795SPeter Avalos mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp, 61e9778795SPeter Avalos u_char *data, u_int datalen, char *alg, u_int compat) 62e9778795SPeter Avalos { 63e9778795SPeter Avalos return (-1); 64e9778795SPeter Avalos } 65e9778795SPeter Avalos 66e9778795SPeter Avalos DH * 67e9778795SPeter Avalos mm_choose_dh(int min, int nbits, int max) 68e9778795SPeter Avalos { 69e9778795SPeter Avalos return (NULL); 70e9778795SPeter Avalos } 71e9778795SPeter Avalos 72e9778795SPeter Avalos /* API */ 73e9778795SPeter Avalos 74e9778795SPeter Avalos int 75e9778795SPeter Avalos ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) 76e9778795SPeter Avalos { 77e9778795SPeter Avalos char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 78e9778795SPeter Avalos struct ssh *ssh; 79e9778795SPeter Avalos char **proposal; 80e9778795SPeter Avalos static int called; 81e9778795SPeter Avalos int r; 82e9778795SPeter Avalos 83e9778795SPeter Avalos if (!called) { 84*664f4763Szrj seed_rng(); 85e9778795SPeter Avalos called = 1; 86e9778795SPeter Avalos } 87e9778795SPeter Avalos 88e9778795SPeter Avalos if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL) 89e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 90e9778795SPeter Avalos if (is_server) 91e9778795SPeter Avalos ssh_packet_set_server(ssh); 92e9778795SPeter Avalos 93e9778795SPeter Avalos /* Initialize key exchange */ 94e9778795SPeter Avalos proposal = kex_params ? kex_params->proposal : myproposal; 95*664f4763Szrj if ((r = kex_ready(ssh, proposal)) != 0) { 96e9778795SPeter Avalos ssh_free(ssh); 97e9778795SPeter Avalos return r; 98e9778795SPeter Avalos } 99e9778795SPeter Avalos ssh->kex->server = is_server; 100e9778795SPeter Avalos if (is_server) { 101e9778795SPeter Avalos #ifdef WITH_OPENSSL 102*664f4763Szrj ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 103*664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 104*664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; 105*664f4763Szrj ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; 106*664f4763Szrj ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; 107e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 108e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 109e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 110*664f4763Szrj ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 111e9778795SPeter Avalos # endif 112e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 113*664f4763Szrj ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; 114*664f4763Szrj ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server; 115e9778795SPeter Avalos ssh->kex->load_host_public_key=&_ssh_host_public_key; 116e9778795SPeter Avalos ssh->kex->load_host_private_key=&_ssh_host_private_key; 117e9778795SPeter Avalos ssh->kex->sign=&_ssh_host_key_sign; 118e9778795SPeter Avalos } else { 119e9778795SPeter Avalos #ifdef WITH_OPENSSL 120*664f4763Szrj ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client; 121*664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client; 122*664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client; 123*664f4763Szrj ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client; 124*664f4763Szrj ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client; 125e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 126e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 127e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 128*664f4763Szrj ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 129e9778795SPeter Avalos # endif 130e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 131*664f4763Szrj ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 132*664f4763Szrj ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 133e9778795SPeter Avalos ssh->kex->verify_host_key =&_ssh_verify_host_key; 134e9778795SPeter Avalos } 135e9778795SPeter Avalos *sshp = ssh; 136e9778795SPeter Avalos return 0; 137e9778795SPeter Avalos } 138e9778795SPeter Avalos 139e9778795SPeter Avalos void 140e9778795SPeter Avalos ssh_free(struct ssh *ssh) 141e9778795SPeter Avalos { 142e9778795SPeter Avalos struct key_entry *k; 143e9778795SPeter Avalos 144e9778795SPeter Avalos ssh_packet_close(ssh); 145e9778795SPeter Avalos /* 146e9778795SPeter Avalos * we've only created the public keys variants in case we 147e9778795SPeter Avalos * are a acting as a server. 148e9778795SPeter Avalos */ 149e9778795SPeter Avalos while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) { 150e9778795SPeter Avalos TAILQ_REMOVE(&ssh->public_keys, k, next); 151e9778795SPeter Avalos if (ssh->kex && ssh->kex->server) 152e9778795SPeter Avalos sshkey_free(k->key); 153e9778795SPeter Avalos free(k); 154e9778795SPeter Avalos } 155e9778795SPeter Avalos while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) { 156e9778795SPeter Avalos TAILQ_REMOVE(&ssh->private_keys, k, next); 157e9778795SPeter Avalos free(k); 158e9778795SPeter Avalos } 159e9778795SPeter Avalos if (ssh->kex) 160e9778795SPeter Avalos kex_free(ssh->kex); 161e9778795SPeter Avalos free(ssh); 162e9778795SPeter Avalos } 163e9778795SPeter Avalos 164e9778795SPeter Avalos void 165e9778795SPeter Avalos ssh_set_app_data(struct ssh *ssh, void *app_data) 166e9778795SPeter Avalos { 167e9778795SPeter Avalos ssh->app_data = app_data; 168e9778795SPeter Avalos } 169e9778795SPeter Avalos 170e9778795SPeter Avalos void * 171e9778795SPeter Avalos ssh_get_app_data(struct ssh *ssh) 172e9778795SPeter Avalos { 173e9778795SPeter Avalos return ssh->app_data; 174e9778795SPeter Avalos } 175e9778795SPeter Avalos 176e9778795SPeter Avalos /* Returns < 0 on error, 0 otherwise */ 177e9778795SPeter Avalos int 178e9778795SPeter Avalos ssh_add_hostkey(struct ssh *ssh, struct sshkey *key) 179e9778795SPeter Avalos { 180e9778795SPeter Avalos struct sshkey *pubkey = NULL; 181e9778795SPeter Avalos struct key_entry *k = NULL, *k_prv = NULL; 182e9778795SPeter Avalos int r; 183e9778795SPeter Avalos 184e9778795SPeter Avalos if (ssh->kex->server) { 185e9778795SPeter Avalos if ((r = sshkey_from_private(key, &pubkey)) != 0) 186e9778795SPeter Avalos return r; 187e9778795SPeter Avalos if ((k = malloc(sizeof(*k))) == NULL || 188e9778795SPeter Avalos (k_prv = malloc(sizeof(*k_prv))) == NULL) { 189e9778795SPeter Avalos free(k); 190e9778795SPeter Avalos sshkey_free(pubkey); 191e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 192e9778795SPeter Avalos } 193e9778795SPeter Avalos k_prv->key = key; 194e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next); 195e9778795SPeter Avalos 196e9778795SPeter Avalos /* add the public key, too */ 197e9778795SPeter Avalos k->key = pubkey; 198e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 199e9778795SPeter Avalos r = 0; 200e9778795SPeter Avalos } else { 201e9778795SPeter Avalos if ((k = malloc(sizeof(*k))) == NULL) 202e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 203e9778795SPeter Avalos k->key = key; 204e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 205e9778795SPeter Avalos r = 0; 206e9778795SPeter Avalos } 207e9778795SPeter Avalos 208e9778795SPeter Avalos return r; 209e9778795SPeter Avalos } 210e9778795SPeter Avalos 211e9778795SPeter Avalos int 212e9778795SPeter Avalos ssh_set_verify_host_key_callback(struct ssh *ssh, 213e9778795SPeter Avalos int (*cb)(struct sshkey *, struct ssh *)) 214e9778795SPeter Avalos { 215e9778795SPeter Avalos if (cb == NULL || ssh->kex == NULL) 216e9778795SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 217e9778795SPeter Avalos 218e9778795SPeter Avalos ssh->kex->verify_host_key = cb; 219e9778795SPeter Avalos 220e9778795SPeter Avalos return 0; 221e9778795SPeter Avalos } 222e9778795SPeter Avalos 223e9778795SPeter Avalos int 224e9778795SPeter Avalos ssh_input_append(struct ssh *ssh, const u_char *data, size_t len) 225e9778795SPeter Avalos { 226e9778795SPeter Avalos return sshbuf_put(ssh_packet_get_input(ssh), data, len); 227e9778795SPeter Avalos } 228e9778795SPeter Avalos 229e9778795SPeter Avalos int 230e9778795SPeter Avalos ssh_packet_next(struct ssh *ssh, u_char *typep) 231e9778795SPeter Avalos { 232e9778795SPeter Avalos int r; 233e9778795SPeter Avalos u_int32_t seqnr; 234e9778795SPeter Avalos u_char type; 235e9778795SPeter Avalos 236e9778795SPeter Avalos /* 237e9778795SPeter Avalos * Try to read a packet. Return SSH_MSG_NONE if no packet or not 238e9778795SPeter Avalos * enough data. 239e9778795SPeter Avalos */ 240e9778795SPeter Avalos *typep = SSH_MSG_NONE; 241*664f4763Szrj if (sshbuf_len(ssh->kex->client_version) == 0 || 242*664f4763Szrj sshbuf_len(ssh->kex->server_version) == 0) 243e9778795SPeter Avalos return _ssh_exchange_banner(ssh); 244e9778795SPeter Avalos /* 245e9778795SPeter Avalos * If we enough data and a dispatch function then 246e9778795SPeter Avalos * call the function and get the next packet. 247e9778795SPeter Avalos * Otherwise return the packet type to the caller so it 248e9778795SPeter Avalos * can decide how to go on. 249e9778795SPeter Avalos * 250e9778795SPeter Avalos * We will only call the dispatch function for: 251e9778795SPeter Avalos * 20-29 Algorithm negotiation 252e9778795SPeter Avalos * 30-49 Key exchange method specific (numbers can be reused for 253e9778795SPeter Avalos * different authentication methods) 254e9778795SPeter Avalos */ 255e9778795SPeter Avalos for (;;) { 256e9778795SPeter Avalos if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0) 257e9778795SPeter Avalos return r; 258e9778795SPeter Avalos if (type > 0 && type < DISPATCH_MAX && 259e9778795SPeter Avalos type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX && 260e9778795SPeter Avalos ssh->dispatch[type] != NULL) { 261e9778795SPeter Avalos if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0) 262e9778795SPeter Avalos return r; 263e9778795SPeter Avalos } else { 264e9778795SPeter Avalos *typep = type; 265e9778795SPeter Avalos return 0; 266e9778795SPeter Avalos } 267e9778795SPeter Avalos } 268e9778795SPeter Avalos } 269e9778795SPeter Avalos 270e9778795SPeter Avalos const u_char * 271e9778795SPeter Avalos ssh_packet_payload(struct ssh *ssh, size_t *lenp) 272e9778795SPeter Avalos { 273e9778795SPeter Avalos return sshpkt_ptr(ssh, lenp); 274e9778795SPeter Avalos } 275e9778795SPeter Avalos 276e9778795SPeter Avalos int 277e9778795SPeter Avalos ssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len) 278e9778795SPeter Avalos { 279e9778795SPeter Avalos int r; 280e9778795SPeter Avalos 281e9778795SPeter Avalos if ((r = sshpkt_start(ssh, type)) != 0 || 282e9778795SPeter Avalos (r = sshpkt_put(ssh, data, len)) != 0 || 283e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 284e9778795SPeter Avalos return r; 285e9778795SPeter Avalos return 0; 286e9778795SPeter Avalos } 287e9778795SPeter Avalos 288e9778795SPeter Avalos const u_char * 289e9778795SPeter Avalos ssh_output_ptr(struct ssh *ssh, size_t *len) 290e9778795SPeter Avalos { 291e9778795SPeter Avalos struct sshbuf *output = ssh_packet_get_output(ssh); 292e9778795SPeter Avalos 293e9778795SPeter Avalos *len = sshbuf_len(output); 294e9778795SPeter Avalos return sshbuf_ptr(output); 295e9778795SPeter Avalos } 296e9778795SPeter Avalos 297e9778795SPeter Avalos int 298e9778795SPeter Avalos ssh_output_consume(struct ssh *ssh, size_t len) 299e9778795SPeter Avalos { 300e9778795SPeter Avalos return sshbuf_consume(ssh_packet_get_output(ssh), len); 301e9778795SPeter Avalos } 302e9778795SPeter Avalos 303e9778795SPeter Avalos int 304e9778795SPeter Avalos ssh_output_space(struct ssh *ssh, size_t len) 305e9778795SPeter Avalos { 306e9778795SPeter Avalos return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len)); 307e9778795SPeter Avalos } 308e9778795SPeter Avalos 309e9778795SPeter Avalos int 310e9778795SPeter Avalos ssh_input_space(struct ssh *ssh, size_t len) 311e9778795SPeter Avalos { 312e9778795SPeter Avalos return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len)); 313e9778795SPeter Avalos } 314e9778795SPeter Avalos 315e9778795SPeter Avalos /* Read other side's version identification. */ 316e9778795SPeter Avalos int 317*664f4763Szrj _ssh_read_banner(struct ssh *ssh, struct sshbuf *banner) 318e9778795SPeter Avalos { 319*664f4763Szrj struct sshbuf *input = ssh_packet_get_input(ssh); 320e9778795SPeter Avalos const char *mismatch = "Protocol mismatch.\r\n"; 321*664f4763Szrj const u_char *s = sshbuf_ptr(input); 322*664f4763Szrj u_char c; 323*664f4763Szrj char *cp, *remote_version; 324*664f4763Szrj int r, remote_major, remote_minor, expect_nl; 325*664f4763Szrj size_t n, j; 326e9778795SPeter Avalos 327e9778795SPeter Avalos for (j = n = 0;;) { 328*664f4763Szrj sshbuf_reset(banner); 329*664f4763Szrj expect_nl = 0; 330*664f4763Szrj for (;;) { 331*664f4763Szrj if (j >= sshbuf_len(input)) 332*664f4763Szrj return 0; /* insufficient data in input buf */ 333*664f4763Szrj c = s[j++]; 334*664f4763Szrj if (c == '\r') { 335*664f4763Szrj expect_nl = 1; 336*664f4763Szrj continue; 337e9778795SPeter Avalos } 338*664f4763Szrj if (c == '\n') 339e9778795SPeter Avalos break; 340*664f4763Szrj if (expect_nl) 341*664f4763Szrj goto bad; 342*664f4763Szrj if ((r = sshbuf_put_u8(banner, c)) != 0) 343*664f4763Szrj return r; 344*664f4763Szrj if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN) 345*664f4763Szrj goto bad; 346e9778795SPeter Avalos } 347*664f4763Szrj if (sshbuf_len(banner) >= 4 && 348*664f4763Szrj memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0) 349e9778795SPeter Avalos break; 350*664f4763Szrj if ((cp = sshbuf_dup_string(banner)) == NULL) 351*664f4763Szrj return SSH_ERR_ALLOC_FAIL; 352*664f4763Szrj debug("%s: %s", __func__, cp); 353*664f4763Szrj free(cp); 354*664f4763Szrj /* Accept lines before banner only on client */ 355*664f4763Szrj if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) { 356*664f4763Szrj bad: 357e9778795SPeter Avalos if ((r = sshbuf_put(ssh_packet_get_output(ssh), 358e9778795SPeter Avalos mismatch, strlen(mismatch))) != 0) 359e9778795SPeter Avalos return r; 360e9778795SPeter Avalos return SSH_ERR_NO_PROTOCOL_VERSION; 361e9778795SPeter Avalos } 362e9778795SPeter Avalos } 363e9778795SPeter Avalos if ((r = sshbuf_consume(input, j)) != 0) 364e9778795SPeter Avalos return r; 365e9778795SPeter Avalos 366*664f4763Szrj if ((cp = sshbuf_dup_string(banner)) == NULL) 367*664f4763Szrj return SSH_ERR_ALLOC_FAIL; 368*664f4763Szrj /* XXX remote version must be the same size as banner for sscanf */ 369*664f4763Szrj if ((remote_version = calloc(1, sshbuf_len(banner))) == NULL) 370*664f4763Szrj return SSH_ERR_ALLOC_FAIL; 371*664f4763Szrj 372e9778795SPeter Avalos /* 373e9778795SPeter Avalos * Check that the versions match. In future this might accept 374e9778795SPeter Avalos * several versions and set appropriate flags to handle them. 375e9778795SPeter Avalos */ 376*664f4763Szrj if (sscanf(cp, "SSH-%d.%d-%[^\n]\n", 377e9778795SPeter Avalos &remote_major, &remote_minor, remote_version) != 3) 378e9778795SPeter Avalos return SSH_ERR_INVALID_FORMAT; 379e9778795SPeter Avalos debug("Remote protocol version %d.%d, remote software version %.100s", 380e9778795SPeter Avalos remote_major, remote_minor, remote_version); 381e9778795SPeter Avalos 382e9778795SPeter Avalos ssh->compat = compat_datafellows(remote_version); 383e9778795SPeter Avalos if (remote_major == 1 && remote_minor == 99) { 384e9778795SPeter Avalos remote_major = 2; 385e9778795SPeter Avalos remote_minor = 0; 386e9778795SPeter Avalos } 387e9778795SPeter Avalos if (remote_major != 2) 388e9778795SPeter Avalos return SSH_ERR_PROTOCOL_MISMATCH; 389*664f4763Szrj debug("Remote version string %.100s", cp); 390*664f4763Szrj free(cp); 391e9778795SPeter Avalos return 0; 392e9778795SPeter Avalos } 393e9778795SPeter Avalos 394e9778795SPeter Avalos /* Send our own protocol version identification. */ 395e9778795SPeter Avalos int 396*664f4763Szrj _ssh_send_banner(struct ssh *ssh, struct sshbuf *banner) 397e9778795SPeter Avalos { 398*664f4763Szrj char *cp; 399e9778795SPeter Avalos int r; 400e9778795SPeter Avalos 401*664f4763Szrj if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0) 402e9778795SPeter Avalos return r; 403*664f4763Szrj if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) 404*664f4763Szrj return r; 405*664f4763Szrj /* Remove trailing \r\n */ 406*664f4763Szrj if ((r = sshbuf_consume_end(banner, 2)) != 0) 407*664f4763Szrj return r; 408*664f4763Szrj if ((cp = sshbuf_dup_string(banner)) == NULL) 409e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 410*664f4763Szrj debug("Local version string %.100s", cp); 411*664f4763Szrj free(cp); 412e9778795SPeter Avalos return 0; 413e9778795SPeter Avalos } 414e9778795SPeter Avalos 415e9778795SPeter Avalos int 416e9778795SPeter Avalos _ssh_exchange_banner(struct ssh *ssh) 417e9778795SPeter Avalos { 418e9778795SPeter Avalos struct kex *kex = ssh->kex; 419e9778795SPeter Avalos int r; 420e9778795SPeter Avalos 421e9778795SPeter Avalos /* 422e9778795SPeter Avalos * if _ssh_read_banner() cannot parse a full version string 423e9778795SPeter Avalos * it will return NULL and we end up calling it again. 424e9778795SPeter Avalos */ 425e9778795SPeter Avalos 426e9778795SPeter Avalos r = 0; 427e9778795SPeter Avalos if (kex->server) { 428*664f4763Szrj if (sshbuf_len(ssh->kex->server_version) == 0) 429*664f4763Szrj r = _ssh_send_banner(ssh, ssh->kex->server_version); 430e9778795SPeter Avalos if (r == 0 && 431*664f4763Szrj sshbuf_len(ssh->kex->server_version) != 0 && 432*664f4763Szrj sshbuf_len(ssh->kex->client_version) == 0) 433*664f4763Szrj r = _ssh_read_banner(ssh, ssh->kex->client_version); 434e9778795SPeter Avalos } else { 435*664f4763Szrj if (sshbuf_len(ssh->kex->server_version) == 0) 436*664f4763Szrj r = _ssh_read_banner(ssh, ssh->kex->server_version); 437e9778795SPeter Avalos if (r == 0 && 438*664f4763Szrj sshbuf_len(ssh->kex->server_version) != 0 && 439*664f4763Szrj sshbuf_len(ssh->kex->client_version) == 0) 440*664f4763Szrj r = _ssh_send_banner(ssh, ssh->kex->client_version); 441e9778795SPeter Avalos } 442e9778795SPeter Avalos if (r != 0) 443e9778795SPeter Avalos return r; 444e9778795SPeter Avalos /* start initial kex as soon as we have exchanged the banners */ 445*664f4763Szrj if (sshbuf_len(ssh->kex->server_version) != 0 && 446*664f4763Szrj sshbuf_len(ssh->kex->client_version) != 0) { 447e9778795SPeter Avalos if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 || 448e9778795SPeter Avalos (r = kex_send_kexinit(ssh)) != 0) 449e9778795SPeter Avalos return r; 450e9778795SPeter Avalos } 451e9778795SPeter Avalos return 0; 452e9778795SPeter Avalos } 453e9778795SPeter Avalos 454e9778795SPeter Avalos struct sshkey * 455e9778795SPeter Avalos _ssh_host_public_key(int type, int nid, struct ssh *ssh) 456e9778795SPeter Avalos { 457e9778795SPeter Avalos struct key_entry *k; 458e9778795SPeter Avalos 459e9778795SPeter Avalos debug3("%s: need %d", __func__, type); 460e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->public_keys, next) { 461e9778795SPeter Avalos debug3("%s: check %s", __func__, sshkey_type(k->key)); 462e9778795SPeter Avalos if (k->key->type == type && 463e9778795SPeter Avalos (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 464e9778795SPeter Avalos return (k->key); 465e9778795SPeter Avalos } 466e9778795SPeter Avalos return (NULL); 467e9778795SPeter Avalos } 468e9778795SPeter Avalos 469e9778795SPeter Avalos struct sshkey * 470e9778795SPeter Avalos _ssh_host_private_key(int type, int nid, struct ssh *ssh) 471e9778795SPeter Avalos { 472e9778795SPeter Avalos struct key_entry *k; 473e9778795SPeter Avalos 474e9778795SPeter Avalos debug3("%s: need %d", __func__, type); 475e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->private_keys, next) { 476e9778795SPeter Avalos debug3("%s: check %s", __func__, sshkey_type(k->key)); 477e9778795SPeter Avalos if (k->key->type == type && 478e9778795SPeter Avalos (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 479e9778795SPeter Avalos return (k->key); 480e9778795SPeter Avalos } 481e9778795SPeter Avalos return (NULL); 482e9778795SPeter Avalos } 483e9778795SPeter Avalos 484e9778795SPeter Avalos int 485e9778795SPeter Avalos _ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh) 486e9778795SPeter Avalos { 487e9778795SPeter Avalos struct key_entry *k; 488e9778795SPeter Avalos 489e9778795SPeter Avalos debug3("%s: need %s", __func__, sshkey_type(hostkey)); 490e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->public_keys, next) { 491e9778795SPeter Avalos debug3("%s: check %s", __func__, sshkey_type(k->key)); 492e9778795SPeter Avalos if (sshkey_equal_public(hostkey, k->key)) 493e9778795SPeter Avalos return (0); /* ok */ 494e9778795SPeter Avalos } 495e9778795SPeter Avalos return (-1); /* failed */ 496e9778795SPeter Avalos } 497e9778795SPeter Avalos 498e9778795SPeter Avalos /* offer hostkey algorithms in kexinit depending on registered keys */ 499e9778795SPeter Avalos int 500e9778795SPeter Avalos _ssh_order_hostkeyalgs(struct ssh *ssh) 501e9778795SPeter Avalos { 502e9778795SPeter Avalos struct key_entry *k; 503e9778795SPeter Avalos char *orig, *avail, *oavail = NULL, *alg, *replace = NULL; 504e9778795SPeter Avalos char **proposal; 505e9778795SPeter Avalos size_t maxlen; 506e9778795SPeter Avalos int ktype, r; 507e9778795SPeter Avalos 508e9778795SPeter Avalos /* XXX we de-serialize ssh->kex->my, modify it, and change it */ 509e9778795SPeter Avalos if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0) 510e9778795SPeter Avalos return r; 511e9778795SPeter Avalos orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; 512e9778795SPeter Avalos if ((oavail = avail = strdup(orig)) == NULL) { 513e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 514e9778795SPeter Avalos goto out; 515e9778795SPeter Avalos } 516e9778795SPeter Avalos maxlen = strlen(avail) + 1; 517e9778795SPeter Avalos if ((replace = calloc(1, maxlen)) == NULL) { 518e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 519e9778795SPeter Avalos goto out; 520e9778795SPeter Avalos } 521e9778795SPeter Avalos *replace = '\0'; 522e9778795SPeter Avalos while ((alg = strsep(&avail, ",")) && *alg != '\0') { 523e9778795SPeter Avalos if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 524e9778795SPeter Avalos continue; 525e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->public_keys, next) { 526e9778795SPeter Avalos if (k->key->type == ktype || 527e9778795SPeter Avalos (sshkey_is_cert(k->key) && k->key->type == 528e9778795SPeter Avalos sshkey_type_plain(ktype))) { 529e9778795SPeter Avalos if (*replace != '\0') 530e9778795SPeter Avalos strlcat(replace, ",", maxlen); 531e9778795SPeter Avalos strlcat(replace, alg, maxlen); 532e9778795SPeter Avalos break; 533e9778795SPeter Avalos } 534e9778795SPeter Avalos } 535e9778795SPeter Avalos } 536e9778795SPeter Avalos if (*replace != '\0') { 537e9778795SPeter Avalos debug2("%s: orig/%d %s", __func__, ssh->kex->server, orig); 538e9778795SPeter Avalos debug2("%s: replace/%d %s", __func__, ssh->kex->server, replace); 539e9778795SPeter Avalos free(orig); 540e9778795SPeter Avalos proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace; 541e9778795SPeter Avalos replace = NULL; /* owned by proposal */ 542e9778795SPeter Avalos r = kex_prop2buf(ssh->kex->my, proposal); 543e9778795SPeter Avalos } 544e9778795SPeter Avalos out: 545e9778795SPeter Avalos free(oavail); 546e9778795SPeter Avalos free(replace); 547e9778795SPeter Avalos kex_prop_free(proposal); 548e9778795SPeter Avalos return r; 549e9778795SPeter Avalos } 550e9778795SPeter Avalos 551e9778795SPeter Avalos int 552*664f4763Szrj _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey, 553*664f4763Szrj struct sshkey *pubkey, u_char **signature, size_t *slen, 554*664f4763Szrj const u_char *data, size_t dlen, const char *alg) 555e9778795SPeter Avalos { 556*664f4763Szrj return sshkey_sign(privkey, signature, slen, data, dlen, 557*664f4763Szrj alg, ssh->compat); 558e9778795SPeter Avalos } 559