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