Esempio n. 1
0
/**
 * @return >0: the version that was negotiated
 *          0: no agreement on version was reached
 *         -1: error
 */
int ServerNegotiateProtocol(const ConnectionInfo *conn_info)
{
    int ret;
    char input[CF_SMALLBUF] = "";

    /* Send "CFE_v%d cf-serverd version". */
    char version_string[CF_MAXVARSIZE];
    int len = snprintf(version_string, sizeof(version_string),
                       "CFE_v%d cf-serverd %s\n",
                       SERVER_PROTOCOL_VERSION, VERSION);

    ret = TLSSend(conn_info->ssl, version_string, len);
    if (ret != len)
    {
        Log(LOG_LEVEL_ERR, "Connection was hung up!");
        return -1;
    }

    /* Receive CFE_v%d ... */
    ret = TLSRecvLine(conn_info->ssl, input, sizeof(input));
    if (ret <= 0)
    {
        Log(LOG_LEVEL_ERR,
            "Client closed connection early! He probably does not trust our key...");
        return -1;
    }

    int version_received = -1;
    ret = sscanf(input, "CFE_v%d", &version_received);
    if (ret != 1)
    {
        Log(LOG_LEVEL_ERR,
            "Protocol version negotiation failed! Received: %s",
            input);
        return -1;
    }

    /* For now we support only one version, so just check they match... */
    if (version_received == SERVER_PROTOCOL_VERSION)
    {
        char s[] = "OK\n";
        TLSSend(conn_info->ssl, s, sizeof(s)-1);
    }
    else
    {
        char s[] = "BAD unsupported protocol version\n";
        TLSSend(conn_info->ssl, s, sizeof(s)-1);
        Log(LOG_LEVEL_ERR,
            "Client advertises unsupported protocol version: %d", version_received);
        version_received = 0;
    }
    return version_received;
}
Esempio n. 2
0
/**
 * @brief Return the client's username into the #username variable
 * @TODO More protocol identity: IDENTIFY USERNAME=xxx HOSTNAME=xxx CUSTOMNAME=xxx
 * @return 1 if IDENTITY command was parsed correctly. Identity fields
 *         (only #username for now) have the respective string values, or they are
 *         empty if field was not on IDENTITY line.
 * @return -1 in case of error.
 */
int ServerIdentifyClient(const ConnectionInfo *conn_info,
                         char *username, size_t username_size)
{
    char line[1024], word1[1024], word2[1024];
    int line_pos = 0, chars_read = 0;
    int ret;

    /* Reset all identity variables, we'll set them later according to fields
     * on IDENTITY line. For now only "username" setting exists... */
    username[0] = '\0';

    ret = TLSRecvLine(conn_info->ssl, line, sizeof(line));
    if (ret <= 0)
    {
        return -1;
    }

    /* Assert sscanf() is safe to use. */
    assert(sizeof(word1)>=sizeof(line) && sizeof(word2)>=sizeof(line));

    ret = sscanf(line, "IDENTITY %[^=]=%s %n", word1, word2, &chars_read);
    while (ret >= 2)
    {
        /* Found USERNAME identity setting */
        if (strcmp(word1, "USERNAME") == 0)
        {
            if (strlen(word2) < username_size)
            {
                strcpy(username, word2);
            }
            else
            {
                Log(LOG_LEVEL_ERR, "IDENTITY parameter too long: %s=%s",
                    word1, word2);
                return -1;
            }
            Log(LOG_LEVEL_VERBOSE, "Setting IDENTITY: %s=%s",
                word1, word2);
        }
        else
        {
            Log(LOG_LEVEL_VERBOSE, "Received unknown IDENTITY parameter: %s=%s",
                word1, word2);
        }

        line_pos += chars_read;
        ret = sscanf(&line[line_pos], " %[^=]=%s %n", word1, word2, &chars_read);
    }

    return 1;
}
Esempio n. 3
0
/*
 * This test checks for the three basic operations:
 * - TLSSend
 * - TLSRecv
 * - TLSRecvLine
 * It is difficult to test each one separatedly, so we test all at once.
 * The test consists on establishing a connection to our child process and then
 * sending and receiving data. We switch between the original functions and the
 * mock functions.
 * We do not test SSL_new, SSL_accept and such because those will be covered by either
 * the client or server tests.
 */
