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