mirror of
https://github.com/libssh2/libssh2.git
synced 2025-07-29 13:01:14 +03:00
Use modern API in userauth_keyboard_interactive() (#663)
Files: userauth_kbd_packet.c, userauth_kbd_packet.h, test_keyboard_interactive_auth_info_request.c, userauth.c Notes: This refactors `SSH_MSG_USERAUTH_INFO_REQUEST` processing in `userauth_keyboard_interactive()` in order to improve robustness, correctness and readability or the code. * Refactor userauth_keyboard_interactive to use new api for packet parsing * add unit test for userauth_keyboard_interactive_parse_response() * add _libssh2_get_boolean() and _libssh2_get_byte() utility functions Credit: xalopp
This commit is contained in:
335
tests/test_keyboard_interactive_auth_info_request.c
Normal file
335
tests/test_keyboard_interactive_auth_info_request.c
Normal file
@ -0,0 +1,335 @@
|
||||
/* Copyright (C) 2022 Xaver Loppenstedt
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms,
|
||||
* with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names
|
||||
* of any other contributors may be used to endorse or
|
||||
* promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libssh2_priv.h"
|
||||
#include "userauth_kbd_packet.h"
|
||||
|
||||
#define PASS 0
|
||||
#define FAIL -1
|
||||
|
||||
struct expected {
|
||||
int rc;
|
||||
int last_error_code;
|
||||
char *last_error_message;
|
||||
};
|
||||
struct test_case {
|
||||
char *data;
|
||||
int data_len;
|
||||
struct expected expected;
|
||||
};
|
||||
|
||||
#define TEST_CASES_LEN 16
|
||||
struct test_case test_cases[TEST_CASES_LEN] = {
|
||||
/* to small */
|
||||
{
|
||||
NULL, 0,
|
||||
{FAIL, -38,
|
||||
"userauth keyboard data buffer too small to get length"}},
|
||||
/* to small */
|
||||
{
|
||||
"1234", 4,
|
||||
{FAIL, -38,
|
||||
"userauth keyboard data buffer too small to get length"}},
|
||||
/* smalest valid packet possible */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0", 17,
|
||||
{PASS, 0, ""}},
|
||||
/* overrun name */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\x7f"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0", 17,
|
||||
{FAIL, -6,
|
||||
"Unable to decode keyboard-interactive 'name' request field"}},
|
||||
/* overrun instruction */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\x7f"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0", 17,
|
||||
{FAIL, -6,
|
||||
"Unable to decode keyboard-interactive 'instruction' "
|
||||
"request field"}},
|
||||
/* overrun language */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\x7f"
|
||||
"\0\0\0\0", 17,
|
||||
{FAIL, -6, "Unable to decode keyboard-interactive 'language tag' "
|
||||
"request field"}},
|
||||
/* underrun prompt number */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\x01"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0", 17,
|
||||
{FAIL, -38,
|
||||
"Unable to decode keyboard-interactive number of "
|
||||
"keyboard prompts"}},
|
||||
/* too many prompts */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\x7f", 17,
|
||||
{FAIL, -41, "Too many replies for keyboard-interactive prompts"}},
|
||||
/* empty prompt */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\0"
|
||||
"\0\0\0\x01"
|
||||
"\0\0\0\0"
|
||||
"\0", 22, {PASS, 0, ""}},
|
||||
/* copied from OpenSSH */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||
"\0\0\0\x0aPassword: \0", 32, {PASS, 0, ""}},
|
||||
/* overrun in prompt text */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||
"\0\0\0\x7bPassword: \0", 32,
|
||||
{FAIL, -6, "Unable to decode keyboard-interactive "
|
||||
"prompt message"}},
|
||||
/* no echo prompt boolean */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||
"\0\0\0\x0bPassword: \0", 32,
|
||||
{FAIL, -38, "Unable to decode user auth keyboard prompt echo"}},
|
||||
/* two prompts */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02"
|
||||
"\0\0\0\x0aPassword: \0"
|
||||
"\0\0\0\x07Token: \1", 44,
|
||||
{PASS, 0, ""}},
|
||||
/* example from RFC 4256 */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\x19""CRYPTOCard Authentication"
|
||||
"\0\0\0\x1b""The challenge is '14315716'"
|
||||
"\0\0\0\x05""en-US"
|
||||
"\0\0\0\x01"
|
||||
"\0\0\0\x0aResponse: "
|
||||
"\x01"
|
||||
, 89, {PASS, 0, ""}},
|
||||
/* three prompts, 3rd missing*/
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03"
|
||||
"\0\0\0\x0aPassword: \0"
|
||||
"\0\0\0\x07Token: \1", 44,
|
||||
{FAIL, -6,
|
||||
"Unable to decode keyboard-interactive prompt message"}},
|
||||
/* overflow language on 32 bit platform */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\x19"
|
||||
"\0\0\0\x01"
|
||||
"\0\0\0\x05""PWN3D\0\1\2\3\4\5\6\7\1\2\3"
|
||||
"\x01"
|
||||
"\0\0\0\x1b""The challenge is '14315716'"
|
||||
"\xff\xff\xff\xc4""en-US"
|
||||
"\0\0\0\x01"
|
||||
"\0\0\0\x0aResponse: "
|
||||
"\x01",
|
||||
89,
|
||||
{FAIL, -6,
|
||||
"Unable to decode keyboard-interactive 'language tag' "
|
||||
"request field"}},
|
||||
};
|
||||
|
||||
#define FAILED_MALLOC_TEST_CASES_LEN 2
|
||||
struct test_case failed_malloc_test_cases[FAILED_MALLOC_TEST_CASES_LEN] = {
|
||||
/* malloc fail */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||
"\0\0\0\x0aPassword: \0", 32,
|
||||
{FAIL, -6,
|
||||
"Unable to allocate memory for "
|
||||
"keyboard-interactive prompts array"}},
|
||||
/* malloc fail */
|
||||
{
|
||||
"<"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"
|
||||
"\0\0\0\x0aPassword: \0", 32,
|
||||
{FAIL, -6,
|
||||
"Unable to allocate memory for "
|
||||
"keyboard-interactive responses array"
|
||||
}}
|
||||
};
|
||||
|
||||
static int alloc_count = 0;
|
||||
static int free_count = 0;
|
||||
|
||||
/* libssh2_default_alloc
|
||||
*/
|
||||
static
|
||||
LIBSSH2_ALLOC_FUNC(test_alloc)
|
||||
{
|
||||
alloc_count++;
|
||||
|
||||
int *threshold_int_ptr = *abstract;
|
||||
if (*abstract != NULL && *threshold_int_ptr == alloc_count) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return malloc(count);
|
||||
}
|
||||
|
||||
/* libssh2_default_free
|
||||
*/
|
||||
static
|
||||
LIBSSH2_FREE_FUNC(test_free)
|
||||
{
|
||||
(void) abstract;
|
||||
free_count++;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static
|
||||
int test_case(int num,
|
||||
char *data, int data_len, void *abstract,
|
||||
struct expected expected)
|
||||
{
|
||||
alloc_count = 0;
|
||||
free_count = 0;
|
||||
LIBSSH2_SESSION *session = NULL;
|
||||
session = libssh2_session_init_ex(test_alloc, test_free, NULL, abstract);
|
||||
if(session == NULL) {
|
||||
fprintf(stderr, "libssh2_session_init_ex failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
session->userauth_kybd_data = LIBSSH2_ALLOC(session, data_len);
|
||||
session->userauth_kybd_data_len = data_len;
|
||||
memcpy(session->userauth_kybd_data, data, data_len);
|
||||
|
||||
int rc = userauth_keyboard_interactive_decode_info_request(session);
|
||||
|
||||
if(rc != expected.rc) {
|
||||
fprintf(stdout,
|
||||
"Test case %d: expected return code to be %d got %d\n",
|
||||
num, expected.rc, rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *message;
|
||||
int error_code = libssh2_session_last_error(session, &message, NULL, 0);
|
||||
|
||||
if(expected.last_error_code != error_code) {
|
||||
fprintf(stdout,
|
||||
"Test case %d: expected last error code to be "
|
||||
"\"%d\" got \"%d\"\n",
|
||||
num, expected.last_error_code, error_code);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(strcmp(expected.last_error_message, message) != 0) {
|
||||
fprintf(stdout,
|
||||
"Test case %d: expected last error message to be "
|
||||
"\"%s\" got \"%s\"\n",
|
||||
num, expected.last_error_message, message);
|
||||
return 1;
|
||||
}
|
||||
libssh2_session_free(session);
|
||||
|
||||
fprintf(stderr, "Test case %d passed\n", num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < TEST_CASES_LEN; i++) {
|
||||
test_case(i + 1,
|
||||
test_cases[i].data, test_cases[i].data_len,
|
||||
NULL,
|
||||
test_cases[i].expected);
|
||||
}
|
||||
|
||||
for(i = 0; i < FAILED_MALLOC_TEST_CASES_LEN; i++) {
|
||||
int tc = i + TEST_CASES_LEN + 1;
|
||||
int malloc_call_num = 5 + i;
|
||||
test_case(tc,
|
||||
failed_malloc_test_cases[i].data,
|
||||
failed_malloc_test_cases[i].data_len,
|
||||
&malloc_call_num,
|
||||
failed_malloc_test_cases[i].expected);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Workaround for Visual Studio */
|
||||
#ifdef _MSC_VER
|
||||
int
|
||||
bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
|
||||
size_t saltlen,
|
||||
uint8_t *key, size_t keylen, unsigned int rounds)
|
||||
{
|
||||
(void)pass;
|
||||
(void)passlen;
|
||||
(void)salt;
|
||||
(void)saltlen;
|
||||
(void)key;
|
||||
(void)keylen;
|
||||
(void)rounds;
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user