static void test_TLSBasicIO(void)
{
    ASSERT_IF_NOT_INITIALIZED;
    RESET_STATUS;
    SSL *ssl = NULL;
    char output_buffer[] = "this is a buffer";
    int output_buffer_length = strlen(output_buffer);
    char input_buffer[4096];
    int result = 0;

    /*
     * Open a socket and establish a tcp connection.
     */
    struct sockaddr_in server_addr;
    int server = 0;

    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server = socket(AF_INET, SOCK_STREAM, 0);
    assert_int_not_equal(-1, server);
    server_addr.sin_family = AF_INET;
    /* We should not use inet_addr, but it is easier for this particular case. */
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_addr.sin_port = htons(8035);

    /*
     * Connect
     */
    result = connect(server, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
    assert_int_not_equal(-1, result);
    /*
     * Create a SSL instance
     */
    ssl = SSL_new(SSLCLIENTCONTEXT);
    assert_true(ssl != NULL);
    SSL_set_fd(ssl, server);
    /*
     * Establish the TLS connection over the socket.
     */
    result = SSL_connect(ssl);
    assert_int_not_equal(-1, result);
    /*
     * Start testing. The first obvious thing to test is to send data.
     */
    result = TLSSend(ssl, output_buffer, output_buffer_length);
    assert_int_equal(result, output_buffer_length);
    /*
     * Good we sent data and the data was sent. Let's check what we get back
     * by using TLSRecv.
     */
    result = TLSRecv(ssl, input_buffer, output_buffer_length);
    assert_int_equal(output_buffer_length, result);

    input_buffer[output_buffer_length] = '\0';
    assert_string_equal(output_buffer, input_buffer);
    /*
     * Brilliant! We transmitted and received data using simple communication.
     * Let's try the line sending.
     */
    char output_line_buffer[] = "hello\ngoodbye\n";
    int output_line_buffer_length = strlen(output_line_buffer);
    char output_just_hello[] = "hello";
    int output_just_hello_length = strlen(output_just_hello);

    result = TLSSend(ssl, output_line_buffer, output_line_buffer_length);
    assert_int_equal(result, output_line_buffer_length);

    result = TLSRecvLine(ssl, input_buffer, output_line_buffer_length);
    /* The reply should be up to the first hello */
    assert_int_equal(result, output_just_hello_length);
    assert_string_equal(input_buffer, output_just_hello);

    /*
     * Basic check
     */
    USE_MOCK(SSL_write);
    USE_MOCK(SSL_read);
    assert_int_equal(0, TLSSend(ssl, output_buffer, 0));
    assert_int_equal(-1, TLSSend(ssl, output_buffer, output_buffer_length));
    assert_int_equal(-1, TLSRecv(ssl, input_buffer, output_buffer_length));
    RESET_STATUS;

    /*
     * Start replacing the functions inside to check that the logic works
     * We start by testing TLSSend, then TLSRead and at last TLSRecvLine.
     */
    USE_MOCK(SSL_write);
    SSL_WRITE_RETURN(0);
    assert_int_equal(0, TLSSend(ssl, output_buffer, output_buffer_length));
    USE_MOCK(SSL_get_shutdown);
    SSL_GET_SHUTDOWN_RETURN(1);
    assert_int_equal(0, TLSSend(ssl, output_buffer, output_buffer_length));
    SSL_WRITE_RETURN(-1);
    assert_int_equal(-1, TLSSend(ssl, output_buffer, output_buffer_length));

    USE_MOCK(SSL_read);
    SSL_READ_RETURN(0);
    SSL_GET_SHUTDOWN_RETURN(0);
    assert_int_equal(0, TLSRecv(ssl, input_buffer, output_buffer_length));
    SSL_GET_SHUTDOWN_RETURN(1);
    assert_int_equal(0, TLSRecv(ssl, input_buffer, output_buffer_length));
    SSL_READ_RETURN(-1);
    assert_int_equal(-1, TLSRecv(ssl, input_buffer, output_buffer_length));

    USE_ORIGINAL(SSL_write);
    SSL_READ_RETURN(0);
    assert_int_equal(-1, TLSRecvLine(ssl, input_buffer, output_buffer_length));
    SSL_READ_RETURN(-1);
    assert_int_equal(-1, TLSRecvLine(ssl, input_buffer, output_buffer_length));
    SSL_READ_RETURN(5);
    assert_int_equal(-1, TLSRecvLine(ssl, input_buffer, 10));
    SSL_READ_USE_BUFFER(output_line_buffer);
    assert_int_equal(5, TLSRecvLine(ssl, input_buffer, output_line_buffer_length));
    assert_string_equal(output_just_hello, input_buffer);

    result = SSL_shutdown(ssl);
    if (ssl)
    {
        SSL_free(ssl);
    }
    RESET_STATUS;
}