blob: 175577bf98eea1e1ce3b540d8f744fbda7e29640 [file] [log] [blame]
Michal Vaskoba9f3582023-02-22 10:26:32 +01001/**
2 * @file test_client_ssh.c
3 * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
4 * @brief client SSH test
5 *
6 * Copyright (c) 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#define _GNU_SOURCE
16
Michal Vaskob83a3fa2021-05-26 09:53:42 +020017#include <errno.h>
18#include <setjmp.h>
David Sedlákddde4492018-09-30 21:34:38 +020019#include <stdio.h>
20#include <stdlib.h>
David Sedlákddde4492018-09-30 21:34:38 +020021#include <sys/socket.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020022#include <sys/types.h>
David Sedlákddde4492018-09-30 21:34:38 +020023
24#include <cmocka.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020025#include <config.h>
romanc1d2b092023-02-02 08:58:27 +010026#include <config_server.h>
David Sedlákddde4492018-09-30 21:34:38 +020027#include <libyang/libyang.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020028#include <log.h>
David Sedlákddde4492018-09-30 21:34:38 +020029#include <session_client.h>
Fred Gan3a736e02021-01-04 17:59:38 +080030#include <session_client_ch.h>
31#include <session_p.h>
David Sedlákddde4492018-09-30 21:34:38 +020032#include "tests/config.h"
33
David Sedlákddde4492018-09-30 21:34:38 +020034#include <libssh/callbacks.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020035#include <libssh/libssh.h>
David Sedlákddde4492018-09-30 21:34:38 +020036#include <libssh/server.h>
37
romanc1d2b092023-02-02 08:58:27 +010038const char *data =
39 "<netconf-server xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-server\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
40 " <listen yang:operation=\"create\">\n"
41 " <idle-timeout>10</idle-timeout>\n"
42 " <endpoint>\n"
43 " <name>default-ssh</name>\n"
44 " <ssh>\n"
45 " <tcp-server-parameters>\n"
46 " <local-address>127.0.0.1</local-address>\n"
47 " <local-port>10005</local-port>\n"
48 " </tcp-server-parameters>\n"
49 " <ssh-server-parameters>\n"
50 " <server-identity>\n"
51 " <host-key>\n"
52 " <name>key</name>\n"
53 " <public-key>\n"
54 " <local-definition>\n"
55 " <public-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:ssh-public-key-format</public-key-format>\n"
56 " <public-key>MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==</public-key>\n"
57 " <private-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:rsa-private-key-format</private-key-format>\n"
58 " <cleartext-private-key>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</cleartext-private-key>\n"
59 " </local-definition>\n"
60 " </public-key>\n"
61 " </host-key>\n"
62 " </server-identity>\n"
63 " <client-authentication>\n"
64 " <users>\n"
65 " <user>\n"
66 " <name>test</name>\n"
67 " <public-keys>\n"
68 " <local-definition>\n"
69 " <public-key>\n"
70 " <name>client</name>\n"
71 " <public-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:ssh-public-key-format</public-key-format>\n"
72 " <public-key>AAAAB3NzaC1yc2EAAAADAQABAAABAQDPavVALiM7QwTIUAndO8E9GOkSDQWjuEwkzbJ3kOBPa7kkq71UOZFeecDjFb9eipkljfFys/JYHGQaYVF8/svT0KV5h7HlutRdF6yvqSEbjpbTORb27pdHX3iFEyDCwCIoq9vMeX+wyXnteyn01GpIL0ig0WAnvkqX/SPjuplX5ZItUSr0MhXM7fNSX50BD6G8IO0/djUcdMUcjTjGv73SxB9ZzLvxnhXuUJbzEJJJLj6qajyEIVaJSa73vA33JCD8qzarrsuITojVLPDFmeHwSAoB5dP86yop6e6ypuXzKxxef6yNXcE8oTj8UFYBIXsgIP2nBvWk41EaK0Vk3YFl</public-key>\n"
73 " </public-key>\n"
74 " </local-definition>\n"
75 " </public-keys>\n"
76 " </user>\n"
77 " </users>\n"
78 " </client-authentication>\n"
79 " <transport-params>\n"
80 " <host-key>\n"
81 " <host-key-alg xmlns:sshpka=\"urn:ietf:params:xml:ns:yang:iana-ssh-public-key-algs\">sshpka:rsa-sha2-512</host-key-alg>\n"
82 " </host-key>\n"
83 " <key-exchange>\n"
84 " <key-exchange-alg xmlns:sshkea=\"urn:ietf:params:xml:ns:yang:iana-ssh-key-exchange-algs\">sshkea:curve25519-sha256</key-exchange-alg>\n"
85 " </key-exchange>\n"
86 " <encryption>\n"
87 " <encryption-alg xmlns:sshea=\"urn:ietf:params:xml:ns:yang:iana-ssh-encryption-algs\">sshea:aes256-ctr</encryption-alg>\n"
88 " </encryption>\n"
89 " <mac>\n"
90 " <mac-alg xmlns:sshma=\"urn:ietf:params:xml:ns:yang:iana-ssh-mac-algs\">sshma:hmac-sha2-512</mac-alg>\n"
91 " </mac>\n"
92 " </transport-params>\n"
93 " </ssh-server-parameters>\n"
94 " </ssh>\n"
95 " </endpoint>\n"
96 " </listen>\n"
97 "</netconf-server>\n";
98
David Sedlákddde4492018-09-30 21:34:38 +020099static int
100ssh_hostkey_check_clb(const char *hostname, ssh_session session, void *priv)
101{
102 (void)hostname;
103 (void)session;
104 (void)priv;
105
106 return 0;
107}
108
109static int
110setup_f(void **state)
111{
112 (void)state;
113 int ret;
114
115 nc_verbosity(NC_VERB_VERBOSE);
116
117 ret = nc_client_ssh_set_username("username");
118 assert_int_equal(ret, 0);
Fred Gan3a736e02021-01-04 17:59:38 +0800119 ret = nc_client_ssh_ch_set_username("ch_username");
120 assert_int_equal(ret, 0);
David Sedlákddde4492018-09-30 21:34:38 +0200121 nc_client_ssh_set_auth_hostkey_check_clb(ssh_hostkey_check_clb, NULL);
122
123 return 0;
124}
125
126static int
127teardown_f(void **state)
128{
129 (void)state;
130 return 0;
131}
132
133MOCK int
134__wrap_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
135{
136 (void)sockfd;
137 (void)addr;
138 (void)addrlen;
139
140 return (int)mock();
141}
142
143MOCK int
144__wrap_ssh_connect(ssh_session session)
145{
146 (void)session;
147
148 /* set support of all authentication methods by fake server */
149 ssh_set_auth_methods(session, SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_INTERACTIVE);
150 return (int)mock();
151}
152
153MOCK int
154__wrap_ssh_userauth_none(ssh_session session, const char *username)
155{
156 (void)session;
157 (void)username;
158
159 return (int)mock();
160}
161
162MOCK int
163__wrap_ssh_userauth_kbdint(ssh_session session, const char *user, const char *submethods)
164{
165 (void)session;
166 (void)user;
167 (void)submethods;
168
169 return (int)mock();
170}
171
172MOCK int
173__wrap_ssh_is_connected(ssh_session session)
174{
175 (void)session;
176
177 return (int)mock();
178}
179
180MOCK int
181__wrap_ssh_channel_open_session(ssh_channel channel)
182{
183 (void)channel;
184
185 return (int)mock();
186}
187
188MOCK int
189__wrap_ssh_channel_request_subsystem(ssh_channel channel, const char *subsystem)
190{
191 (void)channel;
192 (void)subsystem;
193
194 return (int)mock();
195}
196
197MOCK int
198__wrap_ssh_channel_is_closed(ssh_channel channel)
199{
200 (void)channel;
201
202 return 0;
203}
204
205MOCK int
206__wrap_ssh_channel_write(ssh_channel channel, const void *data, uint32_t len)
207{
208 (void)channel;
209 (void)data;
210
211 return len;
212}
213
214MOCK int
215__wrap_ssh_channel_poll_timeout(ssh_channel channel, int timeout, int is_stderr)
216{
217 (void)channel;
218 (void)timeout;
219 (void)is_stderr;
220
221 return (int)mock();
222}
223
224MOCK int
225__wrap_ssh_userauth_password(ssh_session session, const char *username, const char *password)
226{
227 (void)session;
228 check_expected(password);
229 check_expected(username);
230
David Sedlákddde4492018-09-30 21:34:38 +0200231 return (int)mock();
232}
233
234MOCK int
235__wrap_nc_handshake_io(struct nc_session *session)
236{
237 (void)session;
238
239 return (int)mock();
240}
241
242MOCK int
243__wrap_nc_ctx_check_and_fill(struct nc_session *session)
244{
245 (void)session;
246
247 return (int)mock();
248}
249
David Sedlák77acc202018-10-08 21:44:14 +0200250MOCK int
251__wrap_ssh_userauth_try_publickey(ssh_session session, const char *username, const ssh_key pubkey)
252{
253 (void)session;
254 (void)username;
255 (void)pubkey;
256
257 return (int)mock();
258}
259
260MOCK int
261__wrap_ssh_userauth_publickey(ssh_session session, const char *username, const ssh_key privkey)
262{
263 (void)session;
264 (void)username;
265 (void)privkey;
266
267 return (int)mock();
268}
269
Fred Gan3a736e02021-01-04 17:59:38 +0800270MOCK int
271__wrap_nc_sock_listen_inet(const char *address, uint16_t port, struct nc_keepalives *ka)
272{
273 (void)address;
274 (void)port;
275 (void)ka;
276
277 return (int)mock();
278}
279
280MOCK int
281__wrap_nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx)
282{
283 (void)binds;
284 (void)bind_count;
285 (void)timeout;
286 (void)host;
287 (void)port;
288
289 *idx = 0;
290 return (int)mock();
291}
292
293MOCK struct nc_session *
294__wrap_nc_accept_callhome_ssh_sock(int sock, const char *host, uint16_t port, struct ly_ctx *ctx, int timeout)
295{
296 (void)sock;
297 (void)host;
298 (void)port;
299 (void)ctx;
300 (void)timeout;
301
302 return mock_ptr_type(struct nc_session *);
303}
304
David Sedlákddde4492018-09-30 21:34:38 +0200305static int
306test_hostkey_clb(const char *hostname, ssh_session session, void *priv)
307{
308 (void)hostname;
309 (void)session;
310 (void)priv;
311
312 return 0;
313}
314
315static void
316test_nc_client_ssh_setting_auth_hostkey_check_clb(void **state)
317{
318 (void)state;
319 int (*ret_f)(const char *hostname, ssh_session session, void *priv);
320 char *priv_data_ret;
321
322 /* ssh_hostkey_check_clb is set in setup_f */
323 nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
324 assert_ptr_equal(ret_f, ssh_hostkey_check_clb);
325 assert_null(priv_data_ret);
326
327 /* set different callback and private data */
328 nc_client_ssh_set_auth_hostkey_check_clb(test_hostkey_clb, "DATA");
329 nc_client_ssh_get_auth_hostkey_check_clb(&ret_f, (void **)&priv_data_ret);
330 assert_ptr_equal(ret_f, test_hostkey_clb);
331 assert_string_equal(priv_data_ret, "DATA");
332}
333
334char *
335test_pwd_clb1(const char *username, const char *hostname, void *priv)
336{
337 char *pass, *pass_to_return;
338
339 check_expected(username);
340 check_expected(hostname);
341 check_expected(priv);
342
343 pass = (char *)mock();
344 pass_to_return = malloc(sizeof *pass * (strlen(pass) + 1));
345 strcpy(pass_to_return, pass);
346
347 return pass_to_return;
348}
349
350char *
351test_pwd_clb2(const char *username, const char *hostname, void *priv)
352{
353 (void)username;
354 (void)hostname;
355 (void)priv;
356
357 return 0;
358}
359
360static void
361test_nc_client_ssh_setting_auth_password_clb(void **state)
362{
363 (void)state;
364 char *(*ret_f)(const char *username, const char *hostname, void *priv);
365 char *priv_data_ret;
366
367 /* set callback */
368 nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "DATA");
369 nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
370 assert_ptr_equal(test_pwd_clb1, ret_f);
371 assert_string_equal("DATA", priv_data_ret);
372
373 /* set different callback */
374 nc_client_ssh_set_auth_password_clb(test_pwd_clb2, "NEW DATA");
375 nc_client_ssh_get_auth_password_clb(&ret_f, (void **)&priv_data_ret);
376 assert_ptr_equal(test_pwd_clb2, ret_f);
377 assert_string_equal("NEW DATA", priv_data_ret);
378}
379
380char *
381test_inter_clb1(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
382{
383 (void)auth_name;
384 (void)instruction;
385 (void)prompt;
386 (void)echo;
387 (void)priv;
388
389 return 0;
390}
391
392char *
393test_inter_clb2(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv)
394{
395 (void)auth_name;
396 (void)instruction;
397 (void)prompt;
398 (void)echo;
399 (void)priv;
400
401 return 0;
402}
403
404static void
405test_nc_client_ssh_setting_auth_interactive_clb(void **state)
406{
407 (void)state;
408 char *(*ret_f)(const char *auth_name, const char *instruction, const char *prompt, int echo, void *priv);
409 char *priv_data_ret;
410
411 /* set callback */
412 nc_client_ssh_set_auth_interactive_clb(test_inter_clb1, "DATA");
413 nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
414 assert_ptr_equal(test_inter_clb1, ret_f);
415 assert_string_equal("DATA", priv_data_ret);
416
417 /* set diferent callback */
418 nc_client_ssh_set_auth_interactive_clb(test_inter_clb2, "NEW DATA");
419 nc_client_ssh_get_auth_interactive_clb(&ret_f, (void **)&priv_data_ret);
420 assert_ptr_equal(test_inter_clb2, ret_f);
421 assert_string_equal("NEW DATA", priv_data_ret);
422}
423
424char *
425test_passphrase_clb1(const char *privkey_path, void *priv)
426{
427 (void)privkey_path;
428 (void)priv;
429
430 return 0;
431}
432
433char *
434test_passphrase_clb2(const char *privkey_path, void *priv)
435{
436 (void)privkey_path;
437 (void)priv;
438
439 return 0;
440}
441
442static void
443test_nc_client_ssh_setting_auth_privkey_passphrase_clb(void **state)
444{
445 (void)state;
446 char *(*ret_f)(const char *privkey_path, void *priv);
447 char *priv_data_ret;
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200448
David Sedlákddde4492018-09-30 21:34:38 +0200449 /* set first callback */
450 nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb1, "DATA");
451 nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
452 assert_ptr_equal(ret_f, test_passphrase_clb1);
453 assert_string_equal("DATA", priv_data_ret);
454
455 /* set different callback */
456 nc_client_ssh_set_auth_privkey_passphrase_clb(test_passphrase_clb2, "NEW DATA");
457 nc_client_ssh_get_auth_privkey_passphrase_clb(&ret_f, (void **)&priv_data_ret);
458 assert_ptr_equal(ret_f, test_passphrase_clb2);
459 assert_string_equal("NEW DATA", priv_data_ret);
460}
461
462static void
463test_nc_client_ssh_adding_keypair(void **state)
464{
465 (void)state;
466 int ret;
467 const char *pubkey1, *pubkey2;
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200468
David Sedlákddde4492018-09-30 21:34:38 +0200469 /* at the beginning keypair count should be 0 */
470 ret = nc_client_ssh_get_keypair_count();
471 assert_int_equal(ret, 0);
472
473 /* add first key pair */
Michal Vasko7a4213f2022-09-08 11:02:34 +0200474 ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_ecdsa.pub", TESTS_DIR "/data/key_ecdsa");
David Sedlákddde4492018-09-30 21:34:38 +0200475 assert_int_equal(ret, 0);
476 ret = nc_client_ssh_get_keypair_count();
477 assert_int_equal(ret, 1);
478
479 /* add second keypair */
480 ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
481 assert_int_equal(ret, 0);
482 ret = nc_client_ssh_get_keypair_count();
483 assert_int_equal(ret, 2);
484 ret = nc_client_ssh_get_keypair(1, &pubkey1, &pubkey2);
485 assert_int_equal(ret, 0);
486 assert_string_equal(pubkey1, "key_pub");
487 assert_string_equal(pubkey2, "key_priv");
488
489 /* delete first keypair */
490 ret = nc_client_ssh_del_keypair(0);
491 assert_int_equal(ret, 0);
492 ret = nc_client_ssh_get_keypair_count();
493 assert_int_equal(ret, 1);
494 /* try to get deleted keypair */
495 ret = nc_client_ssh_get_keypair(5, &pubkey1, &pubkey2);
496 assert_int_equal(ret, -1);
497
498 /* try to add keypair that is already set */
499 ret = nc_client_ssh_add_keypair("key_pub", "key_priv");
500 assert_int_equal(ret, -1);
501 ret = nc_client_ssh_get_keypair_count();
502 assert_int_equal(ret, 1);
503
504 /* try to delete keypair with id that is not used */
505 ret = nc_client_ssh_del_keypair(42);
506 assert_int_equal(ret, -1);
507 ret = nc_client_ssh_get_keypair_count();
508 assert_int_equal(ret, 1);
509
510 /* remove remaining keypairs */
511 ret = nc_client_ssh_del_keypair(0);
512 assert_int_equal(ret, 0);
513 ret = nc_client_ssh_get_keypair_count();
514 assert_int_equal(ret, 0);
515}
516
517static void
518test_nc_client_ssh_setting_auth_pref(void **state)
519{
520 (void)state;
521 int ret;
522
David Sedlákaae4df32018-10-08 22:27:22 +0200523 /* initiate client, must be called in first test */
David Sedlákddde4492018-09-30 21:34:38 +0200524 nc_client_init();
525
526 /* check default prefference settings according to documentation */
527 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
roman41a11e42022-06-22 09:27:08 +0200528 assert_int_equal(ret, 1);
David Sedlákddde4492018-09-30 21:34:38 +0200529 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
530 assert_int_equal(ret, 2);
531 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
roman41a11e42022-06-22 09:27:08 +0200532 assert_int_equal(ret, 3);
David Sedlákddde4492018-09-30 21:34:38 +0200533
534 /* try to set prefetence of non existing method */
535 nc_client_ssh_set_auth_pref(42, 22);
536
537 /* try to get preference of non existing method */
538 ret = nc_client_ssh_get_auth_pref(42);
539 assert_int_equal(ret, 0);
540
541 /* change values of all methods and check if they actually changed */
542 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 9);
543 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_INTERACTIVE);
544 assert_int_equal(ret, 9);
545
546 /* negative value should be set as -1 */
547 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -5);
548 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PASSWORD);
549 assert_int_equal(ret, -1);
550
551 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 11);
552 ret = nc_client_ssh_get_auth_pref(NC_SSH_AUTH_PUBLICKEY);
553 assert_int_equal(ret, 11);
554}
555
556static void
557test_nc_client_ssh_setting_username(void **state)
558{
559 (void)state;
560 int ret;
561 const char *username_ret;
Michal Vaskob83a3fa2021-05-26 09:53:42 +0200562
David Sedlákddde4492018-09-30 21:34:38 +0200563 username_ret = nc_client_ssh_get_username();
564 /* username is set to "username" in setup_f */
565 assert_string_equal(username_ret, "username");
566
567 /* set new username and check if it changes */
568 ret = nc_client_ssh_set_username("new_username");
569 assert_int_equal(ret, 0);
570 username_ret = nc_client_ssh_get_username();
571 assert_string_equal(username_ret, "new_username");
572}
573
574static void
575test_nc_connect_ssh_interactive_succesfull(void **state)
576{
577 (void)state;
578 struct nc_session *session;
579
580 /* set authentication method to use interactive authentication */
581 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
582 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
583 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
584
585 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 20);
586
587 /* prepare return values for functions used by nc_connect_ssh */
588 will_return(__wrap_connect, 0);
589 will_return(__wrap_ssh_connect, 0);
590 will_return(__wrap_ssh_userauth_none, 1);
591
592 will_return(__wrap_ssh_userauth_kbdint, 0);
593 will_return(__wrap_ssh_is_connected, 1);
594 will_return(__wrap_ssh_is_connected, 1);
595
596 will_return(__wrap_ssh_channel_open_session, 0);
597 will_return(__wrap_ssh_channel_request_subsystem, 0);
598
599 will_return(__wrap_nc_handshake_io, 3);
600 will_return(__wrap_nc_ctx_check_and_fill, 0);
601
602 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
603 assert_non_null(session);
604
Michal Vasko0ab3a662021-07-26 12:17:41 +0200605 will_return(__wrap_ssh_channel_poll_timeout, 0);
David Sedlákddde4492018-09-30 21:34:38 +0200606 nc_session_free(session, NULL);
607}
608
609static void
610test_nc_connect_ssh_password_succesfull(void **state)
611{
612 (void)state;
613 struct nc_session *session;
614
615 /* set authentication method to use password authentication */
616 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 1);
617 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
618 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
619
620 /* set authentication callback */
621 nc_client_ssh_set_auth_password_clb(test_pwd_clb1, "private_data");
622 will_return(test_pwd_clb1, "secret password");
623 /* set values that are expected as parameters for authentication callback */
624 expect_string(test_pwd_clb1, username, "username");
625 expect_string(test_pwd_clb1, hostname, "127.0.0.1");
626 expect_string(test_pwd_clb1, priv, "private_data");
627
628 /* fake succesfull connection */
629 will_return(__wrap_connect, 0);
630 will_return(__wrap_ssh_connect, 0);
631 /* do not authenticate using no authentication method */
632 will_return(__wrap_ssh_userauth_none, 1);
633
634 /* succesfully authenticate via password authentication */
635 expect_string(__wrap_ssh_userauth_password, password, "secret password");
636 expect_string(__wrap_ssh_userauth_password, username, "username");
637 will_return(__wrap_ssh_userauth_password, 0);
638
639 /* fake ssh functions that are used to open netconf channel */
640 will_return(__wrap_ssh_channel_open_session, 0);
641 will_return(__wrap_ssh_channel_request_subsystem, 0);
642
643 /* fake that connection is still alive*/
644 will_return(__wrap_ssh_is_connected, 1);
645
646 /* fake ssh function for recieving hello message */
647 will_return(__wrap_ssh_is_connected, 1);
648
649 will_return(__wrap_nc_handshake_io, 3);
650 will_return(__wrap_nc_ctx_check_and_fill, 0);
651
652 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
653 assert_non_null(session);
654
655 /* disconnect */
Michal Vasko0ab3a662021-07-26 12:17:41 +0200656 will_return(__wrap_ssh_channel_poll_timeout, 0);
David Sedlákddde4492018-09-30 21:34:38 +0200657 nc_session_free(session, NULL);
658}
659
660static void
romanc1d2b092023-02-02 08:58:27 +0100661test_nc_connect_ssh_pubkey_ecdsa_succesfull(void **state)
David Sedlák77acc202018-10-08 21:44:14 +0200662{
663 (void)state;
664 struct nc_session *session;
665 int ret = 0;
666
667 /* set authentication method to use password authentication */
668 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
669 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
670 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
671
672 /* add keypair for authentication */
Michal Vasko7a4213f2022-09-08 11:02:34 +0200673 ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_ecdsa.pub", TESTS_DIR "/data/key_ecdsa");
David Sedlák77acc202018-10-08 21:44:14 +0200674 assert_int_equal(ret, 0);
675
676 /* fake succesfull connection */
677 will_return(__wrap_connect, 0);
678 will_return(__wrap_ssh_connect, 0);
679 /* do not authenticate using no authentication method */
680 will_return(__wrap_ssh_userauth_none, 1);
681 will_return(__wrap_ssh_userauth_try_publickey, 0);
682 will_return(__wrap_ssh_userauth_publickey, 0);
683 will_return(__wrap_ssh_is_connected, 1);
684 will_return(__wrap_ssh_channel_open_session, 0);
685 will_return(__wrap_ssh_channel_request_subsystem, 0);
686
687 /* fake ssh function for recieving hello message */
688 will_return(__wrap_ssh_is_connected, 1);
689
690 will_return(__wrap_nc_handshake_io, 3);
691 will_return(__wrap_nc_ctx_check_and_fill, 0);
692 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
693 assert_non_null(session);
694
695 /* disconnect */
Michal Vasko0ab3a662021-07-26 12:17:41 +0200696 will_return(__wrap_ssh_channel_poll_timeout, 0);
David Sedlák77acc202018-10-08 21:44:14 +0200697 nc_session_free(session, NULL);
romanc1d2b092023-02-02 08:58:27 +0100698
699 /* delete the keypair */
700 ret = nc_client_ssh_del_keypair(0);
701 assert_int_equal(ret, 0);
702}
703
704static void
705test_nc_connect_ssh_pubkey_succesfull(void **state)
706{
707 (void)state;
708 struct nc_session *session;
709 struct ly_ctx *ctx;
710 struct lyd_node *tree;
711 int ret = 0;
712
713 /* set authentication method to use password authentication */
714 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
715 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
716 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
717
718 /* add keypair for authentication */
719 ret = nc_client_ssh_add_keypair(TESTS_DIR "/data/key_rsa.pub", TESTS_DIR "/data/key_rsa");
720 assert_int_equal(ret, 0);
721
722 /* fake succesfull connection */
723 will_return(__wrap_connect, 0);
724 will_return(__wrap_ssh_connect, 0);
725 /* do not authenticate using no authentication method */
726 will_return(__wrap_ssh_userauth_none, 1);
727 will_return(__wrap_ssh_userauth_try_publickey, 0);
728 will_return(__wrap_ssh_userauth_publickey, 0);
729 will_return(__wrap_ssh_is_connected, 1);
730 will_return(__wrap_ssh_channel_open_session, 0);
731 will_return(__wrap_ssh_channel_request_subsystem, 0);
732
733 /* fake ssh function for recieving hello message */
734 will_return(__wrap_ssh_is_connected, 1);
735
736 will_return(__wrap_nc_handshake_io, 3);
737 will_return(__wrap_nc_ctx_check_and_fill, 0);
738
739 ret = ly_ctx_new(MODULES_DIR, 0, &ctx);
740 assert_int_equal(ret, 0);
741
742 ret = nc_server_config_load_modules(&ctx);
743 assert_int_equal(ret, 0);
744
745 ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
746 assert_int_equal(ret, 0);
747
748 ret = nc_server_config_setup(tree);
749 assert_int_equal(ret, 0);
750
751 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
752 assert_non_null(session);
753
754 /* disconnect */
755 will_return(__wrap_ssh_channel_poll_timeout, 0);
756 nc_session_free(session, NULL);
David Sedlák77acc202018-10-08 21:44:14 +0200757}
758
759static void
David Sedlákddde4492018-09-30 21:34:38 +0200760test_nc_connect_connection_failed(void **state)
761{
762 (void)state;
763 struct nc_session *session;
764
765 errno = ECONNREFUSED;
766 will_return(__wrap_connect, -1);
767 will_return(__wrap_ssh_is_connected, 0);
768
769 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
770 assert_null(session);
771}
772
773static void
774test_nc_connect_ssh_bad_hello(void **state)
775{
776 (void)state;
777 struct nc_session *session;
778
779 /* set authentication method to use interactive authentication */
780 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, 1);
781 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
782 nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1);
783
784 nc_client_ssh_set_auth_password_clb(test_pwd_clb2, NULL);
785
786 will_return(__wrap_connect, 0);
787 will_return(__wrap_ssh_connect, 0);
788 will_return(__wrap_ssh_userauth_none, 1);
789
790 will_return(__wrap_ssh_userauth_kbdint, 0);
791 will_return(__wrap_ssh_is_connected, 1);
792 will_return(__wrap_ssh_is_connected, 1);
793
794 will_return(__wrap_ssh_channel_open_session, 0);
795 will_return(__wrap_ssh_channel_request_subsystem, 0);
796 will_return(__wrap_nc_handshake_io, 4);
797
798 session = nc_connect_ssh("127.0.0.1", 8080, NULL);
799 assert_null(session);
800
David Sedlákaae4df32018-10-08 22:27:22 +0200801 /* destroy client, must be called in last test */
David Sedlákddde4492018-09-30 21:34:38 +0200802 nc_client_destroy();
803}
804
Fred Gan3a736e02021-01-04 17:59:38 +0800805static void
806test_nc_client_ssh_ch_setting_username(void **state)
807{
808 (void)state;
809 const char *username_ret;
810 int ret;
811
812 /* username is set to "ch_username" in setup_f */
813 username_ret = nc_client_ssh_ch_get_username();
814 assert_string_equal(username_ret, "ch_username");
815 /* set new username and check if it changes */
816 ret = nc_client_ssh_ch_set_username("new_ch_username");
817 assert_int_equal(ret, 0);
818 username_ret = nc_client_ssh_ch_get_username();
819 assert_string_equal(username_ret, "new_ch_username");
820}
821
822static void
823test_nc_client_ssh_ch_add_bind_listen(void **state)
824{
825 (void)state;
826 int ret;
827
828 /* invalid parameters, address NULL or port 0 */
829 ret = nc_client_ssh_ch_add_bind_listen(NULL, 4334);
830 assert_int_equal(ret, -1);
831 ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 0);
832 assert_int_equal(ret, -1);
833
834 /* failed to create an ssh listening socket */
835 will_return(__wrap_nc_sock_listen_inet, -1);
836 ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
837 assert_int_equal(ret, -1);
838
839 /* fake a successful CH ssh listening socket */
840 will_return(__wrap_nc_sock_listen_inet, 1);
841 ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
842 assert_int_equal(ret, 0);
843
844 /* remove ssh listening client binds */
845 ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
846 assert_int_equal(ret, 0);
847}
848
849static void
850test_nc_accept_callhome(void **state)
851{
852 (void)state;
853 struct nc_session *session = NULL;
854 int timeout = 10;
855 int ret;
856
857 /* invalid parameter session */
858 ret = nc_accept_callhome(timeout, NULL, NULL);
859 assert_int_equal(ret, -1);
860
861 /* no client bind */
862 ret = nc_accept_callhome(timeout, NULL, &session);
863 assert_int_equal(ret, -1);
864
865 /* successfully add a client Call Home bind */
866 will_return(__wrap_nc_sock_listen_inet, 1);
867 ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
868 assert_int_equal(ret, 0);
869
870 /* failed to accept a client bind */
871 will_return(__wrap_nc_sock_accept_binds, -1);
872 ret = nc_accept_callhome(timeout, NULL, &session);
873 assert_int_equal(ret, -1);
874
875 /* failed to accept a server Call Home connection */
876 will_return(__wrap_nc_accept_callhome_ssh_sock, NULL);
877 will_return(__wrap_nc_sock_accept_binds, 2);
878 ret = nc_accept_callhome(timeout, NULL, &session);
879 assert_int_equal(ret, -1);
880
881 /* create session structure to fake a successful server call home connection */
882 session = nc_new_session(NC_CLIENT, 0);
883 assert_non_null(session);
884 will_return(__wrap_nc_sock_accept_binds, 2);
885 will_return(__wrap_nc_accept_callhome_ssh_sock, session);
886 ret = nc_accept_callhome(timeout, NULL, &session);
887 assert_int_equal(ret, 1);
888
889 /* remove ssh listening client binds */
890 ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
891 assert_int_equal(ret, 0);
892
893 /* free session */
894 nc_session_free(session, NULL);
895}
896
897static void
898test_nc_client_ssh_callhome_successful(void **state)
899{
900 (void)state;
901 struct nc_session *session = NULL;
902 int timeout = 10;
903 int ret;
904
905 /* create session structure */
906 session = nc_new_session(NC_CLIENT, 0);
907 assert_non_null(session);
908
909 /* prepare to fake return values for functions used by nc_accept_callhome */
910 will_return(__wrap_nc_sock_listen_inet, 1);
911 will_return(__wrap_nc_sock_accept_binds, 2);
912 will_return(__wrap_nc_accept_callhome_ssh_sock, session);
913
914 ret = nc_client_ssh_ch_add_bind_listen("127.0.0.1", 4334);
915 assert_int_equal(ret, 0);
916 ret = nc_accept_callhome(timeout, NULL, &session);
917 assert_int_equal(ret, 1);
918
919 /* remove ssh listening client binds */
920 ret = nc_client_ssh_ch_del_bind("127.0.0.1", 4334);
921 assert_int_equal(ret, 0);
922
923 /* free session */
924 nc_session_free(session, NULL);
925}
926
David Sedlákddde4492018-09-30 21:34:38 +0200927int
928main(void)
929{
930 const struct CMUnitTest tests[] = {
931 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_pref, setup_f, teardown_f),
932 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_hostkey_check_clb, setup_f, teardown_f),
933 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_password_clb, setup_f, teardown_f),
934 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_interactive_clb, setup_f, teardown_f),
935 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_auth_privkey_passphrase_clb, setup_f, teardown_f),
936 cmocka_unit_test_setup_teardown(test_nc_client_ssh_adding_keypair, setup_f, teardown_f),
937 cmocka_unit_test_setup_teardown(test_nc_client_ssh_setting_username, setup_f, teardown_f),
938 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_interactive_succesfull, setup_f, teardown_f),
939 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_password_succesfull, setup_f, teardown_f),
romanc1d2b092023-02-02 08:58:27 +0100940 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_ecdsa_succesfull, setup_f, teardown_f),
David Sedlák77acc202018-10-08 21:44:14 +0200941 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_pubkey_succesfull, setup_f, teardown_f),
David Sedlákddde4492018-09-30 21:34:38 +0200942 cmocka_unit_test_setup_teardown(test_nc_connect_connection_failed, setup_f, teardown_f),
943 cmocka_unit_test_setup_teardown(test_nc_connect_ssh_bad_hello, setup_f, teardown_f),
Fred Gan3a736e02021-01-04 17:59:38 +0800944 cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_setting_username, setup_f, teardown_f),
945 cmocka_unit_test_setup_teardown(test_nc_client_ssh_ch_add_bind_listen, setup_f, teardown_f),
946 cmocka_unit_test_setup_teardown(test_nc_accept_callhome, setup_f, teardown_f),
947 cmocka_unit_test_setup_teardown(test_nc_client_ssh_callhome_successful, setup_f, teardown_f),
David Sedlákddde4492018-09-30 21:34:38 +0200948 };
949
950 return cmocka_run_group_tests(tests, NULL, NULL);
951}