1*0cbfa66cSDaniel Fojt /* $OpenBSD: ssh_api.c,v 1.19 2019/10/31 21:23:19 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 20*0cbfa66cSDaniel Fojt #include <sys/types.h> 21*0cbfa66cSDaniel Fojt 22*0cbfa66cSDaniel Fojt #include <stdio.h> 23*0cbfa66cSDaniel Fojt #include <stdlib.h> 24*0cbfa66cSDaniel Fojt 25e9778795SPeter Avalos #include "ssh_api.h" 26e9778795SPeter Avalos #include "compat.h" 27e9778795SPeter Avalos #include "log.h" 28e9778795SPeter Avalos #include "authfile.h" 29e9778795SPeter Avalos #include "sshkey.h" 30e9778795SPeter Avalos #include "misc.h" 31e9778795SPeter Avalos #include "ssh2.h" 32e9778795SPeter Avalos #include "version.h" 33e9778795SPeter Avalos #include "myproposal.h" 34e9778795SPeter Avalos #include "ssherr.h" 35e9778795SPeter Avalos #include "sshbuf.h" 36e9778795SPeter Avalos 37664f4763Szrj #include "openbsd-compat/openssl-compat.h" 38664f4763Szrj 39e9778795SPeter Avalos #include <string.h> 40e9778795SPeter Avalos 41e9778795SPeter Avalos int _ssh_exchange_banner(struct ssh *); 42664f4763Szrj int _ssh_send_banner(struct ssh *, struct sshbuf *); 43664f4763Szrj int _ssh_read_banner(struct ssh *, struct sshbuf *); 44e9778795SPeter Avalos int _ssh_order_hostkeyalgs(struct ssh *); 45e9778795SPeter Avalos int _ssh_verify_host_key(struct sshkey *, struct ssh *); 46e9778795SPeter Avalos struct sshkey *_ssh_host_public_key(int, int, struct ssh *); 47e9778795SPeter Avalos struct sshkey *_ssh_host_private_key(int, int, struct ssh *); 48664f4763Szrj int _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *, 49664f4763Szrj u_char **, size_t *, const u_char *, size_t, const char *); 50e9778795SPeter Avalos 51e9778795SPeter Avalos /* 52e9778795SPeter Avalos * stubs for the server side implementation of kex. 53e9778795SPeter Avalos * disable privsep so our stubs will never be called. 54e9778795SPeter Avalos */ 55e9778795SPeter Avalos int use_privsep = 0; 56e9778795SPeter Avalos int mm_sshkey_sign(struct sshkey *, u_char **, u_int *, 57*0cbfa66cSDaniel Fojt const u_char *, u_int, const char *, const char *, u_int); 58*0cbfa66cSDaniel Fojt 59*0cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL 60e9778795SPeter Avalos DH *mm_choose_dh(int, int, int); 61*0cbfa66cSDaniel Fojt #endif 62e9778795SPeter Avalos 63e9778795SPeter Avalos /* Define these two variables here so that they are part of the library */ 64e9778795SPeter Avalos u_char *session_id2 = NULL; 65e9778795SPeter Avalos u_int session_id2_len = 0; 66e9778795SPeter Avalos 67e9778795SPeter Avalos int 68e9778795SPeter Avalos mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp, 69*0cbfa66cSDaniel Fojt const u_char *data, u_int datalen, const char *alg, const char *sk_provider, 70*0cbfa66cSDaniel Fojt u_int compat) 71e9778795SPeter Avalos { 72e9778795SPeter Avalos return (-1); 73e9778795SPeter Avalos } 74e9778795SPeter Avalos 75*0cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL 76e9778795SPeter Avalos DH * 77e9778795SPeter Avalos mm_choose_dh(int min, int nbits, int max) 78e9778795SPeter Avalos { 79e9778795SPeter Avalos return (NULL); 80e9778795SPeter Avalos } 81*0cbfa66cSDaniel Fojt #endif 82e9778795SPeter Avalos 83e9778795SPeter Avalos /* API */ 84e9778795SPeter Avalos 85e9778795SPeter Avalos int 86e9778795SPeter Avalos ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) 87e9778795SPeter Avalos { 88e9778795SPeter Avalos char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 89e9778795SPeter Avalos struct ssh *ssh; 90e9778795SPeter Avalos char **proposal; 91e9778795SPeter Avalos static int called; 92e9778795SPeter Avalos int r; 93e9778795SPeter Avalos 94e9778795SPeter Avalos if (!called) { 95664f4763Szrj seed_rng(); 96e9778795SPeter Avalos called = 1; 97e9778795SPeter Avalos } 98e9778795SPeter Avalos 99e9778795SPeter Avalos if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL) 100e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 101e9778795SPeter Avalos if (is_server) 102e9778795SPeter Avalos ssh_packet_set_server(ssh); 103e9778795SPeter Avalos 104e9778795SPeter Avalos /* Initialize key exchange */ 105e9778795SPeter Avalos proposal = kex_params ? kex_params->proposal : myproposal; 106664f4763Szrj if ((r = kex_ready(ssh, proposal)) != 0) { 107e9778795SPeter Avalos ssh_free(ssh); 108e9778795SPeter Avalos return r; 109e9778795SPeter Avalos } 110e9778795SPeter Avalos ssh->kex->server = is_server; 111e9778795SPeter Avalos if (is_server) { 112e9778795SPeter Avalos #ifdef WITH_OPENSSL 113664f4763Szrj ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 114664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 115664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; 116664f4763Szrj ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; 117664f4763Szrj ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; 118e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 119e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 120e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 121664f4763Szrj ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 122e9778795SPeter Avalos # endif 123e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 124664f4763Szrj ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; 125664f4763Szrj ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server; 126e9778795SPeter Avalos ssh->kex->load_host_public_key=&_ssh_host_public_key; 127e9778795SPeter Avalos ssh->kex->load_host_private_key=&_ssh_host_private_key; 128e9778795SPeter Avalos ssh->kex->sign=&_ssh_host_key_sign; 129e9778795SPeter Avalos } else { 130e9778795SPeter Avalos #ifdef WITH_OPENSSL 131664f4763Szrj ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client; 132664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client; 133664f4763Szrj ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client; 134664f4763Szrj ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client; 135664f4763Szrj ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client; 136e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 137e9778795SPeter Avalos ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 138e9778795SPeter Avalos # ifdef OPENSSL_HAS_ECC 139664f4763Szrj ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 140e9778795SPeter Avalos # endif 141e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 142664f4763Szrj ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 143664f4763Szrj ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 144e9778795SPeter Avalos ssh->kex->verify_host_key =&_ssh_verify_host_key; 145e9778795SPeter Avalos } 146e9778795SPeter Avalos *sshp = ssh; 147e9778795SPeter Avalos return 0; 148e9778795SPeter Avalos } 149e9778795SPeter Avalos 150e9778795SPeter Avalos void 151e9778795SPeter Avalos ssh_free(struct ssh *ssh) 152e9778795SPeter Avalos { 153e9778795SPeter Avalos struct key_entry *k; 154e9778795SPeter Avalos 155e9778795SPeter Avalos ssh_packet_close(ssh); 156e9778795SPeter Avalos /* 157e9778795SPeter Avalos * we've only created the public keys variants in case we 158e9778795SPeter Avalos * are a acting as a server. 159e9778795SPeter Avalos */ 160e9778795SPeter Avalos while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) { 161e9778795SPeter Avalos TAILQ_REMOVE(&ssh->public_keys, k, next); 162e9778795SPeter Avalos if (ssh->kex && ssh->kex->server) 163e9778795SPeter Avalos sshkey_free(k->key); 164e9778795SPeter Avalos free(k); 165e9778795SPeter Avalos } 166e9778795SPeter Avalos while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) { 167e9778795SPeter Avalos TAILQ_REMOVE(&ssh->private_keys, k, next); 168e9778795SPeter Avalos free(k); 169e9778795SPeter Avalos } 170e9778795SPeter Avalos if (ssh->kex) 171e9778795SPeter Avalos kex_free(ssh->kex); 172e9778795SPeter Avalos free(ssh); 173e9778795SPeter Avalos } 174e9778795SPeter Avalos 175e9778795SPeter Avalos void 176e9778795SPeter Avalos ssh_set_app_data(struct ssh *ssh, void *app_data) 177e9778795SPeter Avalos { 178e9778795SPeter Avalos ssh->app_data = app_data; 179e9778795SPeter Avalos } 180e9778795SPeter Avalos 181e9778795SPeter Avalos void * 182e9778795SPeter Avalos ssh_get_app_data(struct ssh *ssh) 183e9778795SPeter Avalos { 184e9778795SPeter Avalos return ssh->app_data; 185e9778795SPeter Avalos } 186e9778795SPeter Avalos 187e9778795SPeter Avalos /* Returns < 0 on error, 0 otherwise */ 188e9778795SPeter Avalos int 189e9778795SPeter Avalos ssh_add_hostkey(struct ssh *ssh, struct sshkey *key) 190e9778795SPeter Avalos { 191e9778795SPeter Avalos struct sshkey *pubkey = NULL; 192e9778795SPeter Avalos struct key_entry *k = NULL, *k_prv = NULL; 193e9778795SPeter Avalos int r; 194e9778795SPeter Avalos 195e9778795SPeter Avalos if (ssh->kex->server) { 196e9778795SPeter Avalos if ((r = sshkey_from_private(key, &pubkey)) != 0) 197e9778795SPeter Avalos return r; 198e9778795SPeter Avalos if ((k = malloc(sizeof(*k))) == NULL || 199e9778795SPeter Avalos (k_prv = malloc(sizeof(*k_prv))) == NULL) { 200e9778795SPeter Avalos free(k); 201e9778795SPeter Avalos sshkey_free(pubkey); 202e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 203e9778795SPeter Avalos } 204e9778795SPeter Avalos k_prv->key = key; 205e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next); 206e9778795SPeter Avalos 207e9778795SPeter Avalos /* add the public key, too */ 208e9778795SPeter Avalos k->key = pubkey; 209e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 210e9778795SPeter Avalos r = 0; 211e9778795SPeter Avalos } else { 212e9778795SPeter Avalos if ((k = malloc(sizeof(*k))) == NULL) 213e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 214e9778795SPeter Avalos k->key = key; 215e9778795SPeter Avalos TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 216e9778795SPeter Avalos r = 0; 217e9778795SPeter Avalos } 218e9778795SPeter Avalos 219e9778795SPeter Avalos return r; 220e9778795SPeter Avalos } 221e9778795SPeter Avalos 222e9778795SPeter Avalos int 223e9778795SPeter Avalos ssh_set_verify_host_key_callback(struct ssh *ssh, 224e9778795SPeter Avalos int (*cb)(struct sshkey *, struct ssh *)) 225e9778795SPeter Avalos { 226e9778795SPeter Avalos if (cb == NULL || ssh->kex == NULL) 227e9778795SPeter Avalos return SSH_ERR_INVALID_ARGUMENT; 228e9778795SPeter Avalos 229e9778795SPeter Avalos ssh->kex->verify_host_key = cb; 230e9778795SPeter Avalos 231e9778795SPeter Avalos return 0; 232e9778795SPeter Avalos } 233e9778795SPeter Avalos 234e9778795SPeter Avalos int 235e9778795SPeter Avalos ssh_input_append(struct ssh *ssh, const u_char *data, size_t len) 236e9778795SPeter Avalos { 237e9778795SPeter Avalos return sshbuf_put(ssh_packet_get_input(ssh), data, len); 238e9778795SPeter Avalos } 239e9778795SPeter Avalos 240e9778795SPeter Avalos int 241e9778795SPeter Avalos ssh_packet_next(struct ssh *ssh, u_char *typep) 242e9778795SPeter Avalos { 243e9778795SPeter Avalos int r; 244e9778795SPeter Avalos u_int32_t seqnr; 245e9778795SPeter Avalos u_char type; 246e9778795SPeter Avalos 247e9778795SPeter Avalos /* 248e9778795SPeter Avalos * Try to read a packet. Return SSH_MSG_NONE if no packet or not 249e9778795SPeter Avalos * enough data. 250e9778795SPeter Avalos */ 251e9778795SPeter Avalos *typep = SSH_MSG_NONE; 252664f4763Szrj if (sshbuf_len(ssh->kex->client_version) == 0 || 253664f4763Szrj sshbuf_len(ssh->kex->server_version) == 0) 254e9778795SPeter Avalos return _ssh_exchange_banner(ssh); 255e9778795SPeter Avalos /* 256e9778795SPeter Avalos * If we enough data and a dispatch function then 257e9778795SPeter Avalos * call the function and get the next packet. 258e9778795SPeter Avalos * Otherwise return the packet type to the caller so it 259e9778795SPeter Avalos * can decide how to go on. 260e9778795SPeter Avalos * 261e9778795SPeter Avalos * We will only call the dispatch function for: 262e9778795SPeter Avalos * 20-29 Algorithm negotiation 263e9778795SPeter Avalos * 30-49 Key exchange method specific (numbers can be reused for 264e9778795SPeter Avalos * different authentication methods) 265e9778795SPeter Avalos */ 266e9778795SPeter Avalos for (;;) { 267e9778795SPeter Avalos if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0) 268e9778795SPeter Avalos return r; 269e9778795SPeter Avalos if (type > 0 && type < DISPATCH_MAX && 270e9778795SPeter Avalos type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX && 271e9778795SPeter Avalos ssh->dispatch[type] != NULL) { 272e9778795SPeter Avalos if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0) 273e9778795SPeter Avalos return r; 274e9778795SPeter Avalos } else { 275e9778795SPeter Avalos *typep = type; 276e9778795SPeter Avalos return 0; 277e9778795SPeter Avalos } 278e9778795SPeter Avalos } 279e9778795SPeter Avalos } 280e9778795SPeter Avalos 281e9778795SPeter Avalos const u_char * 282e9778795SPeter Avalos ssh_packet_payload(struct ssh *ssh, size_t *lenp) 283e9778795SPeter Avalos { 284e9778795SPeter Avalos return sshpkt_ptr(ssh, lenp); 285e9778795SPeter Avalos } 286e9778795SPeter Avalos 287e9778795SPeter Avalos int 288e9778795SPeter Avalos ssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len) 289e9778795SPeter Avalos { 290e9778795SPeter Avalos int r; 291e9778795SPeter Avalos 292e9778795SPeter Avalos if ((r = sshpkt_start(ssh, type)) != 0 || 293e9778795SPeter Avalos (r = sshpkt_put(ssh, data, len)) != 0 || 294e9778795SPeter Avalos (r = sshpkt_send(ssh)) != 0) 295e9778795SPeter Avalos return r; 296e9778795SPeter Avalos return 0; 297e9778795SPeter Avalos } 298e9778795SPeter Avalos 299e9778795SPeter Avalos const u_char * 300e9778795SPeter Avalos ssh_output_ptr(struct ssh *ssh, size_t *len) 301e9778795SPeter Avalos { 302e9778795SPeter Avalos struct sshbuf *output = ssh_packet_get_output(ssh); 303e9778795SPeter Avalos 304e9778795SPeter Avalos *len = sshbuf_len(output); 305e9778795SPeter Avalos return sshbuf_ptr(output); 306e9778795SPeter Avalos } 307e9778795SPeter Avalos 308e9778795SPeter Avalos int 309e9778795SPeter Avalos ssh_output_consume(struct ssh *ssh, size_t len) 310e9778795SPeter Avalos { 311e9778795SPeter Avalos return sshbuf_consume(ssh_packet_get_output(ssh), len); 312e9778795SPeter Avalos } 313e9778795SPeter Avalos 314e9778795SPeter Avalos int 315e9778795SPeter Avalos ssh_output_space(struct ssh *ssh, size_t len) 316e9778795SPeter Avalos { 317e9778795SPeter Avalos return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len)); 318e9778795SPeter Avalos } 319e9778795SPeter Avalos 320e9778795SPeter Avalos int 321e9778795SPeter Avalos ssh_input_space(struct ssh *ssh, size_t len) 322e9778795SPeter Avalos { 323e9778795SPeter Avalos return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len)); 324e9778795SPeter Avalos } 325e9778795SPeter Avalos 326e9778795SPeter Avalos /* Read other side's version identification. */ 327e9778795SPeter Avalos int 328664f4763Szrj _ssh_read_banner(struct ssh *ssh, struct sshbuf *banner) 329e9778795SPeter Avalos { 330664f4763Szrj struct sshbuf *input = ssh_packet_get_input(ssh); 331e9778795SPeter Avalos const char *mismatch = "Protocol mismatch.\r\n"; 332664f4763Szrj const u_char *s = sshbuf_ptr(input); 333664f4763Szrj u_char c; 334*0cbfa66cSDaniel Fojt char *cp = NULL, *remote_version = NULL; 335*0cbfa66cSDaniel Fojt int r = 0, remote_major, remote_minor, expect_nl; 336664f4763Szrj size_t n, j; 337e9778795SPeter Avalos 338e9778795SPeter Avalos for (j = n = 0;;) { 339664f4763Szrj sshbuf_reset(banner); 340664f4763Szrj expect_nl = 0; 341664f4763Szrj for (;;) { 342664f4763Szrj if (j >= sshbuf_len(input)) 343664f4763Szrj return 0; /* insufficient data in input buf */ 344664f4763Szrj c = s[j++]; 345664f4763Szrj if (c == '\r') { 346664f4763Szrj expect_nl = 1; 347664f4763Szrj continue; 348e9778795SPeter Avalos } 349664f4763Szrj if (c == '\n') 350e9778795SPeter Avalos break; 351664f4763Szrj if (expect_nl) 352664f4763Szrj goto bad; 353664f4763Szrj if ((r = sshbuf_put_u8(banner, c)) != 0) 354664f4763Szrj return r; 355664f4763Szrj if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN) 356664f4763Szrj goto bad; 357e9778795SPeter Avalos } 358664f4763Szrj if (sshbuf_len(banner) >= 4 && 359664f4763Szrj memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0) 360e9778795SPeter Avalos break; 361*0cbfa66cSDaniel Fojt debug("%s: %.*s", __func__, (int)sshbuf_len(banner), 362*0cbfa66cSDaniel Fojt sshbuf_ptr(banner)); 363664f4763Szrj /* Accept lines before banner only on client */ 364664f4763Szrj if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) { 365664f4763Szrj bad: 366e9778795SPeter Avalos if ((r = sshbuf_put(ssh_packet_get_output(ssh), 367e9778795SPeter Avalos mismatch, strlen(mismatch))) != 0) 368e9778795SPeter Avalos return r; 369e9778795SPeter Avalos return SSH_ERR_NO_PROTOCOL_VERSION; 370e9778795SPeter Avalos } 371e9778795SPeter Avalos } 372e9778795SPeter Avalos if ((r = sshbuf_consume(input, j)) != 0) 373e9778795SPeter Avalos return r; 374e9778795SPeter Avalos 375664f4763Szrj /* XXX remote version must be the same size as banner for sscanf */ 376*0cbfa66cSDaniel Fojt if ((cp = sshbuf_dup_string(banner)) == NULL || 377*0cbfa66cSDaniel Fojt (remote_version = calloc(1, sshbuf_len(banner))) == NULL) { 378*0cbfa66cSDaniel Fojt r = SSH_ERR_ALLOC_FAIL; 379*0cbfa66cSDaniel Fojt goto out; 380*0cbfa66cSDaniel Fojt } 381664f4763Szrj 382e9778795SPeter Avalos /* 383e9778795SPeter Avalos * Check that the versions match. In future this might accept 384e9778795SPeter Avalos * several versions and set appropriate flags to handle them. 385e9778795SPeter Avalos */ 386664f4763Szrj if (sscanf(cp, "SSH-%d.%d-%[^\n]\n", 387*0cbfa66cSDaniel Fojt &remote_major, &remote_minor, remote_version) != 3) { 388*0cbfa66cSDaniel Fojt r = SSH_ERR_INVALID_FORMAT; 389*0cbfa66cSDaniel Fojt goto out; 390*0cbfa66cSDaniel Fojt } 391e9778795SPeter Avalos debug("Remote protocol version %d.%d, remote software version %.100s", 392e9778795SPeter Avalos remote_major, remote_minor, remote_version); 393e9778795SPeter Avalos 394e9778795SPeter Avalos ssh->compat = compat_datafellows(remote_version); 395e9778795SPeter Avalos if (remote_major == 1 && remote_minor == 99) { 396e9778795SPeter Avalos remote_major = 2; 397e9778795SPeter Avalos remote_minor = 0; 398e9778795SPeter Avalos } 399e9778795SPeter Avalos if (remote_major != 2) 400*0cbfa66cSDaniel Fojt r = SSH_ERR_PROTOCOL_MISMATCH; 401*0cbfa66cSDaniel Fojt 402664f4763Szrj debug("Remote version string %.100s", cp); 403*0cbfa66cSDaniel Fojt out: 404664f4763Szrj free(cp); 405*0cbfa66cSDaniel Fojt free(remote_version); 406*0cbfa66cSDaniel Fojt return r; 407e9778795SPeter Avalos } 408e9778795SPeter Avalos 409e9778795SPeter Avalos /* Send our own protocol version identification. */ 410e9778795SPeter Avalos int 411664f4763Szrj _ssh_send_banner(struct ssh *ssh, struct sshbuf *banner) 412e9778795SPeter Avalos { 413664f4763Szrj char *cp; 414e9778795SPeter Avalos int r; 415e9778795SPeter Avalos 416664f4763Szrj if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0) 417e9778795SPeter Avalos return r; 418664f4763Szrj if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) 419664f4763Szrj return r; 420664f4763Szrj /* Remove trailing \r\n */ 421664f4763Szrj if ((r = sshbuf_consume_end(banner, 2)) != 0) 422664f4763Szrj return r; 423664f4763Szrj if ((cp = sshbuf_dup_string(banner)) == NULL) 424e9778795SPeter Avalos return SSH_ERR_ALLOC_FAIL; 425664f4763Szrj debug("Local version string %.100s", cp); 426664f4763Szrj free(cp); 427e9778795SPeter Avalos return 0; 428e9778795SPeter Avalos } 429e9778795SPeter Avalos 430e9778795SPeter Avalos int 431e9778795SPeter Avalos _ssh_exchange_banner(struct ssh *ssh) 432e9778795SPeter Avalos { 433e9778795SPeter Avalos struct kex *kex = ssh->kex; 434e9778795SPeter Avalos int r; 435e9778795SPeter Avalos 436e9778795SPeter Avalos /* 437e9778795SPeter Avalos * if _ssh_read_banner() cannot parse a full version string 438e9778795SPeter Avalos * it will return NULL and we end up calling it again. 439e9778795SPeter Avalos */ 440e9778795SPeter Avalos 441e9778795SPeter Avalos r = 0; 442e9778795SPeter Avalos if (kex->server) { 443664f4763Szrj if (sshbuf_len(ssh->kex->server_version) == 0) 444664f4763Szrj r = _ssh_send_banner(ssh, ssh->kex->server_version); 445e9778795SPeter Avalos if (r == 0 && 446664f4763Szrj sshbuf_len(ssh->kex->server_version) != 0 && 447664f4763Szrj sshbuf_len(ssh->kex->client_version) == 0) 448664f4763Szrj r = _ssh_read_banner(ssh, ssh->kex->client_version); 449e9778795SPeter Avalos } else { 450664f4763Szrj if (sshbuf_len(ssh->kex->server_version) == 0) 451664f4763Szrj r = _ssh_read_banner(ssh, ssh->kex->server_version); 452e9778795SPeter Avalos if (r == 0 && 453664f4763Szrj sshbuf_len(ssh->kex->server_version) != 0 && 454664f4763Szrj sshbuf_len(ssh->kex->client_version) == 0) 455664f4763Szrj r = _ssh_send_banner(ssh, ssh->kex->client_version); 456e9778795SPeter Avalos } 457e9778795SPeter Avalos if (r != 0) 458e9778795SPeter Avalos return r; 459e9778795SPeter Avalos /* start initial kex as soon as we have exchanged the banners */ 460664f4763Szrj if (sshbuf_len(ssh->kex->server_version) != 0 && 461664f4763Szrj sshbuf_len(ssh->kex->client_version) != 0) { 462e9778795SPeter Avalos if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 || 463e9778795SPeter Avalos (r = kex_send_kexinit(ssh)) != 0) 464e9778795SPeter Avalos return r; 465e9778795SPeter Avalos } 466e9778795SPeter Avalos return 0; 467e9778795SPeter Avalos } 468e9778795SPeter Avalos 469e9778795SPeter Avalos struct sshkey * 470e9778795SPeter Avalos _ssh_host_public_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->public_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 struct sshkey * 485e9778795SPeter Avalos _ssh_host_private_key(int type, int nid, struct ssh *ssh) 486e9778795SPeter Avalos { 487e9778795SPeter Avalos struct key_entry *k; 488e9778795SPeter Avalos 489e9778795SPeter Avalos debug3("%s: need %d", __func__, type); 490e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->private_keys, next) { 491e9778795SPeter Avalos debug3("%s: check %s", __func__, sshkey_type(k->key)); 492e9778795SPeter Avalos if (k->key->type == type && 493e9778795SPeter Avalos (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 494e9778795SPeter Avalos return (k->key); 495e9778795SPeter Avalos } 496e9778795SPeter Avalos return (NULL); 497e9778795SPeter Avalos } 498e9778795SPeter Avalos 499e9778795SPeter Avalos int 500e9778795SPeter Avalos _ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh) 501e9778795SPeter Avalos { 502e9778795SPeter Avalos struct key_entry *k; 503e9778795SPeter Avalos 504e9778795SPeter Avalos debug3("%s: need %s", __func__, sshkey_type(hostkey)); 505e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->public_keys, next) { 506e9778795SPeter Avalos debug3("%s: check %s", __func__, sshkey_type(k->key)); 507e9778795SPeter Avalos if (sshkey_equal_public(hostkey, k->key)) 508e9778795SPeter Avalos return (0); /* ok */ 509e9778795SPeter Avalos } 510e9778795SPeter Avalos return (-1); /* failed */ 511e9778795SPeter Avalos } 512e9778795SPeter Avalos 513e9778795SPeter Avalos /* offer hostkey algorithms in kexinit depending on registered keys */ 514e9778795SPeter Avalos int 515e9778795SPeter Avalos _ssh_order_hostkeyalgs(struct ssh *ssh) 516e9778795SPeter Avalos { 517e9778795SPeter Avalos struct key_entry *k; 518e9778795SPeter Avalos char *orig, *avail, *oavail = NULL, *alg, *replace = NULL; 519e9778795SPeter Avalos char **proposal; 520e9778795SPeter Avalos size_t maxlen; 521e9778795SPeter Avalos int ktype, r; 522e9778795SPeter Avalos 523e9778795SPeter Avalos /* XXX we de-serialize ssh->kex->my, modify it, and change it */ 524e9778795SPeter Avalos if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0) 525e9778795SPeter Avalos return r; 526e9778795SPeter Avalos orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; 527e9778795SPeter Avalos if ((oavail = avail = strdup(orig)) == NULL) { 528e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 529e9778795SPeter Avalos goto out; 530e9778795SPeter Avalos } 531e9778795SPeter Avalos maxlen = strlen(avail) + 1; 532e9778795SPeter Avalos if ((replace = calloc(1, maxlen)) == NULL) { 533e9778795SPeter Avalos r = SSH_ERR_ALLOC_FAIL; 534e9778795SPeter Avalos goto out; 535e9778795SPeter Avalos } 536e9778795SPeter Avalos *replace = '\0'; 537e9778795SPeter Avalos while ((alg = strsep(&avail, ",")) && *alg != '\0') { 538e9778795SPeter Avalos if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 539e9778795SPeter Avalos continue; 540e9778795SPeter Avalos TAILQ_FOREACH(k, &ssh->public_keys, next) { 541e9778795SPeter Avalos if (k->key->type == ktype || 542e9778795SPeter Avalos (sshkey_is_cert(k->key) && k->key->type == 543e9778795SPeter Avalos sshkey_type_plain(ktype))) { 544e9778795SPeter Avalos if (*replace != '\0') 545e9778795SPeter Avalos strlcat(replace, ",", maxlen); 546e9778795SPeter Avalos strlcat(replace, alg, maxlen); 547e9778795SPeter Avalos break; 548e9778795SPeter Avalos } 549e9778795SPeter Avalos } 550e9778795SPeter Avalos } 551e9778795SPeter Avalos if (*replace != '\0') { 552e9778795SPeter Avalos debug2("%s: orig/%d %s", __func__, ssh->kex->server, orig); 553e9778795SPeter Avalos debug2("%s: replace/%d %s", __func__, ssh->kex->server, replace); 554e9778795SPeter Avalos free(orig); 555e9778795SPeter Avalos proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace; 556e9778795SPeter Avalos replace = NULL; /* owned by proposal */ 557e9778795SPeter Avalos r = kex_prop2buf(ssh->kex->my, proposal); 558e9778795SPeter Avalos } 559e9778795SPeter Avalos out: 560e9778795SPeter Avalos free(oavail); 561e9778795SPeter Avalos free(replace); 562e9778795SPeter Avalos kex_prop_free(proposal); 563e9778795SPeter Avalos return r; 564e9778795SPeter Avalos } 565e9778795SPeter Avalos 566e9778795SPeter Avalos int 567664f4763Szrj _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey, 568664f4763Szrj struct sshkey *pubkey, u_char **signature, size_t *slen, 569664f4763Szrj const u_char *data, size_t dlen, const char *alg) 570e9778795SPeter Avalos { 571664f4763Szrj return sshkey_sign(privkey, signature, slen, data, dlen, 572*0cbfa66cSDaniel Fojt alg, NULL, ssh->compat); 573e9778795SPeter Avalos } 574