xref: /openbsd-src/usr.bin/ssh/ssh_api.c (revision 559366d60a3ec28558bac09ee7122b367df18637)
1*559366d6Sdjm /* $OpenBSD: ssh_api.c,v 1.32 2024/10/18 05:14:51 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"
2871f11376Sdjm #include "dh.h"
29d9c3c4c1Smarkus #include "misc.h"
30d9c3c4c1Smarkus #include "ssh2.h"
31d9c3c4c1Smarkus #include "version.h"
32d9c3c4c1Smarkus #include "myproposal.h"
33d9c3c4c1Smarkus #include "ssherr.h"
34d9c3c4c1Smarkus #include "sshbuf.h"
35d9c3c4c1Smarkus 
36d9c3c4c1Smarkus #include <string.h>
37d9c3c4c1Smarkus 
38d9c3c4c1Smarkus int	_ssh_exchange_banner(struct ssh *);
3901cfcf25Sdjm int	_ssh_send_banner(struct ssh *, struct sshbuf *);
4001cfcf25Sdjm int	_ssh_read_banner(struct ssh *, struct sshbuf *);
41d9c3c4c1Smarkus int	_ssh_order_hostkeyalgs(struct ssh *);
42d9c3c4c1Smarkus int	_ssh_verify_host_key(struct sshkey *, struct ssh *);
433482e068Sdjm struct sshkey *_ssh_host_public_key(int, int, struct ssh *);
443482e068Sdjm struct sshkey *_ssh_host_private_key(int, int, struct ssh *);
458d3ff63dSdjm int	_ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *,
468d3ff63dSdjm     u_char **, size_t *, const u_char *, size_t, const char *);
47d9c3c4c1Smarkus 
48d9c3c4c1Smarkus /*
4971f11376Sdjm  * stubs for privsep calls in the server side implementation of kex.
50d9c3c4c1Smarkus  */
51d9c3c4c1Smarkus int	mm_sshkey_sign(struct sshkey *, u_char **, u_int *,
521f63d3c4Sdjm     const u_char *, u_int, const char *, const char *, const char *, u_int);
531f96526fSdjm 
541f96526fSdjm #ifdef WITH_OPENSSL
55d9c3c4c1Smarkus DH	*mm_choose_dh(int, int, int);
561f96526fSdjm #endif
57d9c3c4c1Smarkus 
58d9c3c4c1Smarkus int
59d9c3c4c1Smarkus mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
601f63d3c4Sdjm     const u_char *data, u_int datalen, const char *alg,
611f63d3c4Sdjm     const char *sk_provider, const char *sk_pin, u_int compat)
62d9c3c4c1Smarkus {
6371f11376Sdjm 	size_t slen = 0;
6471f11376Sdjm 	int ret;
6571f11376Sdjm 
6671f11376Sdjm 	ret = sshkey_sign(key, sigp, &slen, data, datalen, alg,
6771f11376Sdjm 	    sk_provider, sk_pin, compat);
6871f11376Sdjm 	*lenp = slen;
6971f11376Sdjm 	return ret;
70d9c3c4c1Smarkus }
71d9c3c4c1Smarkus 
721f96526fSdjm #ifdef WITH_OPENSSL
73d9c3c4c1Smarkus DH *
74d9c3c4c1Smarkus mm_choose_dh(int min, int nbits, int max)
75d9c3c4c1Smarkus {
7671f11376Sdjm 	return choose_dh(min, nbits, max);
77d9c3c4c1Smarkus }
781f96526fSdjm #endif
79d9c3c4c1Smarkus 
80d9c3c4c1Smarkus /* API */
81d9c3c4c1Smarkus 
82d9c3c4c1Smarkus int
83d9c3c4c1Smarkus ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
84d9c3c4c1Smarkus {
85d9c3c4c1Smarkus 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
8629ae6bbdSdjm 	char *populated[PROPOSAL_MAX];
87d9c3c4c1Smarkus 	struct ssh *ssh;
88d9c3c4c1Smarkus 	char **proposal;
89d9c3c4c1Smarkus 	static int called;
90d9c3c4c1Smarkus 	int r;
91d9c3c4c1Smarkus 
92d9c3c4c1Smarkus 	if (!called) {
931f96526fSdjm #ifdef WITH_OPENSSL
94d9c3c4c1Smarkus 		OpenSSL_add_all_algorithms();
951f96526fSdjm #endif
96d9c3c4c1Smarkus 		called = 1;
97d9c3c4c1Smarkus 	}
98d9c3c4c1Smarkus 
997b0d3b43Sdjm 	if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL)
1007b0d3b43Sdjm 		return SSH_ERR_ALLOC_FAIL;
101d9c3c4c1Smarkus 	if (is_server)
102d9c3c4c1Smarkus 		ssh_packet_set_server(ssh);
103d9c3c4c1Smarkus 
104d9c3c4c1Smarkus 	/* Initialize key exchange */
105d9c3c4c1Smarkus 	proposal = kex_params ? kex_params->proposal : myproposal;
10629ae6bbdSdjm 	kex_proposal_populate_entries(ssh, populated,
10729ae6bbdSdjm 	    proposal[PROPOSAL_KEX_ALGS],
10829ae6bbdSdjm 	    proposal[PROPOSAL_ENC_ALGS_CTOS],
10929ae6bbdSdjm 	    proposal[PROPOSAL_MAC_ALGS_CTOS],
11029ae6bbdSdjm 	    proposal[PROPOSAL_COMP_ALGS_CTOS],
11129ae6bbdSdjm 	    proposal[PROPOSAL_SERVER_HOST_KEY_ALGS]);
11229ae6bbdSdjm 	r = kex_ready(ssh, populated);
11329ae6bbdSdjm 	kex_proposal_free_entries(populated);
11429ae6bbdSdjm 	if (r != 0) {
115d9c3c4c1Smarkus 		ssh_free(ssh);
116d9c3c4c1Smarkus 		return r;
117d9c3c4c1Smarkus 	}
11829ae6bbdSdjm 
119d9c3c4c1Smarkus 	ssh->kex->server = is_server;
120d9c3c4c1Smarkus 	if (is_server) {
121d9c3c4c1Smarkus #ifdef WITH_OPENSSL
12239957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server;
12339957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server;
12439957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server;
12539957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server;
12639957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server;
127d9c3c4c1Smarkus 		ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
128d9c3c4c1Smarkus 		ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
12939957e0dSdjm 		ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_server;
130d9c3c4c1Smarkus #endif /* WITH_OPENSSL */
13139957e0dSdjm 		ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server;
1323e284e19Sdjm 		ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server;
1339dc26a4eSdjm 		ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server;
134d9c3c4c1Smarkus 		ssh->kex->load_host_public_key=&_ssh_host_public_key;
135d9c3c4c1Smarkus 		ssh->kex->load_host_private_key=&_ssh_host_private_key;
136d9c3c4c1Smarkus 		ssh->kex->sign=&_ssh_host_key_sign;
137d9c3c4c1Smarkus 	} else {
138d9c3c4c1Smarkus #ifdef WITH_OPENSSL
13939957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_client;
14039957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_client;
14139957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_client;
14239957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_client;
14339957e0dSdjm 		ssh->kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_client;
144d9c3c4c1Smarkus 		ssh->kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
145d9c3c4c1Smarkus 		ssh->kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
14639957e0dSdjm 		ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client;
147d9c3c4c1Smarkus #endif /* WITH_OPENSSL */
14839957e0dSdjm 		ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client;
1493e284e19Sdjm 		ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client;
1509dc26a4eSdjm 		ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client;
151d9c3c4c1Smarkus 		ssh->kex->verify_host_key =&_ssh_verify_host_key;
152d9c3c4c1Smarkus 	}
153d9c3c4c1Smarkus 	*sshp = ssh;
154d9c3c4c1Smarkus 	return 0;
155d9c3c4c1Smarkus }
156d9c3c4c1Smarkus 
157d9c3c4c1Smarkus void
158d9c3c4c1Smarkus ssh_free(struct ssh *ssh)
159d9c3c4c1Smarkus {
160d9c3c4c1Smarkus 	struct key_entry *k;
161d9c3c4c1Smarkus 
162ee048ab9Sdjm 	if (ssh == NULL)
163ee048ab9Sdjm 		return;
164ee048ab9Sdjm 
165d9c3c4c1Smarkus 	/*
166d9c3c4c1Smarkus 	 * we've only created the public keys variants in case we
167d9c3c4c1Smarkus 	 * are a acting as a server.
168d9c3c4c1Smarkus 	 */
169d9c3c4c1Smarkus 	while ((k = TAILQ_FIRST(&ssh->public_keys)) != NULL) {
170d9c3c4c1Smarkus 		TAILQ_REMOVE(&ssh->public_keys, k, next);
171d9c3c4c1Smarkus 		if (ssh->kex && ssh->kex->server)
172d9c3c4c1Smarkus 			sshkey_free(k->key);
173d9c3c4c1Smarkus 		free(k);
174d9c3c4c1Smarkus 	}
175d9c3c4c1Smarkus 	while ((k = TAILQ_FIRST(&ssh->private_keys)) != NULL) {
176d9c3c4c1Smarkus 		TAILQ_REMOVE(&ssh->private_keys, k, next);
177d9c3c4c1Smarkus 		free(k);
178d9c3c4c1Smarkus 	}
17935e6b843Smarkus 	ssh_packet_close(ssh);
180d9c3c4c1Smarkus 	free(ssh);
181d9c3c4c1Smarkus }
182d9c3c4c1Smarkus 
183d9c3c4c1Smarkus void
184d9c3c4c1Smarkus ssh_set_app_data(struct ssh *ssh, void *app_data)
185d9c3c4c1Smarkus {
186d9c3c4c1Smarkus 	ssh->app_data = app_data;
187d9c3c4c1Smarkus }
188d9c3c4c1Smarkus 
189d9c3c4c1Smarkus void *
190d9c3c4c1Smarkus ssh_get_app_data(struct ssh *ssh)
191d9c3c4c1Smarkus {
192d9c3c4c1Smarkus 	return ssh->app_data;
193d9c3c4c1Smarkus }
194d9c3c4c1Smarkus 
195d9c3c4c1Smarkus /* Returns < 0 on error, 0 otherwise */
196d9c3c4c1Smarkus int
197d9c3c4c1Smarkus ssh_add_hostkey(struct ssh *ssh, struct sshkey *key)
198d9c3c4c1Smarkus {
199d9c3c4c1Smarkus 	struct sshkey *pubkey = NULL;
200d9c3c4c1Smarkus 	struct key_entry *k = NULL, *k_prv = NULL;
201d9c3c4c1Smarkus 	int r;
202d9c3c4c1Smarkus 
203d9c3c4c1Smarkus 	if (ssh->kex->server) {
204d9c3c4c1Smarkus 		if ((r = sshkey_from_private(key, &pubkey)) != 0)
205d9c3c4c1Smarkus 			return r;
206d9c3c4c1Smarkus 		if ((k = malloc(sizeof(*k))) == NULL ||
207d9c3c4c1Smarkus 		    (k_prv = malloc(sizeof(*k_prv))) == NULL) {
208d9c3c4c1Smarkus 			free(k);
209d9c3c4c1Smarkus 			sshkey_free(pubkey);
210d9c3c4c1Smarkus 			return SSH_ERR_ALLOC_FAIL;
211d9c3c4c1Smarkus 		}
212d9c3c4c1Smarkus 		k_prv->key = key;
213d9c3c4c1Smarkus 		TAILQ_INSERT_TAIL(&ssh->private_keys, k_prv, next);
214d9c3c4c1Smarkus 
215d9c3c4c1Smarkus 		/* add the public key, too */
216d9c3c4c1Smarkus 		k->key = pubkey;
217d9c3c4c1Smarkus 		TAILQ_INSERT_TAIL(&ssh->public_keys, k, next);
218d9c3c4c1Smarkus 		r = 0;
219d9c3c4c1Smarkus 	} else {
220d9c3c4c1Smarkus 		if ((k = malloc(sizeof(*k))) == NULL)
221d9c3c4c1Smarkus 			return SSH_ERR_ALLOC_FAIL;
222d9c3c4c1Smarkus 		k->key = key;
223d9c3c4c1Smarkus 		TAILQ_INSERT_TAIL(&ssh->public_keys, k, next);
224d9c3c4c1Smarkus 		r = 0;
225d9c3c4c1Smarkus 	}
226d9c3c4c1Smarkus 
227d9c3c4c1Smarkus 	return r;
228d9c3c4c1Smarkus }
229d9c3c4c1Smarkus 
230d9c3c4c1Smarkus int
231d9c3c4c1Smarkus ssh_set_verify_host_key_callback(struct ssh *ssh,
232d9c3c4c1Smarkus     int (*cb)(struct sshkey *, struct ssh *))
233d9c3c4c1Smarkus {
234d9c3c4c1Smarkus 	if (cb == NULL || ssh->kex == NULL)
235d9c3c4c1Smarkus 		return SSH_ERR_INVALID_ARGUMENT;
236d9c3c4c1Smarkus 
237d9c3c4c1Smarkus 	ssh->kex->verify_host_key = cb;
238d9c3c4c1Smarkus 
239d9c3c4c1Smarkus 	return 0;
240d9c3c4c1Smarkus }
241d9c3c4c1Smarkus 
242d9c3c4c1Smarkus int
243d9c3c4c1Smarkus ssh_input_append(struct ssh *ssh, const u_char *data, size_t len)
244d9c3c4c1Smarkus {
245d9c3c4c1Smarkus 	return sshbuf_put(ssh_packet_get_input(ssh), data, len);
246d9c3c4c1Smarkus }
247d9c3c4c1Smarkus 
248d9c3c4c1Smarkus int
249d9c3c4c1Smarkus ssh_packet_next(struct ssh *ssh, u_char *typep)
250d9c3c4c1Smarkus {
251d9c3c4c1Smarkus 	int r;
252d9c3c4c1Smarkus 	u_int32_t seqnr;
253d9c3c4c1Smarkus 	u_char type;
254d9c3c4c1Smarkus 
255d9c3c4c1Smarkus 	/*
256d9c3c4c1Smarkus 	 * Try to read a packet. Return SSH_MSG_NONE if no packet or not
257d9c3c4c1Smarkus 	 * enough data.
258d9c3c4c1Smarkus 	 */
259d9c3c4c1Smarkus 	*typep = SSH_MSG_NONE;
26001cfcf25Sdjm 	if (sshbuf_len(ssh->kex->client_version) == 0 ||
26101cfcf25Sdjm 	    sshbuf_len(ssh->kex->server_version) == 0)
262d9c3c4c1Smarkus 		return _ssh_exchange_banner(ssh);
263d9c3c4c1Smarkus 	/*
264d9c3c4c1Smarkus 	 * If we enough data and a dispatch function then
265d9c3c4c1Smarkus 	 * call the function and get the next packet.
266d9c3c4c1Smarkus 	 * Otherwise return the packet type to the caller so it
267d9c3c4c1Smarkus 	 * can decide how to go on.
268d9c3c4c1Smarkus 	 *
269d9c3c4c1Smarkus 	 * We will only call the dispatch function for:
270d9c3c4c1Smarkus 	 *     20-29    Algorithm negotiation
271d9c3c4c1Smarkus 	 *     30-49    Key exchange method specific (numbers can be reused for
272d9c3c4c1Smarkus 	 *              different authentication methods)
273d9c3c4c1Smarkus 	 */
274d9c3c4c1Smarkus 	for (;;) {
275d9c3c4c1Smarkus 		if ((r = ssh_packet_read_poll2(ssh, &type, &seqnr)) != 0)
276d9c3c4c1Smarkus 			return r;
277d9c3c4c1Smarkus 		if (type > 0 && type < DISPATCH_MAX &&
278d9c3c4c1Smarkus 		    type >= SSH2_MSG_KEXINIT && type <= SSH2_MSG_TRANSPORT_MAX &&
279d9c3c4c1Smarkus 		    ssh->dispatch[type] != NULL) {
280d9c3c4c1Smarkus 			if ((r = (*ssh->dispatch[type])(type, seqnr, ssh)) != 0)
281d9c3c4c1Smarkus 				return r;
282d9c3c4c1Smarkus 		} else {
283d9c3c4c1Smarkus 			*typep = type;
284d9c3c4c1Smarkus 			return 0;
285d9c3c4c1Smarkus 		}
286d9c3c4c1Smarkus 	}
287d9c3c4c1Smarkus }
288d9c3c4c1Smarkus 
289d9c3c4c1Smarkus const u_char *
290d9c3c4c1Smarkus ssh_packet_payload(struct ssh *ssh, size_t *lenp)
291d9c3c4c1Smarkus {
292d9c3c4c1Smarkus 	return sshpkt_ptr(ssh, lenp);
293d9c3c4c1Smarkus }
294d9c3c4c1Smarkus 
295d9c3c4c1Smarkus int
296d9c3c4c1Smarkus ssh_packet_put(struct ssh *ssh, int type, const u_char *data, size_t len)
297d9c3c4c1Smarkus {
298d9c3c4c1Smarkus 	int r;
299d9c3c4c1Smarkus 
300d9c3c4c1Smarkus 	if ((r = sshpkt_start(ssh, type)) != 0 ||
301d9c3c4c1Smarkus 	    (r = sshpkt_put(ssh, data, len)) != 0 ||
302d9c3c4c1Smarkus 	    (r = sshpkt_send(ssh)) != 0)
303d9c3c4c1Smarkus 		return r;
304d9c3c4c1Smarkus 	return 0;
305d9c3c4c1Smarkus }
306d9c3c4c1Smarkus 
307d9c3c4c1Smarkus const u_char *
308d9c3c4c1Smarkus ssh_output_ptr(struct ssh *ssh, size_t *len)
309d9c3c4c1Smarkus {
310d9c3c4c1Smarkus 	struct sshbuf *output = ssh_packet_get_output(ssh);
311d9c3c4c1Smarkus 
312d9c3c4c1Smarkus 	*len = sshbuf_len(output);
313d9c3c4c1Smarkus 	return sshbuf_ptr(output);
314d9c3c4c1Smarkus }
315d9c3c4c1Smarkus 
316d9c3c4c1Smarkus int
317d9c3c4c1Smarkus ssh_output_consume(struct ssh *ssh, size_t len)
318d9c3c4c1Smarkus {
319d9c3c4c1Smarkus 	return sshbuf_consume(ssh_packet_get_output(ssh), len);
320d9c3c4c1Smarkus }
321d9c3c4c1Smarkus 
322d9c3c4c1Smarkus int
323d9c3c4c1Smarkus ssh_output_space(struct ssh *ssh, size_t len)
324d9c3c4c1Smarkus {
325d9c3c4c1Smarkus 	return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh), len));
326d9c3c4c1Smarkus }
327d9c3c4c1Smarkus 
328d9c3c4c1Smarkus int
329d9c3c4c1Smarkus ssh_input_space(struct ssh *ssh, size_t len)
330d9c3c4c1Smarkus {
331d9c3c4c1Smarkus 	return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh), len));
332d9c3c4c1Smarkus }
333d9c3c4c1Smarkus 
334d9c3c4c1Smarkus /* Read other side's version identification. */
335d9c3c4c1Smarkus int
33601cfcf25Sdjm _ssh_read_banner(struct ssh *ssh, struct sshbuf *banner)
337d9c3c4c1Smarkus {
33801cfcf25Sdjm 	struct sshbuf *input = ssh_packet_get_input(ssh);
339d9c3c4c1Smarkus 	const char *mismatch = "Protocol mismatch.\r\n";
34001cfcf25Sdjm 	const u_char *s = sshbuf_ptr(input);
34101cfcf25Sdjm 	u_char c;
34233d1bf81Sdtucker 	char *cp = NULL, *remote_version = NULL;
34333d1bf81Sdtucker 	int r = 0, remote_major, remote_minor, expect_nl;
34401cfcf25Sdjm 	size_t n, j;
345d9c3c4c1Smarkus 
346d9c3c4c1Smarkus 	for (j = n = 0;;) {
34701cfcf25Sdjm 		sshbuf_reset(banner);
34801cfcf25Sdjm 		expect_nl = 0;
34901cfcf25Sdjm 		for (;;) {
35001cfcf25Sdjm 			if (j >= sshbuf_len(input))
35101cfcf25Sdjm 				return 0; /* insufficient data in input buf */
35201cfcf25Sdjm 			c = s[j++];
35301cfcf25Sdjm 			if (c == '\r') {
35401cfcf25Sdjm 				expect_nl = 1;
35501cfcf25Sdjm 				continue;
356d9c3c4c1Smarkus 			}
35701cfcf25Sdjm 			if (c == '\n')
358d9c3c4c1Smarkus 				break;
35901cfcf25Sdjm 			if (expect_nl)
36001cfcf25Sdjm 				goto bad;
36101cfcf25Sdjm 			if ((r = sshbuf_put_u8(banner, c)) != 0)
36201cfcf25Sdjm 				return r;
36301cfcf25Sdjm 			if (sshbuf_len(banner) > SSH_MAX_BANNER_LEN)
36401cfcf25Sdjm 				goto bad;
365d9c3c4c1Smarkus 		}
36601cfcf25Sdjm 		if (sshbuf_len(banner) >= 4 &&
36701cfcf25Sdjm 		    memcmp(sshbuf_ptr(banner), "SSH-", 4) == 0)
368d9c3c4c1Smarkus 			break;
36948e6b99dSdjm 		debug_f("%.*s", (int)sshbuf_len(banner),
37033d1bf81Sdtucker 		    sshbuf_ptr(banner));
37101cfcf25Sdjm 		/* Accept lines before banner only on client */
37201cfcf25Sdjm 		if (ssh->kex->server || ++n > SSH_MAX_PRE_BANNER_LINES) {
37301cfcf25Sdjm   bad:
374d9c3c4c1Smarkus 			if ((r = sshbuf_put(ssh_packet_get_output(ssh),
375d9c3c4c1Smarkus 			    mismatch, strlen(mismatch))) != 0)
376d9c3c4c1Smarkus 				return r;
377d9c3c4c1Smarkus 			return SSH_ERR_NO_PROTOCOL_VERSION;
378d9c3c4c1Smarkus 		}
379d9c3c4c1Smarkus 	}
380d9c3c4c1Smarkus 	if ((r = sshbuf_consume(input, j)) != 0)
381d9c3c4c1Smarkus 		return r;
382d9c3c4c1Smarkus 
38301cfcf25Sdjm 	/* XXX remote version must be the same size as banner for sscanf */
38433d1bf81Sdtucker 	if ((cp = sshbuf_dup_string(banner)) == NULL ||
38533d1bf81Sdtucker 	    (remote_version = calloc(1, sshbuf_len(banner))) == NULL) {
38633d1bf81Sdtucker 		r = SSH_ERR_ALLOC_FAIL;
38733d1bf81Sdtucker 		goto out;
38833d1bf81Sdtucker 	}
38901cfcf25Sdjm 
390d9c3c4c1Smarkus 	/*
391d9c3c4c1Smarkus 	 * Check that the versions match.  In future this might accept
392d9c3c4c1Smarkus 	 * several versions and set appropriate flags to handle them.
393d9c3c4c1Smarkus 	 */
39401cfcf25Sdjm 	if (sscanf(cp, "SSH-%d.%d-%[^\n]\n",
39533d1bf81Sdtucker 	    &remote_major, &remote_minor, remote_version) != 3) {
39633d1bf81Sdtucker 		r = SSH_ERR_INVALID_FORMAT;
39733d1bf81Sdtucker 		goto out;
39833d1bf81Sdtucker 	}
399d9c3c4c1Smarkus 	debug("Remote protocol version %d.%d, remote software version %.100s",
400d9c3c4c1Smarkus 	    remote_major, remote_minor, remote_version);
401d9c3c4c1Smarkus 
402e9d14800Sdjm 	compat_banner(ssh, remote_version);
403d9c3c4c1Smarkus 	if  (remote_major == 1 && remote_minor == 99) {
404d9c3c4c1Smarkus 		remote_major = 2;
405d9c3c4c1Smarkus 		remote_minor = 0;
406d9c3c4c1Smarkus 	}
407d9c3c4c1Smarkus 	if (remote_major != 2)
40833d1bf81Sdtucker 		r = SSH_ERR_PROTOCOL_MISMATCH;
40933d1bf81Sdtucker 
41001cfcf25Sdjm 	debug("Remote version string %.100s", cp);
41133d1bf81Sdtucker  out:
41201cfcf25Sdjm 	free(cp);
41333d1bf81Sdtucker 	free(remote_version);
41433d1bf81Sdtucker 	return r;
415d9c3c4c1Smarkus }
416d9c3c4c1Smarkus 
417d9c3c4c1Smarkus /* Send our own protocol version identification. */
418d9c3c4c1Smarkus int
41901cfcf25Sdjm _ssh_send_banner(struct ssh *ssh, struct sshbuf *banner)
420d9c3c4c1Smarkus {
42101cfcf25Sdjm 	char *cp;
422d9c3c4c1Smarkus 	int r;
423d9c3c4c1Smarkus 
42401cfcf25Sdjm 	if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0)
425d9c3c4c1Smarkus 		return r;
42601cfcf25Sdjm 	if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0)
42701cfcf25Sdjm 		return r;
42801cfcf25Sdjm 	/* Remove trailing \r\n */
42901cfcf25Sdjm 	if ((r = sshbuf_consume_end(banner, 2)) != 0)
43001cfcf25Sdjm 		return r;
43101cfcf25Sdjm 	if ((cp = sshbuf_dup_string(banner)) == NULL)
432d9c3c4c1Smarkus 		return SSH_ERR_ALLOC_FAIL;
43301cfcf25Sdjm 	debug("Local version string %.100s", cp);
43401cfcf25Sdjm 	free(cp);
435d9c3c4c1Smarkus 	return 0;
436d9c3c4c1Smarkus }
437d9c3c4c1Smarkus 
438d9c3c4c1Smarkus int
439d9c3c4c1Smarkus _ssh_exchange_banner(struct ssh *ssh)
440d9c3c4c1Smarkus {
441d9c3c4c1Smarkus 	struct kex *kex = ssh->kex;
442d9c3c4c1Smarkus 	int r;
443d9c3c4c1Smarkus 
444d9c3c4c1Smarkus 	/*
445d9c3c4c1Smarkus 	 * if _ssh_read_banner() cannot parse a full version string
446d9c3c4c1Smarkus 	 * it will return NULL and we end up calling it again.
447d9c3c4c1Smarkus 	 */
448d9c3c4c1Smarkus 
449d9c3c4c1Smarkus 	r = 0;
450d9c3c4c1Smarkus 	if (kex->server) {
45101cfcf25Sdjm 		if (sshbuf_len(ssh->kex->server_version) == 0)
45201cfcf25Sdjm 			r = _ssh_send_banner(ssh, ssh->kex->server_version);
453d9c3c4c1Smarkus 		if (r == 0 &&
45401cfcf25Sdjm 		    sshbuf_len(ssh->kex->server_version) != 0 &&
45501cfcf25Sdjm 		    sshbuf_len(ssh->kex->client_version) == 0)
45601cfcf25Sdjm 			r = _ssh_read_banner(ssh, ssh->kex->client_version);
457d9c3c4c1Smarkus 	} else {
45801cfcf25Sdjm 		if (sshbuf_len(ssh->kex->server_version) == 0)
45901cfcf25Sdjm 			r = _ssh_read_banner(ssh, ssh->kex->server_version);
460d9c3c4c1Smarkus 		if (r == 0 &&
46101cfcf25Sdjm 		    sshbuf_len(ssh->kex->server_version) != 0 &&
46201cfcf25Sdjm 		    sshbuf_len(ssh->kex->client_version) == 0)
46301cfcf25Sdjm 			r = _ssh_send_banner(ssh, ssh->kex->client_version);
464d9c3c4c1Smarkus 	}
465d9c3c4c1Smarkus 	if (r != 0)
466d9c3c4c1Smarkus 		return r;
467d9c3c4c1Smarkus 	/* start initial kex as soon as we have exchanged the banners */
46801cfcf25Sdjm 	if (sshbuf_len(ssh->kex->server_version) != 0 &&
46901cfcf25Sdjm 	    sshbuf_len(ssh->kex->client_version) != 0) {
470d9c3c4c1Smarkus 		if ((r = _ssh_order_hostkeyalgs(ssh)) != 0 ||
471d9c3c4c1Smarkus 		    (r = kex_send_kexinit(ssh)) != 0)
472d9c3c4c1Smarkus 			return r;
473d9c3c4c1Smarkus 	}
474d9c3c4c1Smarkus 	return 0;
475d9c3c4c1Smarkus }
476d9c3c4c1Smarkus 
477d9c3c4c1Smarkus struct sshkey *
4783482e068Sdjm _ssh_host_public_key(int type, int nid, struct ssh *ssh)
479d9c3c4c1Smarkus {
480d9c3c4c1Smarkus 	struct key_entry *k;
481d9c3c4c1Smarkus 
48248e6b99dSdjm 	debug3_f("need %d", type);
483d9c3c4c1Smarkus 	TAILQ_FOREACH(k, &ssh->public_keys, next) {
48448e6b99dSdjm 		debug3_f("check %s", sshkey_type(k->key));
4853482e068Sdjm 		if (k->key->type == type &&
4863482e068Sdjm 		    (type != KEY_ECDSA || k->key->ecdsa_nid == nid))
487d9c3c4c1Smarkus 			return (k->key);
488d9c3c4c1Smarkus 	}
489d9c3c4c1Smarkus 	return (NULL);
490d9c3c4c1Smarkus }
491d9c3c4c1Smarkus 
492d9c3c4c1Smarkus struct sshkey *
4933482e068Sdjm _ssh_host_private_key(int type, int nid, struct ssh *ssh)
494d9c3c4c1Smarkus {
495d9c3c4c1Smarkus 	struct key_entry *k;
496d9c3c4c1Smarkus 
49748e6b99dSdjm 	debug3_f("need %d", type);
498d9c3c4c1Smarkus 	TAILQ_FOREACH(k, &ssh->private_keys, next) {
49948e6b99dSdjm 		debug3_f("check %s", sshkey_type(k->key));
5003482e068Sdjm 		if (k->key->type == type &&
5013482e068Sdjm 		    (type != KEY_ECDSA || k->key->ecdsa_nid == nid))
502d9c3c4c1Smarkus 			return (k->key);
503d9c3c4c1Smarkus 	}
504d9c3c4c1Smarkus 	return (NULL);
505d9c3c4c1Smarkus }
506d9c3c4c1Smarkus 
507d9c3c4c1Smarkus int
508d9c3c4c1Smarkus _ssh_verify_host_key(struct sshkey *hostkey, struct ssh *ssh)
509d9c3c4c1Smarkus {
510d9c3c4c1Smarkus 	struct key_entry *k;
511d9c3c4c1Smarkus 
51248e6b99dSdjm 	debug3_f("need %s", sshkey_type(hostkey));
513d9c3c4c1Smarkus 	TAILQ_FOREACH(k, &ssh->public_keys, next) {
51448e6b99dSdjm 		debug3_f("check %s", sshkey_type(k->key));
515d9c3c4c1Smarkus 		if (sshkey_equal_public(hostkey, k->key))
516d9c3c4c1Smarkus 			return (0);	/* ok */
517d9c3c4c1Smarkus 	}
518d9c3c4c1Smarkus 	return (-1);	/* failed */
519d9c3c4c1Smarkus }
520d9c3c4c1Smarkus 
521d9c3c4c1Smarkus /* offer hostkey algorithms in kexinit depending on registered keys */
522d9c3c4c1Smarkus int
523d9c3c4c1Smarkus _ssh_order_hostkeyalgs(struct ssh *ssh)
524d9c3c4c1Smarkus {
525d9c3c4c1Smarkus 	struct key_entry *k;
526d9c3c4c1Smarkus 	char *orig, *avail, *oavail = NULL, *alg, *replace = NULL;
527d9c3c4c1Smarkus 	char **proposal;
528d9c3c4c1Smarkus 	size_t maxlen;
529*559366d6Sdjm 	int ktype, nid, r;
530d9c3c4c1Smarkus 
531d9c3c4c1Smarkus 	/* XXX we de-serialize ssh->kex->my, modify it, and change it */
532d9c3c4c1Smarkus 	if ((r = kex_buf2prop(ssh->kex->my, NULL, &proposal)) != 0)
533d9c3c4c1Smarkus 		return r;
534d9c3c4c1Smarkus 	orig = proposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
535d9c3c4c1Smarkus 	if ((oavail = avail = strdup(orig)) == NULL) {
536d9c3c4c1Smarkus 		r = SSH_ERR_ALLOC_FAIL;
537d9c3c4c1Smarkus 		goto out;
538d9c3c4c1Smarkus 	}
539d9c3c4c1Smarkus 	maxlen = strlen(avail) + 1;
540d9c3c4c1Smarkus 	if ((replace = calloc(1, maxlen)) == NULL) {
541d9c3c4c1Smarkus 		r = SSH_ERR_ALLOC_FAIL;
542d9c3c4c1Smarkus 		goto out;
543d9c3c4c1Smarkus 	}
544d9c3c4c1Smarkus 	*replace = '\0';
545d9c3c4c1Smarkus 	while ((alg = strsep(&avail, ",")) && *alg != '\0') {
546d9c3c4c1Smarkus 		if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
547d9c3c4c1Smarkus 			continue;
548*559366d6Sdjm 		nid = sshkey_ecdsa_nid_from_name(alg);
549d9c3c4c1Smarkus 		TAILQ_FOREACH(k, &ssh->public_keys, next) {
550*559366d6Sdjm 			if (k->key->type != ktype &&
551*559366d6Sdjm 			    (!sshkey_is_cert(k->key) ||
552*559366d6Sdjm 			    k->key->type != sshkey_type_plain(ktype)))
553*559366d6Sdjm 				continue;
554*559366d6Sdjm 			if (sshkey_type_plain(k->key->type) == KEY_ECDSA &&
555*559366d6Sdjm 			    k->key->ecdsa_nid != nid)
556*559366d6Sdjm 				continue;
557*559366d6Sdjm 			/* Candidate */
558d9c3c4c1Smarkus 			if (*replace != '\0')
559d9c3c4c1Smarkus 				strlcat(replace, ",", maxlen);
560d9c3c4c1Smarkus 			strlcat(replace, alg, maxlen);
561d9c3c4c1Smarkus 			break;
562d9c3c4c1Smarkus 		}
563d9c3c4c1Smarkus 	}
564d9c3c4c1Smarkus 	if (*replace != '\0') {
56548e6b99dSdjm 		debug2_f("orig/%d    %s", ssh->kex->server, orig);
56648e6b99dSdjm 		debug2_f("replace/%d %s", ssh->kex->server, replace);
567d9c3c4c1Smarkus 		free(orig);
568d9c3c4c1Smarkus 		proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = replace;
569d9c3c4c1Smarkus 		replace = NULL;	/* owned by proposal */
570d9c3c4c1Smarkus 		r = kex_prop2buf(ssh->kex->my, proposal);
571d9c3c4c1Smarkus 	}
572d9c3c4c1Smarkus  out:
573d9c3c4c1Smarkus 	free(oavail);
574d9c3c4c1Smarkus 	free(replace);
575d9c3c4c1Smarkus 	kex_prop_free(proposal);
576d9c3c4c1Smarkus 	return r;
577d9c3c4c1Smarkus }
578d9c3c4c1Smarkus 
579d9c3c4c1Smarkus int
5808d3ff63dSdjm _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey,
5818d3ff63dSdjm     struct sshkey *pubkey, u_char **signature, size_t *slen,
5828d3ff63dSdjm     const u_char *data, size_t dlen, const char *alg)
583d9c3c4c1Smarkus {
5848d3ff63dSdjm 	return sshkey_sign(privkey, signature, slen, data, dlen,
5851f63d3c4Sdjm 	    alg, NULL, NULL, ssh->compat);
586d9c3c4c1Smarkus }
587