1323124Sdes/* $OpenBSD: ssh_api.c,v 1.7 2016/05/04 14:22:33 markus Exp $ */ 2285031Sdes/* 3285031Sdes * Copyright (c) 2012 Markus Friedl. All rights reserved. 4285031Sdes * 5285031Sdes * Permission to use, copy, modify, and distribute this software for any 6285031Sdes * purpose with or without fee is hereby granted, provided that the above 7285031Sdes * copyright notice and this permission notice appear in all copies. 8285031Sdes * 9285031Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10285031Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11285031Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12285031Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13285031Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14285031Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15285031Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16285031Sdes */ 17285031Sdes 18285031Sdes#include "includes.h" 19285031Sdes 20285031Sdes#include "ssh_api.h" 21285031Sdes#include "compat.h" 22285031Sdes#include "log.h" 23285031Sdes#include "authfile.h" 24285031Sdes#include "sshkey.h" 25285031Sdes#include "misc.h" 26285031Sdes#include "ssh2.h" 27285031Sdes#include "version.h" 28285031Sdes#include "myproposal.h" 29285031Sdes#include "ssherr.h" 30285031Sdes#include "sshbuf.h" 31285031Sdes 32285031Sdes#include <string.h> 33285031Sdes 34285031Sdesint _ssh_exchange_banner(struct ssh *); 35285031Sdesint _ssh_send_banner(struct ssh *, char **); 36285031Sdesint _ssh_read_banner(struct ssh *, char **); 37285031Sdesint _ssh_order_hostkeyalgs(struct ssh *); 38285031Sdesint _ssh_verify_host_key(struct sshkey *, struct ssh *); 39285031Sdesstruct sshkey *_ssh_host_public_key(int, int, struct ssh *); 40285031Sdesstruct sshkey *_ssh_host_private_key(int, int, struct ssh *); 41296781Sdesint _ssh_host_key_sign(struct sshkey *, struct sshkey *, 42296781Sdes u_char **, size_t *, const u_char *, size_t, const char *, u_int); 43285031Sdes 44285031Sdes/* 45285031Sdes * stubs for the server side implementation of kex. 46285031Sdes * disable privsep so our stubs will never be called. 47285031Sdes */ 48285031Sdesint use_privsep = 0; 49285031Sdesint mm_sshkey_sign(struct sshkey *, u_char **, u_int *, 50296781Sdes u_char *, u_int, char *, u_int); 51285031SdesDH *mm_choose_dh(int, int, int); 52285031Sdes 53285031Sdes/* Define these two variables here so that they are part of the library */ 54285031Sdesu_char *session_id2 = NULL; 55285031Sdesu_int session_id2_len = 0; 56285031Sdes 57285031Sdesint 58285031Sdesmm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp, 59296781Sdes u_char *data, u_int datalen, char *alg, u_int compat) 60285031Sdes{ 61285031Sdes return (-1); 62285031Sdes} 63285031Sdes 64285031SdesDH * 65285031Sdesmm_choose_dh(int min, int nbits, int max) 66285031Sdes{ 67285031Sdes return (NULL); 68285031Sdes} 69285031Sdes 70285031Sdes/* API */ 71285031Sdes 72285031Sdesint 73285031Sdesssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) 74285031Sdes{ 75285031Sdes char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; 76285031Sdes struct ssh *ssh; 77285031Sdes char **proposal; 78285031Sdes static int called; 79285031Sdes int r; 80285031Sdes 81285031Sdes if (!called) { 82285031Sdes#ifdef WITH_OPENSSL 83285031Sdes OpenSSL_add_all_algorithms(); 84285031Sdes#endif /* WITH_OPENSSL */ 85285031Sdes called = 1; 86285031Sdes } 87285031Sdes 88285031Sdes if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL) 89285031Sdes return SSH_ERR_ALLOC_FAIL; 90285031Sdes if (is_server) 91285031Sdes ssh_packet_set_server(ssh); 92285031Sdes 93285031Sdes /* Initialize key exchange */ 94285031Sdes proposal = kex_params ? kex_params->proposal : myproposal; 95285031Sdes if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) { 96285031Sdes ssh_free(ssh); 97285031Sdes return r; 98285031Sdes } 99285031Sdes ssh->kex->server = is_server; 100285031Sdes if (is_server) { 101285031Sdes#ifdef WITH_OPENSSL 102285031Sdes ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 103285031Sdes ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 104323124Sdes ssh->kex->kex[KEX_DH_GRP14_SHA256] = kexdh_server; 105323124Sdes ssh->kex->kex[KEX_DH_GRP16_SHA512] = kexdh_server; 106323124Sdes ssh->kex->kex[KEX_DH_GRP18_SHA512] = kexdh_server; 107285031Sdes ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 108285031Sdes ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 109285031Sdes# ifdef OPENSSL_HAS_ECC 110285031Sdes ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_server; 111285031Sdes# endif 112285031Sdes#endif /* WITH_OPENSSL */ 113285031Sdes ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_server; 114285031Sdes ssh->kex->load_host_public_key=&_ssh_host_public_key; 115285031Sdes ssh->kex->load_host_private_key=&_ssh_host_private_key; 116285031Sdes ssh->kex->sign=&_ssh_host_key_sign; 117285031Sdes } else { 118285031Sdes#ifdef WITH_OPENSSL 119285031Sdes ssh->kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 120285031Sdes ssh->kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 121323124Sdes ssh->kex->kex[KEX_DH_GRP14_SHA256] = kexdh_client; 122323124Sdes ssh->kex->kex[KEX_DH_GRP16_SHA512] = kexdh_client; 123323124Sdes ssh->kex->kex[KEX_DH_GRP18_SHA512] = kexdh_client; 124285031Sdes ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 125285031Sdes ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 126285031Sdes# ifdef OPENSSL_HAS_ECC 127285031Sdes ssh->kex->kex[KEX_ECDH_SHA2] = kexecdh_client; 128285031Sdes# endif 129285031Sdes#endif /* WITH_OPENSSL */ 130285031Sdes ssh->kex->kex[KEX_C25519_SHA256] = kexc25519_client; 131285031Sdes ssh->kex->verify_host_key =&_ssh_verify_host_key; 132285031Sdes } 133285031Sdes *sshp = ssh; 134285031Sdes return 0; 135285031Sdes} 136285031Sdes 137285031Sdesvoid 138285031Sdesssh_free(struct ssh *ssh) 139285031Sdes{ 140285031Sdes struct key_entry *k; 141285031Sdes 142285031Sdes ssh_packet_close(ssh); 143285031Sdes /* 144285031Sdes * we've only created the public keys variants in case we 145285031Sdes * are a acting as a server. 146285031Sdes */ 147285031Sdes while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) { 148285031Sdes TAILQ_REMOVE(&ssh->public_keys, k, next); 149285031Sdes if (ssh->kex && ssh->kex->server) 150285031Sdes sshkey_free(k->key); 151285031Sdes free(k); 152285031Sdes } 153285031Sdes while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) { 154285031Sdes TAILQ_REMOVE(&ssh->private_keys, k, next); 155285031Sdes free(k); 156285031Sdes } 157285031Sdes if (ssh->kex) 158285031Sdes kex_free(ssh->kex); 159285031Sdes free(ssh); 160285031Sdes} 161285031Sdes 162285031Sdesvoid 163285031Sdesssh_set_app_data(struct ssh *ssh, void *app_data) 164285031Sdes{ 165285031Sdes ssh->app_data = app_data; 166285031Sdes} 167285031Sdes 168285031Sdesvoid * 169285031Sdesssh_get_app_data(struct ssh *ssh) 170285031Sdes{ 171285031Sdes return ssh->app_data; 172285031Sdes} 173285031Sdes 174285031Sdes/* Returns < 0 on error, 0 otherwise */ 175285031Sdesint 176285031Sdesssh_add_hostkey(struct ssh *ssh, struct sshkey *key) 177285031Sdes{ 178285031Sdes struct sshkey *pubkey = NULL; 179285031Sdes struct key_entry *k = NULL, *k_prv = NULL; 180285031Sdes int r; 181285031Sdes 182285031Sdes if (ssh->kex->server) { 183285031Sdes if ((r = sshkey_from_private(key, &pubkey)) != 0) 184285031Sdes return r; 185285031Sdes if ((k = malloc(sizeof(*k))) == NULL || 186285031Sdes (k_prv = malloc(sizeof(*k_prv))) == NULL) { 187285031Sdes free(k); 188285031Sdes sshkey_free(pubkey); 189285031Sdes return SSH_ERR_ALLOC_FAIL; 190285031Sdes } 191285031Sdes k_prv->key = key; 192285031Sdes TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next); 193285031Sdes 194285031Sdes /* add the public key, too */ 195285031Sdes k->key = pubkey; 196285031Sdes TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 197285031Sdes r = 0; 198285031Sdes } else { 199285031Sdes if ((k = malloc(sizeof(*k))) == NULL) 200285031Sdes return SSH_ERR_ALLOC_FAIL; 201285031Sdes k->key = key; 202285031Sdes TAILQ_INSERT_TAIL(&ssh->public_keys, k, next); 203285031Sdes r = 0; 204285031Sdes } 205285031Sdes 206285031Sdes return r; 207285031Sdes} 208285031Sdes 209285031Sdesint 210285031Sdesssh_set_verify_host_key_callback(struct ssh *ssh, 211285031Sdes int (*cb)(struct sshkey *, struct ssh *)) 212285031Sdes{ 213285031Sdes if (cb == NULL || ssh->kex == NULL) 214285031Sdes return SSH_ERR_INVALID_ARGUMENT; 215285031Sdes 216285031Sdes ssh->kex->verify_host_key = cb; 217285031Sdes 218285031Sdes return 0; 219285031Sdes} 220285031Sdes 221285031Sdesint 222285031Sdesssh_input_append(struct ssh *ssh, const u_char *data, size_t len) 223285031Sdes{ 224285031Sdes return sshbuf_put(ssh_packet_get_input(ssh), data, len); 225285031Sdes} 226285031Sdes 227285031Sdesint 228285031Sdesssh_packet_next(struct ssh *ssh, u_char *typep) 229285031Sdes{ 230285031Sdes int r; 231285031Sdes u_int32_t seqnr; 232285031Sdes u_char type; 233285031Sdes 234285031Sdes /* 235285031Sdes * Try to read a packet. Return SSH_MSG_NONE if no packet or not 236285031Sdes * enough data. 237285031Sdes */ 238285031Sdes *typep = SSH_MSG_NONE; 239285031Sdes if (ssh->kex->client_version_string == NULL || 240285031Sdes ssh->kex->server_version_string == NULL) 241285031Sdes return _ssh_exchange_banner(ssh); 242285031Sdes /* 243285031Sdes * If we enough data and a dispatch function then 244285031Sdes * call the function and get the next packet. 245285031Sdes * Otherwise return the packet type to the caller so it 246285031Sdes * can decide how to go on. 247285031Sdes * 248285031Sdes * We will only call the dispatch function for: 249285031Sdes * 20-29 Algorithm negotiation 250285031Sdes * 30-49 Key exchange method specific (numbers can be reused for 251285031Sdes * different authentication methods) 252285031Sdes */ 253285031Sdes for (;;) { 254285031Sdes if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0) 255285031Sdes return r; 256285031Sdes if (type > 0 && type < DISPATCH_MAX && 257285031Sdes type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX && 258285031Sdes ssh->dispatch[type] != NULL) { 259285031Sdes if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0) 260285031Sdes return r; 261285031Sdes } else { 262285031Sdes *typep = type; 263285031Sdes return 0; 264285031Sdes } 265285031Sdes } 266285031Sdes} 267285031Sdes 268285031Sdesconst u_char * 269285031Sdesssh_packet_payload(struct ssh *ssh, size_t *lenp) 270285031Sdes{ 271285031Sdes return sshpkt_ptr(ssh, lenp); 272285031Sdes} 273285031Sdes 274285031Sdesint 275285031Sdesssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len) 276285031Sdes{ 277285031Sdes int r; 278285031Sdes 279285031Sdes if ((r = sshpkt_start(ssh, type)) != 0 || 280285031Sdes (r = sshpkt_put(ssh, data, len)) != 0 || 281285031Sdes (r = sshpkt_send(ssh)) != 0) 282285031Sdes return r; 283285031Sdes return 0; 284285031Sdes} 285285031Sdes 286285031Sdesconst u_char * 287285031Sdesssh_output_ptr(struct ssh *ssh, size_t *len) 288285031Sdes{ 289285031Sdes struct sshbuf *output = ssh_packet_get_output(ssh); 290285031Sdes 291285031Sdes *len = sshbuf_len(output); 292285031Sdes return sshbuf_ptr(output); 293285031Sdes} 294285031Sdes 295285031Sdesint 296285031Sdesssh_output_consume(struct ssh *ssh, size_t len) 297285031Sdes{ 298285031Sdes return sshbuf_consume(ssh_packet_get_output(ssh), len); 299285031Sdes} 300285031Sdes 301285031Sdesint 302285031Sdesssh_output_space(struct ssh *ssh, size_t len) 303285031Sdes{ 304285031Sdes return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len)); 305285031Sdes} 306285031Sdes 307285031Sdesint 308285031Sdesssh_input_space(struct ssh *ssh, size_t len) 309285031Sdes{ 310285031Sdes return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len)); 311285031Sdes} 312285031Sdes 313285031Sdes/* Read other side's version identification. */ 314285031Sdesint 315285031Sdes_ssh_read_banner(struct ssh *ssh, char **bannerp) 316285031Sdes{ 317285031Sdes struct sshbuf *input; 318285031Sdes const char *s; 319285031Sdes char buf[256], remote_version[256]; /* must be same size! */ 320285031Sdes const char *mismatch = "Protocol mismatch.\r\n"; 321285031Sdes int r, remote_major, remote_minor; 322285031Sdes size_t i, n, j, len; 323285031Sdes 324285031Sdes *bannerp = NULL; 325285031Sdes input = ssh_packet_get_input(ssh); 326285031Sdes len = sshbuf_len(input); 327285031Sdes s = (const char *)sshbuf_ptr(input); 328285031Sdes for (j = n = 0;;) { 329285031Sdes for (i = 0; i < sizeof(buf) - 1; i++) { 330285031Sdes if (j >= len) 331285031Sdes return (0); 332285031Sdes buf[i] = s[j++]; 333285031Sdes if (buf[i] == '\r') { 334285031Sdes buf[i] = '\n'; 335285031Sdes buf[i + 1] = 0; 336285031Sdes continue; /**XXX wait for \n */ 337285031Sdes } 338285031Sdes if (buf[i] == '\n') { 339285031Sdes buf[i + 1] = 0; 340285031Sdes break; 341285031Sdes } 342285031Sdes } 343285031Sdes buf[sizeof(buf) - 1] = 0; 344285031Sdes if (strncmp(buf, "SSH-", 4) == 0) 345285031Sdes break; 346285031Sdes debug("ssh_exchange_identification: %s", buf); 347285031Sdes if (ssh->kex->server || ++n > 65536) { 348285031Sdes if ((r = sshbuf_put(ssh_packet_get_output(ssh), 349285031Sdes mismatch, strlen(mismatch))) != 0) 350285031Sdes return r; 351285031Sdes return SSH_ERR_NO_PROTOCOL_VERSION; 352285031Sdes } 353285031Sdes } 354285031Sdes if ((r = sshbuf_consume(input, j)) != 0) 355285031Sdes return r; 356285031Sdes 357285031Sdes /* 358285031Sdes * Check that the versions match. In future this might accept 359285031Sdes * several versions and set appropriate flags to handle them. 360285031Sdes */ 361285031Sdes if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", 362285031Sdes &remote_major, &remote_minor, remote_version) != 3) 363285031Sdes return SSH_ERR_INVALID_FORMAT; 364285031Sdes debug("Remote protocol version %d.%d, remote software version %.100s", 365285031Sdes remote_major, remote_minor, remote_version); 366285031Sdes 367285031Sdes ssh->compat = compat_datafellows(remote_version); 368285031Sdes if (remote_major == 1 && remote_minor == 99) { 369285031Sdes remote_major = 2; 370285031Sdes remote_minor = 0; 371285031Sdes } 372285031Sdes if (remote_major != 2) 373285031Sdes return SSH_ERR_PROTOCOL_MISMATCH; 374285031Sdes enable_compat20(); 375285031Sdes chop(buf); 376285031Sdes debug("Remote version string %.100s", buf); 377285031Sdes if ((*bannerp = strdup(buf)) == NULL) 378285031Sdes return SSH_ERR_ALLOC_FAIL; 379285031Sdes return 0; 380285031Sdes} 381285031Sdes 382285031Sdes/* Send our own protocol version identification. */ 383285031Sdesint 384285031Sdes_ssh_send_banner(struct ssh *ssh, char **bannerp) 385285031Sdes{ 386285031Sdes char buf[256]; 387285031Sdes int r; 388285031Sdes 389285031Sdes snprintf(buf, sizeof buf, "SSH-2.0-%.100s\r\n", SSH_VERSION); 390285031Sdes if ((r = sshbuf_put(ssh_packet_get_output(ssh), buf, strlen(buf))) != 0) 391285031Sdes return r; 392285031Sdes chop(buf); 393285031Sdes debug("Local version string %.100s", buf); 394285031Sdes if ((*bannerp = strdup(buf)) == NULL) 395285031Sdes return SSH_ERR_ALLOC_FAIL; 396285031Sdes return 0; 397285031Sdes} 398285031Sdes 399285031Sdesint 400285031Sdes_ssh_exchange_banner(struct ssh *ssh) 401285031Sdes{ 402285031Sdes struct kex *kex = ssh->kex; 403285031Sdes int r; 404285031Sdes 405285031Sdes /* 406285031Sdes * if _ssh_read_banner() cannot parse a full version string 407285031Sdes * it will return NULL and we end up calling it again. 408285031Sdes */ 409285031Sdes 410285031Sdes r = 0; 411285031Sdes if (kex->server) { 412285031Sdes if (kex->server_version_string == NULL) 413285031Sdes r = _ssh_send_banner(ssh, &kex->server_version_string); 414285031Sdes if (r == 0 && 415285031Sdes kex->server_version_string != NULL && 416285031Sdes kex->client_version_string == NULL) 417285031Sdes r = _ssh_read_banner(ssh, &kex->client_version_string); 418285031Sdes } else { 419285031Sdes if (kex->server_version_string == NULL) 420285031Sdes r = _ssh_read_banner(ssh, &kex->server_version_string); 421285031Sdes if (r == 0 && 422285031Sdes kex->server_version_string != NULL && 423285031Sdes kex->client_version_string == NULL) 424285031Sdes r = _ssh_send_banner(ssh, &kex->client_version_string); 425285031Sdes } 426285031Sdes if (r != 0) 427285031Sdes return r; 428285031Sdes /* start initial kex as soon as we have exchanged the banners */ 429285031Sdes if (kex->server_version_string != NULL && 430285031Sdes kex->client_version_string != NULL) { 431285031Sdes if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 || 432285031Sdes (r = kex_send_kexinit(ssh)) != 0) 433285031Sdes return r; 434285031Sdes } 435285031Sdes return 0; 436285031Sdes} 437285031Sdes 438285031Sdesstruct sshkey * 439285031Sdes_ssh_host_public_key(int type, int nid, struct ssh *ssh) 440285031Sdes{ 441285031Sdes struct key_entry *k; 442285031Sdes 443285031Sdes debug3("%s: need %d", __func__, type); 444285031Sdes TAILQ_FOREACH(k, &ssh->public_keys, next) { 445285031Sdes debug3("%s: check %s", __func__, sshkey_type(k->key)); 446285031Sdes if (k->key->type == type && 447285031Sdes (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 448285031Sdes return (k->key); 449285031Sdes } 450285031Sdes return (NULL); 451285031Sdes} 452285031Sdes 453285031Sdesstruct sshkey * 454285031Sdes_ssh_host_private_key(int type, int nid, struct ssh *ssh) 455285031Sdes{ 456285031Sdes struct key_entry *k; 457285031Sdes 458285031Sdes debug3("%s: need %d", __func__, type); 459285031Sdes TAILQ_FOREACH(k, &ssh->private_keys, next) { 460285031Sdes debug3("%s: check %s", __func__, sshkey_type(k->key)); 461285031Sdes if (k->key->type == type && 462285031Sdes (type != KEY_ECDSA || k->key->ecdsa_nid == nid)) 463285031Sdes return (k->key); 464285031Sdes } 465285031Sdes return (NULL); 466285031Sdes} 467285031Sdes 468285031Sdesint 469285031Sdes_ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh) 470285031Sdes{ 471285031Sdes struct key_entry *k; 472285031Sdes 473285031Sdes debug3("%s: need %s", __func__, sshkey_type(hostkey)); 474285031Sdes TAILQ_FOREACH(k, &ssh->public_keys, next) { 475285031Sdes debug3("%s: check %s", __func__, sshkey_type(k->key)); 476285031Sdes if (sshkey_equal_public(hostkey, k->key)) 477285031Sdes return (0); /* ok */ 478285031Sdes } 479285031Sdes return (-1); /* failed */ 480285031Sdes} 481285031Sdes 482285031Sdes/* offer hostkey algorithms in kexinit depending on registered keys */ 483285031Sdesint 484285031Sdes_ssh_order_hostkeyalgs(struct ssh *ssh) 485285031Sdes{ 486285031Sdes struct key_entry *k; 487285031Sdes char *orig, *avail, *oavail = NULL, *alg, *replace = NULL; 488285031Sdes char **proposal; 489285031Sdes size_t maxlen; 490285031Sdes int ktype, r; 491285031Sdes 492285031Sdes /* XXX we de-serialize ssh->kex->my, modify it, and change it */ 493285031Sdes if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0) 494285031Sdes return r; 495285031Sdes orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; 496285031Sdes if ((oavail = avail = strdup(orig)) == NULL) { 497285031Sdes r = SSH_ERR_ALLOC_FAIL; 498285031Sdes goto out; 499285031Sdes } 500285031Sdes maxlen = strlen(avail) + 1; 501285031Sdes if ((replace = calloc(1, maxlen)) == NULL) { 502285031Sdes r = SSH_ERR_ALLOC_FAIL; 503285031Sdes goto out; 504285031Sdes } 505285031Sdes *replace = '\0'; 506285031Sdes while ((alg = strsep(&avail, ",")) && *alg != '\0') { 507285031Sdes if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC) 508285031Sdes continue; 509285031Sdes TAILQ_FOREACH(k, &ssh->public_keys, next) { 510285031Sdes if (k->key->type == ktype || 511285031Sdes (sshkey_is_cert(k->key) && k->key->type == 512285031Sdes sshkey_type_plain(ktype))) { 513285031Sdes if (*replace != '\0') 514285031Sdes strlcat(replace, ",", maxlen); 515285031Sdes strlcat(replace, alg, maxlen); 516285031Sdes break; 517285031Sdes } 518285031Sdes } 519285031Sdes } 520285031Sdes if (*replace != '\0') { 521285031Sdes debug2("%s: orig/%d %s", __func__, ssh->kex->server, orig); 522285031Sdes debug2("%s: replace/%d %s", __func__, ssh->kex->server, replace); 523285031Sdes free(orig); 524285031Sdes proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace; 525285031Sdes replace = NULL; /* owned by proposal */ 526285031Sdes r = kex_prop2buf(ssh->kex->my, proposal); 527285031Sdes } 528285031Sdes out: 529285031Sdes free(oavail); 530285031Sdes free(replace); 531285031Sdes kex_prop_free(proposal); 532285031Sdes return r; 533285031Sdes} 534285031Sdes 535285031Sdesint 536285031Sdes_ssh_host_key_sign(struct sshkey *privkey, struct sshkey *pubkey, 537296781Sdes u_char **signature, size_t *slen, const u_char *data, size_t dlen, 538296781Sdes const char *alg, u_int compat) 539285031Sdes{ 540296781Sdes return sshkey_sign(privkey, signature, slen, data, dlen, alg, compat); 541285031Sdes} 542