xref: /openbsd-src/usr.bin/ssh/ssh_api.c (revision 1f96526fb0deff53898d266d4e2e399e64e301ef)
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