1 /* $OpenBSD: ssh_api.c,v 1.27 2021/04/03 06:18:41 djm Exp $ */
3 * Copyright (c) 2012 Markus Friedl. All rights reserved.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
33 #include "myproposal.h"
37 #include "openbsd-compat/openssl-compat.h"
41 int _ssh_exchange_banner(struct ssh
*);
42 int _ssh_send_banner(struct ssh
*, struct sshbuf
*);
43 int _ssh_read_banner(struct ssh
*, struct sshbuf
*);
44 int _ssh_order_hostkeyalgs(struct ssh
*);
45 int _ssh_verify_host_key(struct sshkey
*, struct ssh
*);
46 struct sshkey
*_ssh_host_public_key(int, int, struct ssh
*);
47 struct sshkey
*_ssh_host_private_key(int, int, struct ssh
*);
48 int _ssh_host_key_sign(struct ssh
*, struct sshkey
*, struct sshkey
*,
49 u_char
**, size_t *, const u_char
*, size_t, const char *);
52 * stubs for the server side implementation of kex.
53 * disable privsep so our stubs will never be called.
56 int mm_sshkey_sign(struct sshkey
*, u_char
**, u_int
*,
57 const u_char
*, u_int
, const char *, const char *, const char *, u_int
);
60 DH
*mm_choose_dh(int, int, int);
64 mm_sshkey_sign(struct sshkey
*key
, u_char
**sigp
, u_int
*lenp
,
65 const u_char
*data
, u_int datalen
, const char *alg
,
66 const char *sk_provider
, const char *sk_pin
, u_int compat
)
73 mm_choose_dh(int min
, int nbits
, int max
)
82 ssh_init(struct ssh
**sshp
, int is_server
, struct kex_params
*kex_params
)
84 char *myproposal
[PROPOSAL_MAX
] = { KEX_CLIENT
};
95 if ((ssh
= ssh_packet_set_connection(NULL
, -1, -1)) == NULL
)
96 return SSH_ERR_ALLOC_FAIL
;
98 ssh_packet_set_server(ssh
);
100 /* Initialize key exchange */
101 proposal
= kex_params
? kex_params
->proposal
: myproposal
;
102 if ((r
= kex_ready(ssh
, proposal
)) != 0) {
106 ssh
->kex
->server
= is_server
;
109 ssh
->kex
->kex
[KEX_DH_GRP1_SHA1
] = kex_gen_server
;
110 ssh
->kex
->kex
[KEX_DH_GRP14_SHA1
] = kex_gen_server
;
111 ssh
->kex
->kex
[KEX_DH_GRP14_SHA256
] = kex_gen_server
;
112 ssh
->kex
->kex
[KEX_DH_GRP16_SHA512
] = kex_gen_server
;
113 ssh
->kex
->kex
[KEX_DH_GRP18_SHA512
] = kex_gen_server
;
114 ssh
->kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_server
;
115 ssh
->kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_server
;
116 # ifdef OPENSSL_HAS_ECC
117 ssh
->kex
->kex
[KEX_ECDH_SHA2
] = kex_gen_server
;
119 #endif /* WITH_OPENSSL */
120 ssh
->kex
->kex
[KEX_C25519_SHA256
] = kex_gen_server
;
121 ssh
->kex
->kex
[KEX_KEM_SNTRUP761X25519_SHA512
] = kex_gen_server
;
122 ssh
->kex
->load_host_public_key
=&_ssh_host_public_key
;
123 ssh
->kex
->load_host_private_key
=&_ssh_host_private_key
;
124 ssh
->kex
->sign
=&_ssh_host_key_sign
;
127 ssh
->kex
->kex
[KEX_DH_GRP1_SHA1
] = kex_gen_client
;
128 ssh
->kex
->kex
[KEX_DH_GRP14_SHA1
] = kex_gen_client
;
129 ssh
->kex
->kex
[KEX_DH_GRP14_SHA256
] = kex_gen_client
;
130 ssh
->kex
->kex
[KEX_DH_GRP16_SHA512
] = kex_gen_client
;
131 ssh
->kex
->kex
[KEX_DH_GRP18_SHA512
] = kex_gen_client
;
132 ssh
->kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_client
;
133 ssh
->kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_client
;
134 # ifdef OPENSSL_HAS_ECC
135 ssh
->kex
->kex
[KEX_ECDH_SHA2
] = kex_gen_client
;
137 #endif /* WITH_OPENSSL */
138 ssh
->kex
->kex
[KEX_C25519_SHA256
] = kex_gen_client
;
139 ssh
->kex
->kex
[KEX_KEM_SNTRUP761X25519_SHA512
] = kex_gen_client
;
140 ssh
->kex
->verify_host_key
=&_ssh_verify_host_key
;
147 ssh_free(struct ssh
*ssh
)
155 * we've only created the public keys variants in case we
156 * are a acting as a server.
158 while ((k
= TAILQ_FIRST(&ssh
->public_keys
)) != NULL
) {
159 TAILQ_REMOVE(&ssh
->public_keys
, k
, next
);
160 if (ssh
->kex
&& ssh
->kex
->server
)
164 while ((k
= TAILQ_FIRST(&ssh
->private_keys
)) != NULL
) {
165 TAILQ_REMOVE(&ssh
->private_keys
, k
, next
);
168 ssh_packet_close(ssh
);
173 ssh_set_app_data(struct ssh
*ssh
, void *app_data
)
175 ssh
->app_data
= app_data
;
179 ssh_get_app_data(struct ssh
*ssh
)
181 return ssh
->app_data
;
184 /* Returns < 0 on error, 0 otherwise */
186 ssh_add_hostkey(struct ssh
*ssh
, struct sshkey
*key
)
188 struct sshkey
*pubkey
= NULL
;
189 struct key_entry
*k
= NULL
, *k_prv
= NULL
;
192 if (ssh
->kex
->server
) {
193 if ((r
= sshkey_from_private(key
, &pubkey
)) != 0)
195 if ((k
= malloc(sizeof(*k
))) == NULL
||
196 (k_prv
= malloc(sizeof(*k_prv
))) == NULL
) {
199 return SSH_ERR_ALLOC_FAIL
;
202 TAILQ_INSERT_TAIL(&ssh
->private_keys
, k_prv
, next
);
204 /* add the public key, too */
206 TAILQ_INSERT_TAIL(&ssh
->public_keys
, k
, next
);
209 if ((k
= malloc(sizeof(*k
))) == NULL
)
210 return SSH_ERR_ALLOC_FAIL
;
212 TAILQ_INSERT_TAIL(&ssh
->public_keys
, k
, next
);
220 ssh_set_verify_host_key_callback(struct ssh
*ssh
,
221 int (*cb
)(struct sshkey
*, struct ssh
*))
223 if (cb
== NULL
|| ssh
->kex
== NULL
)
224 return SSH_ERR_INVALID_ARGUMENT
;
226 ssh
->kex
->verify_host_key
= cb
;
232 ssh_input_append(struct ssh
*ssh
, const u_char
*data
, size_t len
)
234 return sshbuf_put(ssh_packet_get_input(ssh
), data
, len
);
238 ssh_packet_next(struct ssh
*ssh
, u_char
*typep
)
245 * Try to read a packet. Return SSH_MSG_NONE if no packet or not
248 *typep
= SSH_MSG_NONE
;
249 if (sshbuf_len(ssh
->kex
->client_version
) == 0 ||
250 sshbuf_len(ssh
->kex
->server_version
) == 0)
251 return _ssh_exchange_banner(ssh
);
253 * If we enough data and a dispatch function then
254 * call the function and get the next packet.
255 * Otherwise return the packet type to the caller so it
256 * can decide how to go on.
258 * We will only call the dispatch function for:
259 * 20-29 Algorithm negotiation
260 * 30-49 Key exchange method specific (numbers can be reused for
261 * different authentication methods)
264 if ((r
= ssh_packet_read_poll2(ssh
, &type
, &seqnr
)) != 0)
266 if (type
> 0 && type
< DISPATCH_MAX
&&
267 type
>= SSH2_MSG_KEXINIT
&& type
<= SSH2_MSG_TRANSPORT_MAX
&&
268 ssh
->dispatch
[type
] != NULL
) {
269 if ((r
= (*ssh
->dispatch
[type
])(type
, seqnr
, ssh
)) != 0)
279 ssh_packet_payload(struct ssh
*ssh
, size_t *lenp
)
281 return sshpkt_ptr(ssh
, lenp
);
285 ssh_packet_put(struct ssh
*ssh
, int type
, const u_char
*data
, size_t len
)
289 if ((r
= sshpkt_start(ssh
, type
)) != 0 ||
290 (r
= sshpkt_put(ssh
, data
, len
)) != 0 ||
291 (r
= sshpkt_send(ssh
)) != 0)
297 ssh_output_ptr(struct ssh
*ssh
, size_t *len
)
299 struct sshbuf
*output
= ssh_packet_get_output(ssh
);
301 *len
= sshbuf_len(output
);
302 return sshbuf_ptr(output
);
306 ssh_output_consume(struct ssh
*ssh
, size_t len
)
308 return sshbuf_consume(ssh_packet_get_output(ssh
), len
);
312 ssh_output_space(struct ssh
*ssh
, size_t len
)
314 return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh
), len
));
318 ssh_input_space(struct ssh
*ssh
, size_t len
)
320 return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh
), len
));
323 /* Read other side's version identification. */
325 _ssh_read_banner(struct ssh
*ssh
, struct sshbuf
*banner
)
327 struct sshbuf
*input
= ssh_packet_get_input(ssh
);
328 const char *mismatch
= "Protocol mismatch.\r\n";
329 const u_char
*s
= sshbuf_ptr(input
);
331 char *cp
= NULL
, *remote_version
= NULL
;
332 int r
= 0, remote_major
, remote_minor
, expect_nl
;
336 sshbuf_reset(banner
);
339 if (j
>= sshbuf_len(input
))
340 return 0; /* insufficient data in input buf */
350 if ((r
= sshbuf_put_u8(banner
, c
)) != 0)
352 if (sshbuf_len(banner
) > SSH_MAX_BANNER_LEN
)
355 if (sshbuf_len(banner
) >= 4 &&
356 memcmp(sshbuf_ptr(banner
), "SSH-", 4) == 0)
358 debug_f("%.*s", (int)sshbuf_len(banner
),
360 /* Accept lines before banner only on client */
361 if (ssh
->kex
->server
|| ++n
> SSH_MAX_PRE_BANNER_LINES
) {
363 if ((r
= sshbuf_put(ssh_packet_get_output(ssh
),
364 mismatch
, strlen(mismatch
))) != 0)
366 return SSH_ERR_NO_PROTOCOL_VERSION
;
369 if ((r
= sshbuf_consume(input
, j
)) != 0)
372 /* XXX remote version must be the same size as banner for sscanf */
373 if ((cp
= sshbuf_dup_string(banner
)) == NULL
||
374 (remote_version
= calloc(1, sshbuf_len(banner
))) == NULL
) {
375 r
= SSH_ERR_ALLOC_FAIL
;
380 * Check that the versions match. In future this might accept
381 * several versions and set appropriate flags to handle them.
383 if (sscanf(cp
, "SSH-%d.%d-%[^\n]\n",
384 &remote_major
, &remote_minor
, remote_version
) != 3) {
385 r
= SSH_ERR_INVALID_FORMAT
;
388 debug("Remote protocol version %d.%d, remote software version %.100s",
389 remote_major
, remote_minor
, remote_version
);
391 compat_banner(ssh
, remote_version
);
392 if (remote_major
== 1 && remote_minor
== 99) {
396 if (remote_major
!= 2)
397 r
= SSH_ERR_PROTOCOL_MISMATCH
;
399 debug("Remote version string %.100s", cp
);
402 free(remote_version
);
406 /* Send our own protocol version identification. */
408 _ssh_send_banner(struct ssh
*ssh
, struct sshbuf
*banner
)
413 if ((r
= sshbuf_putf(banner
, "SSH-2.0-%.100s\r\n", SSH_VERSION
)) != 0)
415 if ((r
= sshbuf_putb(ssh_packet_get_output(ssh
), banner
)) != 0)
417 /* Remove trailing \r\n */
418 if ((r
= sshbuf_consume_end(banner
, 2)) != 0)
420 if ((cp
= sshbuf_dup_string(banner
)) == NULL
)
421 return SSH_ERR_ALLOC_FAIL
;
422 debug("Local version string %.100s", cp
);
428 _ssh_exchange_banner(struct ssh
*ssh
)
430 struct kex
*kex
= ssh
->kex
;
434 * if _ssh_read_banner() cannot parse a full version string
435 * it will return NULL and we end up calling it again.
440 if (sshbuf_len(ssh
->kex
->server_version
) == 0)
441 r
= _ssh_send_banner(ssh
, ssh
->kex
->server_version
);
443 sshbuf_len(ssh
->kex
->server_version
) != 0 &&
444 sshbuf_len(ssh
->kex
->client_version
) == 0)
445 r
= _ssh_read_banner(ssh
, ssh
->kex
->client_version
);
447 if (sshbuf_len(ssh
->kex
->server_version
) == 0)
448 r
= _ssh_read_banner(ssh
, ssh
->kex
->server_version
);
450 sshbuf_len(ssh
->kex
->server_version
) != 0 &&
451 sshbuf_len(ssh
->kex
->client_version
) == 0)
452 r
= _ssh_send_banner(ssh
, ssh
->kex
->client_version
);
456 /* start initial kex as soon as we have exchanged the banners */
457 if (sshbuf_len(ssh
->kex
->server_version
) != 0 &&
458 sshbuf_len(ssh
->kex
->client_version
) != 0) {
459 if ((r
= _ssh_order_hostkeyalgs(ssh
)) != 0 ||
460 (r
= kex_send_kexinit(ssh
)) != 0)
467 _ssh_host_public_key(int type
, int nid
, struct ssh
*ssh
)
471 debug3_f("need %d", type
);
472 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
473 debug3_f("check %s", sshkey_type(k
->key
));
474 if (k
->key
->type
== type
&&
475 (type
!= KEY_ECDSA
|| k
->key
->ecdsa_nid
== nid
))
482 _ssh_host_private_key(int type
, int nid
, struct ssh
*ssh
)
486 debug3_f("need %d", type
);
487 TAILQ_FOREACH(k
, &ssh
->private_keys
, next
) {
488 debug3_f("check %s", sshkey_type(k
->key
));
489 if (k
->key
->type
== type
&&
490 (type
!= KEY_ECDSA
|| k
->key
->ecdsa_nid
== nid
))
497 _ssh_verify_host_key(struct sshkey
*hostkey
, struct ssh
*ssh
)
501 debug3_f("need %s", sshkey_type(hostkey
));
502 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
503 debug3_f("check %s", sshkey_type(k
->key
));
504 if (sshkey_equal_public(hostkey
, k
->key
))
507 return (-1); /* failed */
510 /* offer hostkey algorithms in kexinit depending on registered keys */
512 _ssh_order_hostkeyalgs(struct ssh
*ssh
)
515 char *orig
, *avail
, *oavail
= NULL
, *alg
, *replace
= NULL
;
520 /* XXX we de-serialize ssh->kex->my, modify it, and change it */
521 if ((r
= kex_buf2prop(ssh
->kex
->my
, NULL
, &proposal
)) != 0)
523 orig
= proposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
];
524 if ((oavail
= avail
= strdup(orig
)) == NULL
) {
525 r
= SSH_ERR_ALLOC_FAIL
;
528 maxlen
= strlen(avail
) + 1;
529 if ((replace
= calloc(1, maxlen
)) == NULL
) {
530 r
= SSH_ERR_ALLOC_FAIL
;
534 while ((alg
= strsep(&avail
, ",")) && *alg
!= '\0') {
535 if ((ktype
= sshkey_type_from_name(alg
)) == KEY_UNSPEC
)
537 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
538 if (k
->key
->type
== ktype
||
539 (sshkey_is_cert(k
->key
) && k
->key
->type
==
540 sshkey_type_plain(ktype
))) {
541 if (*replace
!= '\0')
542 strlcat(replace
, ",", maxlen
);
543 strlcat(replace
, alg
, maxlen
);
548 if (*replace
!= '\0') {
549 debug2_f("orig/%d %s", ssh
->kex
->server
, orig
);
550 debug2_f("replace/%d %s", ssh
->kex
->server
, replace
);
552 proposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = replace
;
553 replace
= NULL
; /* owned by proposal */
554 r
= kex_prop2buf(ssh
->kex
->my
, proposal
);
559 kex_prop_free(proposal
);
564 _ssh_host_key_sign(struct ssh
*ssh
, struct sshkey
*privkey
,
565 struct sshkey
*pubkey
, u_char
**signature
, size_t *slen
,
566 const u_char
*data
, size_t dlen
, const char *alg
)
568 return sshkey_sign(privkey
, signature
, slen
, data
, dlen
,
569 alg
, NULL
, NULL
, ssh
->compat
);