1 /* $OpenBSD: ssh_api.c,v 1.8 2017/04/30 23:13:25 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.
28 #include "myproposal.h"
34 int _ssh_exchange_banner(struct ssh
*);
35 int _ssh_send_banner(struct ssh
*, char **);
36 int _ssh_read_banner(struct ssh
*, char **);
37 int _ssh_order_hostkeyalgs(struct ssh
*);
38 int _ssh_verify_host_key(struct sshkey
*, struct ssh
*);
39 struct sshkey
*_ssh_host_public_key(int, int, struct ssh
*);
40 struct sshkey
*_ssh_host_private_key(int, int, struct ssh
*);
41 int _ssh_host_key_sign(struct sshkey
*, struct sshkey
*,
42 u_char
**, size_t *, const u_char
*, size_t, const char *, u_int
);
45 * stubs for the server side implementation of kex.
46 * disable privsep so our stubs will never be called.
49 int mm_sshkey_sign(struct sshkey
*, u_char
**, u_int
*,
50 u_char
*, u_int
, char *, u_int
);
51 DH
*mm_choose_dh(int, int, int);
53 /* Define these two variables here so that they are part of the library */
54 u_char
*session_id2
= NULL
;
55 u_int session_id2_len
= 0;
58 mm_sshkey_sign(struct sshkey
*key
, u_char
**sigp
, u_int
*lenp
,
59 u_char
*data
, u_int datalen
, char *alg
, u_int compat
)
65 mm_choose_dh(int min
, int nbits
, int max
)
73 ssh_init(struct ssh
**sshp
, int is_server
, struct kex_params
*kex_params
)
75 char *myproposal
[PROPOSAL_MAX
] = { KEX_CLIENT
};
83 OpenSSL_add_all_algorithms();
84 #endif /* WITH_OPENSSL */
88 if ((ssh
= ssh_packet_set_connection(NULL
, -1, -1)) == NULL
)
89 return SSH_ERR_ALLOC_FAIL
;
91 ssh_packet_set_server(ssh
);
93 /* Initialize key exchange */
94 proposal
= kex_params
? kex_params
->proposal
: myproposal
;
95 if ((r
= kex_new(ssh
, proposal
, &ssh
->kex
)) != 0) {
99 ssh
->kex
->server
= is_server
;
102 ssh
->kex
->kex
[KEX_DH_GRP1_SHA1
] = kexdh_server
;
103 ssh
->kex
->kex
[KEX_DH_GRP14_SHA1
] = kexdh_server
;
104 ssh
->kex
->kex
[KEX_DH_GRP14_SHA256
] = kexdh_server
;
105 ssh
->kex
->kex
[KEX_DH_GRP16_SHA512
] = kexdh_server
;
106 ssh
->kex
->kex
[KEX_DH_GRP18_SHA512
] = kexdh_server
;
107 ssh
->kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_server
;
108 ssh
->kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_server
;
109 # ifdef OPENSSL_HAS_ECC
110 ssh
->kex
->kex
[KEX_ECDH_SHA2
] = kexecdh_server
;
112 #endif /* WITH_OPENSSL */
113 ssh
->kex
->kex
[KEX_C25519_SHA256
] = kexc25519_server
;
114 ssh
->kex
->load_host_public_key
=&_ssh_host_public_key
;
115 ssh
->kex
->load_host_private_key
=&_ssh_host_private_key
;
116 ssh
->kex
->sign
=&_ssh_host_key_sign
;
119 ssh
->kex
->kex
[KEX_DH_GRP1_SHA1
] = kexdh_client
;
120 ssh
->kex
->kex
[KEX_DH_GRP14_SHA1
] = kexdh_client
;
121 ssh
->kex
->kex
[KEX_DH_GRP14_SHA256
] = kexdh_client
;
122 ssh
->kex
->kex
[KEX_DH_GRP16_SHA512
] = kexdh_client
;
123 ssh
->kex
->kex
[KEX_DH_GRP18_SHA512
] = kexdh_client
;
124 ssh
->kex
->kex
[KEX_DH_GEX_SHA1
] = kexgex_client
;
125 ssh
->kex
->kex
[KEX_DH_GEX_SHA256
] = kexgex_client
;
126 # ifdef OPENSSL_HAS_ECC
127 ssh
->kex
->kex
[KEX_ECDH_SHA2
] = kexecdh_client
;
129 #endif /* WITH_OPENSSL */
130 ssh
->kex
->kex
[KEX_C25519_SHA256
] = kexc25519_client
;
131 ssh
->kex
->verify_host_key
=&_ssh_verify_host_key
;
138 ssh_free(struct ssh
*ssh
)
142 ssh_packet_close(ssh
);
144 * we've only created the public keys variants in case we
145 * are a acting as a server.
147 while ((k
= TAILQ_FIRST(&ssh
->public_keys
)) != NULL
) {
148 TAILQ_REMOVE(&ssh
->public_keys
, k
, next
);
149 if (ssh
->kex
&& ssh
->kex
->server
)
153 while ((k
= TAILQ_FIRST(&ssh
->private_keys
)) != NULL
) {
154 TAILQ_REMOVE(&ssh
->private_keys
, k
, next
);
163 ssh_set_app_data(struct ssh
*ssh
, void *app_data
)
165 ssh
->app_data
= app_data
;
169 ssh_get_app_data(struct ssh
*ssh
)
171 return ssh
->app_data
;
174 /* Returns < 0 on error, 0 otherwise */
176 ssh_add_hostkey(struct ssh
*ssh
, struct sshkey
*key
)
178 struct sshkey
*pubkey
= NULL
;
179 struct key_entry
*k
= NULL
, *k_prv
= NULL
;
182 if (ssh
->kex
->server
) {
183 if ((r
= sshkey_from_private(key
, &pubkey
)) != 0)
185 if ((k
= malloc(sizeof(*k
))) == NULL
||
186 (k_prv
= malloc(sizeof(*k_prv
))) == NULL
) {
189 return SSH_ERR_ALLOC_FAIL
;
192 TAILQ_INSERT_TAIL(&ssh
->private_keys
, k_prv
, next
);
194 /* add the public key, too */
196 TAILQ_INSERT_TAIL(&ssh
->public_keys
, k
, next
);
199 if ((k
= malloc(sizeof(*k
))) == NULL
)
200 return SSH_ERR_ALLOC_FAIL
;
202 TAILQ_INSERT_TAIL(&ssh
->public_keys
, k
, next
);
210 ssh_set_verify_host_key_callback(struct ssh
*ssh
,
211 int (*cb
)(struct sshkey
*, struct ssh
*))
213 if (cb
== NULL
|| ssh
->kex
== NULL
)
214 return SSH_ERR_INVALID_ARGUMENT
;
216 ssh
->kex
->verify_host_key
= cb
;
222 ssh_input_append(struct ssh
*ssh
, const u_char
*data
, size_t len
)
224 return sshbuf_put(ssh_packet_get_input(ssh
), data
, len
);
228 ssh_packet_next(struct ssh
*ssh
, u_char
*typep
)
235 * Try to read a packet. Return SSH_MSG_NONE if no packet or not
238 *typep
= SSH_MSG_NONE
;
239 if (ssh
->kex
->client_version_string
== NULL
||
240 ssh
->kex
->server_version_string
== NULL
)
241 return _ssh_exchange_banner(ssh
);
243 * If we enough data and a dispatch function then
244 * call the function and get the next packet.
245 * Otherwise return the packet type to the caller so it
246 * can decide how to go on.
248 * We will only call the dispatch function for:
249 * 20-29 Algorithm negotiation
250 * 30-49 Key exchange method specific (numbers can be reused for
251 * different authentication methods)
254 if ((r
= ssh_packet_read_poll2(ssh
, &type
, &seqnr
)) != 0)
256 if (type
> 0 && type
< DISPATCH_MAX
&&
257 type
>= SSH2_MSG_KEXINIT
&& type
<= SSH2_MSG_TRANSPORT_MAX
&&
258 ssh
->dispatch
[type
] != NULL
) {
259 if ((r
= (*ssh
->dispatch
[type
])(type
, seqnr
, ssh
)) != 0)
269 ssh_packet_payload(struct ssh
*ssh
, size_t *lenp
)
271 return sshpkt_ptr(ssh
, lenp
);
275 ssh_packet_put(struct ssh
*ssh
, int type
, const u_char
*data
, size_t len
)
279 if ((r
= sshpkt_start(ssh
, type
)) != 0 ||
280 (r
= sshpkt_put(ssh
, data
, len
)) != 0 ||
281 (r
= sshpkt_send(ssh
)) != 0)
287 ssh_output_ptr(struct ssh
*ssh
, size_t *len
)
289 struct sshbuf
*output
= ssh_packet_get_output(ssh
);
291 *len
= sshbuf_len(output
);
292 return sshbuf_ptr(output
);
296 ssh_output_consume(struct ssh
*ssh
, size_t len
)
298 return sshbuf_consume(ssh_packet_get_output(ssh
), len
);
302 ssh_output_space(struct ssh
*ssh
, size_t len
)
304 return (0 == sshbuf_check_reserve(ssh_packet_get_output(ssh
), len
));
308 ssh_input_space(struct ssh
*ssh
, size_t len
)
310 return (0 == sshbuf_check_reserve(ssh_packet_get_input(ssh
), len
));
313 /* Read other side's version identification. */
315 _ssh_read_banner(struct ssh
*ssh
, char **bannerp
)
317 struct sshbuf
*input
;
319 char buf
[256], remote_version
[256]; /* must be same size! */
320 const char *mismatch
= "Protocol mismatch.\r\n";
321 int r
, remote_major
, remote_minor
;
325 input
= ssh_packet_get_input(ssh
);
326 len
= sshbuf_len(input
);
327 s
= (const char *)sshbuf_ptr(input
);
329 for (i
= 0; i
< sizeof(buf
) - 1; i
++) {
333 if (buf
[i
] == '\r') {
336 continue; /**XXX wait for \n */
338 if (buf
[i
] == '\n') {
343 buf
[sizeof(buf
) - 1] = 0;
344 if (strncmp(buf
, "SSH-", 4) == 0)
346 debug("ssh_exchange_identification: %s", buf
);
347 if (ssh
->kex
->server
|| ++n
> 65536) {
348 if ((r
= sshbuf_put(ssh_packet_get_output(ssh
),
349 mismatch
, strlen(mismatch
))) != 0)
351 return SSH_ERR_NO_PROTOCOL_VERSION
;
354 if ((r
= sshbuf_consume(input
, j
)) != 0)
358 * Check that the versions match. In future this might accept
359 * several versions and set appropriate flags to handle them.
361 if (sscanf(buf
, "SSH-%d.%d-%[^\n]\n",
362 &remote_major
, &remote_minor
, remote_version
) != 3)
363 return SSH_ERR_INVALID_FORMAT
;
364 debug("Remote protocol version %d.%d, remote software version %.100s",
365 remote_major
, remote_minor
, remote_version
);
367 ssh
->compat
= compat_datafellows(remote_version
);
368 if (remote_major
== 1 && remote_minor
== 99) {
372 if (remote_major
!= 2)
373 return SSH_ERR_PROTOCOL_MISMATCH
;
375 debug("Remote version string %.100s", buf
);
376 if ((*bannerp
= strdup(buf
)) == NULL
)
377 return SSH_ERR_ALLOC_FAIL
;
381 /* Send our own protocol version identification. */
383 _ssh_send_banner(struct ssh
*ssh
, char **bannerp
)
388 snprintf(buf
, sizeof buf
, "SSH-2.0-%.100s\r\n", SSH_VERSION
);
389 if ((r
= sshbuf_put(ssh_packet_get_output(ssh
), buf
, strlen(buf
))) != 0)
392 debug("Local version string %.100s", buf
);
393 if ((*bannerp
= strdup(buf
)) == NULL
)
394 return SSH_ERR_ALLOC_FAIL
;
399 _ssh_exchange_banner(struct ssh
*ssh
)
401 struct kex
*kex
= ssh
->kex
;
405 * if _ssh_read_banner() cannot parse a full version string
406 * it will return NULL and we end up calling it again.
411 if (kex
->server_version_string
== NULL
)
412 r
= _ssh_send_banner(ssh
, &kex
->server_version_string
);
414 kex
->server_version_string
!= NULL
&&
415 kex
->client_version_string
== NULL
)
416 r
= _ssh_read_banner(ssh
, &kex
->client_version_string
);
418 if (kex
->server_version_string
== NULL
)
419 r
= _ssh_read_banner(ssh
, &kex
->server_version_string
);
421 kex
->server_version_string
!= NULL
&&
422 kex
->client_version_string
== NULL
)
423 r
= _ssh_send_banner(ssh
, &kex
->client_version_string
);
427 /* start initial kex as soon as we have exchanged the banners */
428 if (kex
->server_version_string
!= NULL
&&
429 kex
->client_version_string
!= NULL
) {
430 if ((r
= _ssh_order_hostkeyalgs(ssh
)) != 0 ||
431 (r
= kex_send_kexinit(ssh
)) != 0)
438 _ssh_host_public_key(int type
, int nid
, struct ssh
*ssh
)
442 debug3("%s: need %d", __func__
, type
);
443 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
444 debug3("%s: check %s", __func__
, sshkey_type(k
->key
));
445 if (k
->key
->type
== type
&&
446 (type
!= KEY_ECDSA
|| k
->key
->ecdsa_nid
== nid
))
453 _ssh_host_private_key(int type
, int nid
, struct ssh
*ssh
)
457 debug3("%s: need %d", __func__
, type
);
458 TAILQ_FOREACH(k
, &ssh
->private_keys
, next
) {
459 debug3("%s: check %s", __func__
, sshkey_type(k
->key
));
460 if (k
->key
->type
== type
&&
461 (type
!= KEY_ECDSA
|| k
->key
->ecdsa_nid
== nid
))
468 _ssh_verify_host_key(struct sshkey
*hostkey
, struct ssh
*ssh
)
472 debug3("%s: need %s", __func__
, sshkey_type(hostkey
));
473 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
474 debug3("%s: check %s", __func__
, sshkey_type(k
->key
));
475 if (sshkey_equal_public(hostkey
, k
->key
))
478 return (-1); /* failed */
481 /* offer hostkey algorithms in kexinit depending on registered keys */
483 _ssh_order_hostkeyalgs(struct ssh
*ssh
)
486 char *orig
, *avail
, *oavail
= NULL
, *alg
, *replace
= NULL
;
491 /* XXX we de-serialize ssh->kex->my, modify it, and change it */
492 if ((r
= kex_buf2prop(ssh
->kex
->my
, NULL
, &proposal
)) != 0)
494 orig
= proposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
];
495 if ((oavail
= avail
= strdup(orig
)) == NULL
) {
496 r
= SSH_ERR_ALLOC_FAIL
;
499 maxlen
= strlen(avail
) + 1;
500 if ((replace
= calloc(1, maxlen
)) == NULL
) {
501 r
= SSH_ERR_ALLOC_FAIL
;
505 while ((alg
= strsep(&avail
, ",")) && *alg
!= '\0') {
506 if ((ktype
= sshkey_type_from_name(alg
)) == KEY_UNSPEC
)
508 TAILQ_FOREACH(k
, &ssh
->public_keys
, next
) {
509 if (k
->key
->type
== ktype
||
510 (sshkey_is_cert(k
->key
) && k
->key
->type
==
511 sshkey_type_plain(ktype
))) {
512 if (*replace
!= '\0')
513 strlcat(replace
, ",", maxlen
);
514 strlcat(replace
, alg
, maxlen
);
519 if (*replace
!= '\0') {
520 debug2("%s: orig/%d %s", __func__
, ssh
->kex
->server
, orig
);
521 debug2("%s: replace/%d %s", __func__
, ssh
->kex
->server
, replace
);
523 proposal
[PROPOSAL_SERVER_HOST_KEY_ALGS
] = replace
;
524 replace
= NULL
; /* owned by proposal */
525 r
= kex_prop2buf(ssh
->kex
->my
, proposal
);
530 kex_prop_free(proposal
);
535 _ssh_host_key_sign(struct sshkey
*privkey
, struct sshkey
*pubkey
,
536 u_char
**signature
, size_t *slen
, const u_char
*data
, size_t dlen
,
537 const char *alg
, u_int compat
)
539 return sshkey_sign(privkey
, signature
, slen
, data
, dlen
, alg
, compat
);