1*1f96526fSdjm /* $OpenBSD: ssh_api.c,v 1.17 2019/09/06 05:23:55 djm Exp $ */ 2d9c3c4c1Smarkus /* 3d9c3c4c1Smarkus * Copyright (c) 2012 Markus Friedl. All rights reserved. 4d9c3c4c1Smarkus * 5d9c3c4c1Smarkus * Permission to use, copy, modify, and distribute this software for any 6d9c3c4c1Smarkus * purpose with or without fee is hereby granted, provided that the above 7d9c3c4c1Smarkus * copyright notice and this permission notice appear in all copies. 8d9c3c4c1Smarkus * 9d9c3c4c1Smarkus * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10d9c3c4c1Smarkus * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11d9c3c4c1Smarkus * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12d9c3c4c1Smarkus * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13d9c3c4c1Smarkus * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14d9c3c4c1Smarkus * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15d9c3c4c1Smarkus * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16d9c3c4c1Smarkus */ 17d9c3c4c1Smarkus 18d04a6061Sdjm #include <sys/types.h> 19d04a6061Sdjm 20d04a6061Sdjm #include <stdio.h> 21d04a6061Sdjm #include <stdlib.h> 22d04a6061Sdjm 23d9c3c4c1Smarkus #include "ssh_api.h" 24d9c3c4c1Smarkus #include "compat.h" 25d9c3c4c1Smarkus #include "log.h" 26d9c3c4c1Smarkus #include "authfile.h" 27d9c3c4c1Smarkus #include "sshkey.h" 28d9c3c4c1Smarkus #include "misc.h" 29d9c3c4c1Smarkus #include "ssh2.h" 30d9c3c4c1Smarkus #include "version.h" 31d9c3c4c1Smarkus #include "myproposal.h" 32d9c3c4c1Smarkus #include "ssherr.h" 33d9c3c4c1Smarkus #include "sshbuf.h" 34d9c3c4c1Smarkus 35d9c3c4c1Smarkus #include <string.h> 36d9c3c4c1Smarkus 37d9c3c4c1Smarkus int _ssh_exchange_banner(struct ssh *); 3801cfcf25Sdjm int _ssh_send_banner(struct ssh *, struct sshbuf *); 3901cfcf25Sdjm int _ssh_read_banner(struct ssh *, struct sshbuf *); 40d9c3c4c1Smarkus int _ssh_order_hostkeyalgs(struct ssh *); 41d9c3c4c1Smarkus int _ssh_verify_host_key(struct sshkey *, struct ssh *); 423482e068Sdjm struct sshkey *_ssh_host_public_key(int, int, struct ssh *); 433482e068Sdjm struct sshkey *_ssh_host_private_key(int, int, struct ssh *); 448d3ff63dSdjm int _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *, 458d3ff63dSdjm u_char **, size_t *, const u_char *, size_t, const char *); 46d9c3c4c1Smarkus 47d9c3c4c1Smarkus /* 48d9c3c4c1Smarkus * stubs for the server side implementation of kex. 49d9c3c4c1Smarkus * disable privsep so our stubs will never be called. 50d9c3c4c1Smarkus */ 51d9c3c4c1Smarkus int use_privsep = 0; 52d9c3c4c1Smarkus int mm_sshkey_sign(struct sshkey *, u_char **, u_int *, 53321f30e3Smarkus u_char *, u_int, char *, u_int); 54*1f96526fSdjm 55*1f96526fSdjm #ifdef WITH_OPENSSL 56d9c3c4c1Smarkus DH *mm_choose_dh(int, int, int); 57*1f96526fSdjm #endif 58d9c3c4c1Smarkus 59d9c3c4c1Smarkus /* Define these two variables here so that they are part of the library */ 60d9c3c4c1Smarkus u_char *session_id2 = NULL; 61d9c3c4c1Smarkus u_int session_id2_len = 0; 62d9c3c4c1Smarkus 63d9c3c4c1Smarkus int 64d9c3c4c1Smarkus mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp, 65321f30e3Smarkus u_char *data, u_int datalen, char *alg, u_int compat) 66d9c3c4c1Smarkus { 67d9c3c4c1Smarkus return (-1); 68d9c3c4c1Smarkus } 69d9c3c4c1Smarkus 70*1f96526fSdjm #ifdef WITH_OPENSSL 71d9c3c4c1Smarkus DH * 72d9c3c4c1Smarkus mm_choose_dh(int min, int nbits, int max) 73d9c3c4c1Smarkus { 74d9c3c4c1Smarkus return (NULL); 75d9c3c4c1Smarkus } 76*1f96526fSdjm #endif 77d9c3c4c1Smarkus 78d9c3c4c1Smarkus /* API */ 79d9c3c4c1Smarkus 80d9c3c4c1Smarkus int 81d9c3c4c1Smarkus ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) 82d9c3c4c1Smarkus { 83d9c3c4c1Smarkus char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 84d9c3c4c1Smarkus struct ssh *ssh; 85d9c3c4c1Smarkus char **proposal; 86d9c3c4c1Smarkus static int called; 87d9c3c4c1Smarkus int r; 88d9c3c4c1Smarkus 89d9c3c4c1Smarkus if (!called) { 90*1f96526fSdjm #ifdef WITH_OPENSSL 91d9c3c4c1Smarkus OpenSSL_add_all_algorithms(); 92*1f96526fSdjm #endif 93d9c3c4c1Smarkus called = 1; 94d9c3c4c1Smarkus } 95d9c3c4c1Smarkus 967b0d3b43Sdjm if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL) 977b0d3b43Sdjm return SSH_ERR_ALLOC_FAIL; 98d9c3c4c1Smarkus if (is_server) 99d9c3c4c1Smarkus ssh_packet_set_server(ssh); 100d9c3c4c1Smarkus 101d9c3c4c1Smarkus /* Initialize key exchange */ 102d9c3c4c1Smarkus proposal = kex_params ? kex_params->proposal : myproposal; 10301cfcf25Sdjm if ((r = kex_ready(ssh, proposal)) != 0) { 104d9c3c4c1Smarkus ssh_free(ssh); 105d9c3c4c1Smarkus return r; 106d9c3c4c1Smarkus } 107d9c3c4c1Smarkus ssh->kex->server = is_server; 108d9c3c4c1Smarkus if (is_server) { 109d9c3c4c1Smarkus #ifdef WITH_OPENSSL 11039957e0dSdjm ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; 11139957e0dSdjm ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; 11239957e0dSdjm ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; 11339957e0dSdjm ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; 11439957e0dSdjm ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; 115d9c3c4c1Smarkus ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 116d9c3c4c1Smarkus ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 11739957e0dSdjm ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server; 118d9c3c4c1Smarkus #endif /* WITH_OPENSSL */ 11939957e0dSdjm ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; 12039957e0dSdjm ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server; 121d9c3c4c1Smarkus ssh->kex->load_host_public_key=&_ssh_host_public_key; 122d9c3c4c1Smarkus ssh->kex->load_host_private_key=&_ssh_host_private_key; 123d9c3c4c1Smarkus ssh->kex->sign=&_ssh_host_key_sign; 124d9c3c4c1Smarkus } else { 125d9c3c4c1Smarkus #ifdef WITH_OPENSSL 12639957e0dSdjm ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client; 12739957e0dSdjm ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client; 12839957e0dSdjm ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client; 12939957e0dSdjm ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client; 13039957e0dSdjm ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client; 131d9c3c4c1Smarkus ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 132d9c3c4c1Smarkus ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 13339957e0dSdjm ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; 134d9c3c4c1Smarkus #endif /* WITH_OPENSSL */ 13539957e0dSdjm ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; 13639957e0dSdjm ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; 137d9c3c4c1Smarkus ssh->kex->verify_host_key =&_ssh_verify_host_key; 138d9c3c4c1Smarkus } 139d9c3c4c1Smarkus *sshp = ssh; 140d9c3c4c1Smarkus return 0; 141d9c3c4c1Smarkus } 142d9c3c4c1Smarkus 143d9c3c4c1Smarkus void 144d9c3c4c1Smarkus ssh_free(struct ssh *ssh) 145d9c3c4c1Smarkus { 146d9c3c4c1Smarkus struct key_entry *k; 147d9c3c4c1Smarkus 148d9c3c4c1Smarkus ssh_packet_close(ssh); 149d9c3c4c1Smarkus /* 150d9c3c4c1Smarkus * we've only created the public keys variants in case we 151d9c3c4c1Smarkus * are a acting as a server. 152d9c3c4c1Smarkus */ 153d9c3c4c1Smarkus while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) { 154d9c3c4c1Smarkus TAILQ_REMOVE(&ssh->public_keys, k, next); 155d9c3c4c1Smarkus if (ssh->kex && ssh->kex->server) 156d9c3c4c1Smarkus sshkey_free(k->key); 157d9c3c4c1Smarkus free(k); 158d9c3c4c1Smarkus } 159d9c3c4c1Smarkus while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) { 160d9c3c4c1Smarkus TAILQ_REMOVE(&ssh->private_keys, k, next); 161d9c3c4c1Smarkus free(k); 162d9c3c4c1Smarkus } 163d9c3c4c1Smarkus if (ssh->kex) 164d9c3c4c1Smarkus kex_free(ssh->kex); 165d9c3c4c1Smarkus free(ssh); 166d9c3c4c1Smarkus } 167d9c3c4c1Smarkus 168d9c3c4c1Smarkus void 169d9c3c4c1Smarkus ssh_set_app_data(struct ssh *ssh, void *app_data) 170d9c3c4c1Smarkus { 171d9c3c4c1Smarkus ssh->app_data = app_data; 172d9c3c4c1Smarkus } 173d9c3c4c1Smarkus 174d9c3c4c1Smarkus void * 175d9c3c4c1Smarkus ssh_get_app_data(struct ssh *ssh) 176d9c3c4c1Smarkus { 177d9c3c4c1Smarkus return ssh->app_data; 178d9c3c4c1Smarkus } 179d9c3c4c1Smarkus 180d9c3c4c1Smarkus /* Returns < 0 on error, 0 otherwise */ 181d9c3c4c1Smarkus int 182d9c3c4c1Smarkus ssh_add_hostkey(struct ssh *ssh, struct sshkey *key) 183d9c3c4c1Smarkus { 184d9c3c4c1Smarkus struct sshkey *pubkey = NULL; 185d9c3c4c1Smarkus struct key_entry *k = NULL, *k_prv = NULL; 186d9c3c4c1Smarkus int r; 187d9c3c4c1Smarkus 188d9c3c4c1Smarkus if (ssh->kex->server) { 189d9c3c4c1Smarkus if ((r = sshkey_from_private(key, &pubkey)) != 0) 190d9c3c4c1Smarkus return r; 191d9c3c4c1Smarkus if ((k = malloc(sizeof(*k))) == NULL || 192d9c3c4c1Smarkus (k_prv = malloc(sizeof(*k_prv))) == NULL) { 193d9c3c4c1Smarkus free(k); 194d9c3c4c1Smarkus sshkey_free(pubkey); 195d9c3c4c1Smarkus return SSH_ERR_ALLOC_FAIL; 196d9c3c4c1Smarkus } 197d9c3c4c1Smarkus k_prv->key = key; 198d9c3c4c1Smarkus TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next); 199d9c3c4c1Smarkus 200d9c3c4c1Smarkus /* add the public key, too */ 201d9c3c4c1Smarkus k->key = pubkey; 202d9c3c4c1Smarkus TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 203d9c3c4c1Smarkus r = 0; 204d9c3c4c1Smarkus } else { 205d9c3c4c1Smarkus if ((k = malloc(sizeof(*k))) == NULL) 206d9c3c4c1Smarkus return SSH_ERR_ALLOC_FAIL; 207d9c3c4c1Smarkus k->key = key; 208d9c3c4c1Smarkus TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 209d9c3c4c1Smarkus r = 0; 210d9c3c4c1Smarkus } 211d9c3c4c1Smarkus 212d9c3c4c1Smarkus return r; 213d9c3c4c1Smarkus } 214d9c3c4c1Smarkus 215d9c3c4c1Smarkus int 216d9c3c4c1Smarkus ssh_set_verify_host_key_callback(struct ssh *ssh, 217d9c3c4c1Smarkus int (*cb)(struct sshkey *, struct ssh *)) 218d9c3c4c1Smarkus { 219d9c3c4c1Smarkus if (cb == NULL || ssh->kex == NULL) 220d9c3c4c1Smarkus return SSH_ERR_INVALID_ARGUMENT; 221d9c3c4c1Smarkus 222d9c3c4c1Smarkus ssh->kex->verify_host_key = cb; 223d9c3c4c1Smarkus 224d9c3c4c1Smarkus return 0; 225d9c3c4c1Smarkus } 226d9c3c4c1Smarkus 227d9c3c4c1Smarkus int 228d9c3c4c1Smarkus ssh_input_append(struct ssh *ssh, const u_char *data, size_t len) 229d9c3c4c1Smarkus { 230d9c3c4c1Smarkus return sshbuf_put(ssh_packet_get_input(ssh), data, len); 231d9c3c4c1Smarkus } 232d9c3c4c1Smarkus 233d9c3c4c1Smarkus int 234d9c3c4c1Smarkus ssh_packet_next(struct ssh *ssh, u_char *typep) 235d9c3c4c1Smarkus { 236d9c3c4c1Smarkus int r; 237d9c3c4c1Smarkus u_int32_t seqnr; 238d9c3c4c1Smarkus u_char type; 239d9c3c4c1Smarkus 240d9c3c4c1Smarkus /* 241d9c3c4c1Smarkus * Try to read a packet. Return SSH_MSG_NONE if no packet or not 242d9c3c4c1Smarkus * enough data. 243d9c3c4c1Smarkus */ 244d9c3c4c1Smarkus *typep = SSH_MSG_NONE; 24501cfcf25Sdjm if (sshbuf_len(ssh->kex->client_version) == 0 || 24601cfcf25Sdjm sshbuf_len(ssh->kex->server_version) == 0) 247d9c3c4c1Smarkus return _ssh_exchange_banner(ssh); 248d9c3c4c1Smarkus /* 249d9c3c4c1Smarkus * If we enough data and a dispatch function then 250d9c3c4c1Smarkus * call the function and get the next packet. 251d9c3c4c1Smarkus * Otherwise return the packet type to the caller so it 252d9c3c4c1Smarkus * can decide how to go on. 253d9c3c4c1Smarkus * 254d9c3c4c1Smarkus * We will only call the dispatch function for: 255d9c3c4c1Smarkus * 20-29 Algorithm negotiation 256d9c3c4c1Smarkus * 30-49 Key exchange method specific (numbers can be reused for 257d9c3c4c1Smarkus * different authentication methods) 258d9c3c4c1Smarkus */ 259d9c3c4c1Smarkus for (;;) { 260d9c3c4c1Smarkus if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0) 261d9c3c4c1Smarkus return r; 262d9c3c4c1Smarkus if (type > 0 && type < DISPATCH_MAX && 263d9c3c4c1Smarkus type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX && 264d9c3c4c1Smarkus ssh->dispatch[type] != NULL) { 265d9c3c4c1Smarkus if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0) 266d9c3c4c1Smarkus return r; 267d9c3c4c1Smarkus } else { 268d9c3c4c1Smarkus *typep = type; 269d9c3c4c1Smarkus return 0; 270d9c3c4c1Smarkus } 271d9c3c4c1Smarkus } 272d9c3c4c1Smarkus } 273d9c3c4c1Smarkus 274d9c3c4c1Smarkus const u_char * 275d9c3c4c1Smarkus ssh_packet_payload(struct ssh *ssh, size_t *lenp) 276d9c3c4c1Smarkus { 277d9c3c4c1Smarkus return sshpkt_ptr(ssh, lenp); 278d9c3c4c1Smarkus } 279d9c3c4c1Smarkus 280d9c3c4c1Smarkus int 281d9c3c4c1Smarkus ssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len) 282d9c3c4c1Smarkus { 283d9c3c4c1Smarkus int r; 284d9c3c4c1Smarkus 285d9c3c4c1Smarkus if ((r = sshpkt_start(ssh, type)) != 0 || 286d9c3c4c1Smarkus (r = sshpkt_put(ssh, data, len)) != 0 || 287d9c3c4c1Smarkus (r = sshpkt_send(ssh)) != 0) 288d9c3c4c1Smarkus return r; 289d9c3c4c1Smarkus return 0; 290d9c3c4c1Smarkus } 291d9c3c4c1Smarkus 292d9c3c4c1Smarkus const u_char * 293d9c3c4c1Smarkus ssh_output_ptr(struct ssh *ssh, size_t *len) 294d9c3c4c1Smarkus { 295d9c3c4c1Smarkus struct sshbuf *output = ssh_packet_get_output(ssh); 296d9c3c4c1Smarkus 297d9c3c4c1Smarkus *len = sshbuf_len(output); 298d9c3c4c1Smarkus return sshbuf_ptr(output); 299d9c3c4c1Smarkus } 300d9c3c4c1Smarkus 301d9c3c4c1Smarkus int 302d9c3c4c1Smarkus ssh_output_consume(struct ssh *ssh, size_t len) 303d9c3c4c1Smarkus { 304d9c3c4c1Smarkus return sshbuf_consume(ssh_packet_get_output(ssh), len); 305d9c3c4c1Smarkus } 306d9c3c4c1Smarkus 307d9c3c4c1Smarkus int 308d9c3c4c1Smarkus ssh_output_space(struct ssh *ssh, size_t len) 309d9c3c4c1Smarkus { 310d9c3c4c1Smarkus return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len)); 311d9c3c4c1Smarkus } 312d9c3c4c1Smarkus 313d9c3c4c1Smarkus int 314d9c3c4c1Smarkus ssh_input_space(struct ssh *ssh, size_t len) 315d9c3c4c1Smarkus { 316d9c3c4c1Smarkus return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len)); 317d9c3c4c1Smarkus } 318d9c3c4c1Smarkus 319d9c3c4c1Smarkus /* Read other side's version identification. */ 320d9c3c4c1Smarkus int 32101cfcf25Sdjm _ssh_read_banner(struct ssh *ssh, struct sshbuf *banner) 322d9c3c4c1Smarkus { 32301cfcf25Sdjm struct sshbuf *input = ssh_packet_get_input(ssh); 324d9c3c4c1Smarkus const char *mismatch = "Protocol mismatch.\r\n"; 32501cfcf25Sdjm const u_char *s = sshbuf_ptr(input); 32601cfcf25Sdjm u_char c; 32701cfcf25Sdjm char *cp, *remote_version; 32801cfcf25Sdjm int r, remote_major, remote_minor, expect_nl; 32901cfcf25Sdjm size_t n, j; 330d9c3c4c1Smarkus 331d9c3c4c1Smarkus for (j = n = 0;;) { 33201cfcf25Sdjm sshbuf_reset(banner); 33301cfcf25Sdjm expect_nl = 0; 33401cfcf25Sdjm for (;;) { 33501cfcf25Sdjm if (j >= sshbuf_len(input)) 33601cfcf25Sdjm return 0; /* insufficient data in input buf */ 33701cfcf25Sdjm c = s[j++]; 33801cfcf25Sdjm if (c == '\r') { 33901cfcf25Sdjm expect_nl = 1; 34001cfcf25Sdjm continue; 341d9c3c4c1Smarkus } 34201cfcf25Sdjm if (c == '\n') 343d9c3c4c1Smarkus break; 34401cfcf25Sdjm if (expect_nl) 34501cfcf25Sdjm goto bad; 34601cfcf25Sdjm if ((r = sshbuf_put_u8(banner, c)) != 0) 34701cfcf25Sdjm return r; 34801cfcf25Sdjm if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN) 34901cfcf25Sdjm goto bad; 350d9c3c4c1Smarkus } 35101cfcf25Sdjm if (sshbuf_len(banner) >= 4 && 35201cfcf25Sdjm memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0) 353d9c3c4c1Smarkus break; 35401cfcf25Sdjm if ((cp = sshbuf_dup_string(banner)) == NULL) 35501cfcf25Sdjm return SSH_ERR_ALLOC_FAIL; 35601cfcf25Sdjm debug("%s: %s", __func__, cp); 35701cfcf25Sdjm free(cp); 35801cfcf25Sdjm /* Accept lines before banner only on client */ 35901cfcf25Sdjm if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) { 36001cfcf25Sdjm bad: 361d9c3c4c1Smarkus if ((r = sshbuf_put(ssh_packet_get_output(ssh), 362d9c3c4c1Smarkus mismatch, strlen(mismatch))) != 0) 363d9c3c4c1Smarkus return r; 364d9c3c4c1Smarkus return SSH_ERR_NO_PROTOCOL_VERSION; 365d9c3c4c1Smarkus } 366d9c3c4c1Smarkus } 367d9c3c4c1Smarkus if ((r = sshbuf_consume(input, j)) != 0) 368d9c3c4c1Smarkus return r; 369d9c3c4c1Smarkus 37001cfcf25Sdjm if ((cp = sshbuf_dup_string(banner)) == NULL) 37101cfcf25Sdjm return SSH_ERR_ALLOC_FAIL; 37201cfcf25Sdjm /* XXX remote version must be the same size as banner for sscanf */ 37301cfcf25Sdjm if ((remote_version = calloc(1, sshbuf_len(banner))) == NULL) 37401cfcf25Sdjm return SSH_ERR_ALLOC_FAIL; 37501cfcf25Sdjm 376d9c3c4c1Smarkus /* 377d9c3c4c1Smarkus * Check that the versions match. In future this might accept 378d9c3c4c1Smarkus * several versions and set appropriate flags to handle them. 379d9c3c4c1Smarkus */ 38001cfcf25Sdjm if (sscanf(cp, "SSH-%d.%d-%[^\n]\n", 381d9c3c4c1Smarkus &remote_major, &remote_minor, remote_version) != 3) 382d9c3c4c1Smarkus return SSH_ERR_INVALID_FORMAT; 383d9c3c4c1Smarkus debug("Remote protocol version %d.%d, remote software version %.100s", 384d9c3c4c1Smarkus remote_major, remote_minor, remote_version); 385d9c3c4c1Smarkus 386d9c3c4c1Smarkus ssh->compat = compat_datafellows(remote_version); 387d9c3c4c1Smarkus if (remote_major == 1 && remote_minor == 99) { 388d9c3c4c1Smarkus remote_major = 2; 389d9c3c4c1Smarkus remote_minor = 0; 390d9c3c4c1Smarkus } 391d9c3c4c1Smarkus if (remote_major != 2) 392d9c3c4c1Smarkus return SSH_ERR_PROTOCOL_MISMATCH; 39301cfcf25Sdjm debug("Remote version string %.100s", cp); 39401cfcf25Sdjm free(cp); 395d9c3c4c1Smarkus return 0; 396d9c3c4c1Smarkus } 397d9c3c4c1Smarkus 398d9c3c4c1Smarkus /* Send our own protocol version identification. */ 399d9c3c4c1Smarkus int 40001cfcf25Sdjm _ssh_send_banner(struct ssh *ssh, struct sshbuf *banner) 401d9c3c4c1Smarkus { 40201cfcf25Sdjm char *cp; 403d9c3c4c1Smarkus int r; 404d9c3c4c1Smarkus 40501cfcf25Sdjm if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0) 406d9c3c4c1Smarkus return r; 40701cfcf25Sdjm if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) 40801cfcf25Sdjm return r; 40901cfcf25Sdjm /* Remove trailing \r\n */ 41001cfcf25Sdjm if ((r = sshbuf_consume_end(banner, 2)) != 0) 41101cfcf25Sdjm return r; 41201cfcf25Sdjm if ((cp = sshbuf_dup_string(banner)) == NULL) 413d9c3c4c1Smarkus return SSH_ERR_ALLOC_FAIL; 41401cfcf25Sdjm debug("Local version string %.100s", cp); 41501cfcf25Sdjm free(cp); 416d9c3c4c1Smarkus return 0; 417d9c3c4c1Smarkus } 418d9c3c4c1Smarkus 419d9c3c4c1Smarkus int 420d9c3c4c1Smarkus _ssh_exchange_banner(struct ssh *ssh) 421d9c3c4c1Smarkus { 422d9c3c4c1Smarkus struct kex *kex = ssh->kex; 423d9c3c4c1Smarkus int r; 424d9c3c4c1Smarkus 425d9c3c4c1Smarkus /* 426d9c3c4c1Smarkus * if _ssh_read_banner() cannot parse a full version string 427d9c3c4c1Smarkus * it will return NULL and we end up calling it again. 428d9c3c4c1Smarkus */ 429d9c3c4c1Smarkus 430d9c3c4c1Smarkus r = 0; 431d9c3c4c1Smarkus if (kex->server) { 43201cfcf25Sdjm if (sshbuf_len(ssh->kex->server_version) == 0) 43301cfcf25Sdjm r = _ssh_send_banner(ssh, ssh->kex->server_version); 434d9c3c4c1Smarkus if (r == 0 && 43501cfcf25Sdjm sshbuf_len(ssh->kex->server_version) != 0 && 43601cfcf25Sdjm sshbuf_len(ssh->kex->client_version) == 0) 43701cfcf25Sdjm r = _ssh_read_banner(ssh, ssh->kex->client_version); 438d9c3c4c1Smarkus } else { 43901cfcf25Sdjm if (sshbuf_len(ssh->kex->server_version) == 0) 44001cfcf25Sdjm r = _ssh_read_banner(ssh, ssh->kex->server_version); 441d9c3c4c1Smarkus if (r == 0 && 44201cfcf25Sdjm sshbuf_len(ssh->kex->server_version) != 0 && 44301cfcf25Sdjm sshbuf_len(ssh->kex->client_version) == 0) 44401cfcf25Sdjm r = _ssh_send_banner(ssh, ssh->kex->client_version); 445d9c3c4c1Smarkus } 446d9c3c4c1Smarkus if (r != 0) 447d9c3c4c1Smarkus return r; 448d9c3c4c1Smarkus /* start initial kex as soon as we have exchanged the banners */ 44901cfcf25Sdjm if (sshbuf_len(ssh->kex->server_version) != 0 && 45001cfcf25Sdjm sshbuf_len(ssh->kex->client_version) != 0) { 451d9c3c4c1Smarkus if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 || 452d9c3c4c1Smarkus (r = kex_send_kexinit(ssh)) != 0) 453d9c3c4c1Smarkus return r; 454d9c3c4c1Smarkus } 455d9c3c4c1Smarkus return 0; 456d9c3c4c1Smarkus } 457d9c3c4c1Smarkus 458d9c3c4c1Smarkus struct sshkey * 4593482e068Sdjm _ssh_host_public_key(int type, int nid, struct ssh *ssh) 460d9c3c4c1Smarkus { 461d9c3c4c1Smarkus struct key_entry *k; 462d9c3c4c1Smarkus 463d9c3c4c1Smarkus debug3("%s: need %d", __func__, type); 464d9c3c4c1Smarkus TAILQ_FOREACH(k, &ssh->public_keys, next) { 465d9c3c4c1Smarkus debug3("%s: check %s", __func__, sshkey_type(k->key)); 4663482e068Sdjm if (k->key->type == type && 4673482e068Sdjm (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 468d9c3c4c1Smarkus return (k->key); 469d9c3c4c1Smarkus } 470d9c3c4c1Smarkus return (NULL); 471d9c3c4c1Smarkus } 472d9c3c4c1Smarkus 473d9c3c4c1Smarkus struct sshkey * 4743482e068Sdjm _ssh_host_private_key(int type, int nid, struct ssh *ssh) 475d9c3c4c1Smarkus { 476d9c3c4c1Smarkus struct key_entry *k; 477d9c3c4c1Smarkus 478d9c3c4c1Smarkus debug3("%s: need %d", __func__, type); 479d9c3c4c1Smarkus TAILQ_FOREACH(k, &ssh->private_keys, next) { 480d9c3c4c1Smarkus debug3("%s: check %s", __func__, sshkey_type(k->key)); 4813482e068Sdjm if (k->key->type == type && 4823482e068Sdjm (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 483d9c3c4c1Smarkus return (k->key); 484d9c3c4c1Smarkus } 485d9c3c4c1Smarkus return (NULL); 486d9c3c4c1Smarkus } 487d9c3c4c1Smarkus 488d9c3c4c1Smarkus int 489d9c3c4c1Smarkus _ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh) 490d9c3c4c1Smarkus { 491d9c3c4c1Smarkus struct key_entry *k; 492d9c3c4c1Smarkus 493d9c3c4c1Smarkus debug3("%s: need %s", __func__, sshkey_type(hostkey)); 494d9c3c4c1Smarkus TAILQ_FOREACH(k, &ssh->public_keys, next) { 495d9c3c4c1Smarkus debug3("%s: check %s", __func__, sshkey_type(k->key)); 496d9c3c4c1Smarkus if (sshkey_equal_public(hostkey, k->key)) 497d9c3c4c1Smarkus return (0); /* ok */ 498d9c3c4c1Smarkus } 499d9c3c4c1Smarkus return (-1); /* failed */ 500d9c3c4c1Smarkus } 501d9c3c4c1Smarkus 502d9c3c4c1Smarkus /* offer hostkey algorithms in kexinit depending on registered keys */ 503d9c3c4c1Smarkus int 504d9c3c4c1Smarkus _ssh_order_hostkeyalgs(struct ssh *ssh) 505d9c3c4c1Smarkus { 506d9c3c4c1Smarkus struct key_entry *k; 507d9c3c4c1Smarkus char *orig, *avail, *oavail = NULL, *alg, *replace = NULL; 508d9c3c4c1Smarkus char **proposal; 509d9c3c4c1Smarkus size_t maxlen; 510d9c3c4c1Smarkus int ktype, r; 511d9c3c4c1Smarkus 512d9c3c4c1Smarkus /* XXX we de-serialize ssh->kex->my, modify it, and change it */ 513d9c3c4c1Smarkus if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0) 514d9c3c4c1Smarkus return r; 515d9c3c4c1Smarkus orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; 516d9c3c4c1Smarkus if ((oavail = avail = strdup(orig)) == NULL) { 517d9c3c4c1Smarkus r = SSH_ERR_ALLOC_FAIL; 518d9c3c4c1Smarkus goto out; 519d9c3c4c1Smarkus } 520d9c3c4c1Smarkus maxlen = strlen(avail) + 1; 521d9c3c4c1Smarkus if ((replace = calloc(1, maxlen)) == NULL) { 522d9c3c4c1Smarkus r = SSH_ERR_ALLOC_FAIL; 523d9c3c4c1Smarkus goto out; 524d9c3c4c1Smarkus } 525d9c3c4c1Smarkus *replace = '\0'; 526d9c3c4c1Smarkus while ((alg = strsep(&avail, ",")) && *alg != '\0') { 527d9c3c4c1Smarkus if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 528d9c3c4c1Smarkus continue; 529d9c3c4c1Smarkus TAILQ_FOREACH(k, &ssh->public_keys, next) { 530d9c3c4c1Smarkus if (k->key->type == ktype || 531d9c3c4c1Smarkus (sshkey_is_cert(k->key) && k->key->type == 532d9c3c4c1Smarkus sshkey_type_plain(ktype))) { 533d9c3c4c1Smarkus if (*replace != '\0') 534d9c3c4c1Smarkus strlcat(replace, ",", maxlen); 535d9c3c4c1Smarkus strlcat(replace, alg, maxlen); 536d9c3c4c1Smarkus break; 537d9c3c4c1Smarkus } 538d9c3c4c1Smarkus } 539d9c3c4c1Smarkus } 540d9c3c4c1Smarkus if (*replace != '\0') { 541d9c3c4c1Smarkus debug2("%s: orig/%d %s", __func__, ssh->kex->server, orig); 542d9c3c4c1Smarkus debug2("%s: replace/%d %s", __func__, ssh->kex->server, replace); 543d9c3c4c1Smarkus free(orig); 544d9c3c4c1Smarkus proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace; 545d9c3c4c1Smarkus replace = NULL; /* owned by proposal */ 546d9c3c4c1Smarkus r = kex_prop2buf(ssh->kex->my, proposal); 547d9c3c4c1Smarkus } 548d9c3c4c1Smarkus out: 549d9c3c4c1Smarkus free(oavail); 550d9c3c4c1Smarkus free(replace); 551d9c3c4c1Smarkus kex_prop_free(proposal); 552d9c3c4c1Smarkus return r; 553d9c3c4c1Smarkus } 554d9c3c4c1Smarkus 555d9c3c4c1Smarkus int 5568d3ff63dSdjm _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey, 5578d3ff63dSdjm struct sshkey *pubkey, u_char **signature, size_t *slen, 5588d3ff63dSdjm const u_char *data, size_t dlen, const char *alg) 559d9c3c4c1Smarkus { 5608d3ff63dSdjm return sshkey_sign(privkey, signature, slen, data, dlen, 5618d3ff63dSdjm alg, ssh->compat); 562d9c3c4c1Smarkus } 563