mirror of
				https://github.com/libssh2/libssh2.git
				synced 2025-11-03 22:13:11 +03:00 
			
		
		
		
	Ref: https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html (2023-11-29) Enable new warnings: - replace `-Wno-sign-conversion` with `-Wsign-conversion`. Fix them in example, tests and wincng. There remain about 360 of these warnings in `src`. Add a TODO item for those and disable `-Werror` for this particular warning. - enable `-Wformat=2` for clang (in both cmake and autotools). - enable `__attribute__((format))` for `_libssh2_debug()`, `_libssh2_snprintf()` and in tests for `run_command()`. `LIBSSH2_PRINTF()` copied from `CURL_TEMP_PRINTF()` in curl. - enable `-Wimplicit-fallthrough`. - enable `-Wtrampolines`. Fix them: - src: replace obsolete fall-through-comments with `__attribute__((fallthrough))`. - wincng: fix `-Wsign-conversion` warnings. - tests: fix `-Wsign-conversion` warnings. - example: fix `-Wsign-conversion` warnings. - src: fix `-Wformat` issues in trace calls. Also, where necessary fix `int` and `unsigned char` casts to `unsigned int` and adjust printf format strings. These were not causing compiler warnings. Cast large types to `long` to avoid dealing with printf masks for `size_t` and other C99 types. Existing code often used `int` for this. I'll update them to `long` in an upcoming commit. - tests: fix `-Wformat` warning. - silence `-Wformat-nonliteral` warnings. - mbedtls: silence `-Wsign-conversion`/`-Warith-conversion` in external header. Closes #1257
		
			
				
	
	
		
			332 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 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.
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: BSD-3-Clause
 | 
						|
 */
 | 
						|
 | 
						|
#include "libssh2_priv.h"
 | 
						|
#include "userauth_kbd_packet.h"
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#define PASS 0
 | 
						|
#define FAIL -1
 | 
						|
 | 
						|
struct expected {
 | 
						|
    int rc;
 | 
						|
    int last_error_code;
 | 
						|
    const char *last_error_message;
 | 
						|
};
 | 
						|
struct test_case {
 | 
						|
    const char *data;
 | 
						|
    unsigned int data_len;
 | 
						|
    struct expected expected;
 | 
						|
};
 | 
						|
 | 
						|
#define TEST_CASES_LEN 16
 | 
						|
static const struct test_case
 | 
						|
    test_cases[TEST_CASES_LEN] = {
 | 
						|
    /* too small */
 | 
						|
    {
 | 
						|
        NULL, 0,
 | 
						|
        {FAIL, -38,
 | 
						|
            "userauth keyboard data buffer too small to get length"}},
 | 
						|
    /* too small */
 | 
						|
    {
 | 
						|
        "1234", 4,
 | 
						|
        {FAIL, -38,
 | 
						|
            "userauth keyboard data buffer too small to get length"}},
 | 
						|
    /* smallest 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
 | 
						|
static const 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)
 | 
						|
{
 | 
						|
    int *threshold_int_ptr = *abstract;
 | 
						|
    alloc_count++;
 | 
						|
    if(*abstract && *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,
 | 
						|
              const char *data, unsigned int data_len, void *abstract,
 | 
						|
              struct expected expected)
 | 
						|
{
 | 
						|
    int rc;
 | 
						|
    char *message;
 | 
						|
    int error_code;
 | 
						|
    LIBSSH2_SESSION *session;
 | 
						|
 | 
						|
    alloc_count = 0;
 | 
						|
    free_count = 0;
 | 
						|
 | 
						|
    session = libssh2_session_init_ex(test_alloc, test_free, NULL, abstract);
 | 
						|
    if(!session) {
 | 
						|
        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);
 | 
						|
 | 
						|
    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;
 | 
						|
    }
 | 
						|
 | 
						|
    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(void)
 | 
						|
{
 | 
						|
    int ret = 0;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for(i = 0; i < TEST_CASES_LEN; i++) {
 | 
						|
        if(test_case(i + 1,
 | 
						|
                     test_cases[i].data,
 | 
						|
                     test_cases[i].data_len,
 | 
						|
                     NULL,
 | 
						|
                     test_cases[i].expected))
 | 
						|
            ret = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    for(i = 0; i < FAILED_MALLOC_TEST_CASES_LEN; i++) {
 | 
						|
        int tc =  i + TEST_CASES_LEN + 1;
 | 
						|
        int malloc_call_num = 3 + i;
 | 
						|
        if(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))
 | 
						|
            ret = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 |