mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-22 23:15:43 +01:00
Add mbedtls_test_buffer to SSL unit tests
In a unit test we want to avoid accessing the network. To test the handshake in the unit test suite we need to implement a connection between the server and the client. This ring buffer implementation will serve as the said connection.
This commit is contained in:
parent
512fe9673f
commit
6264e66ba4
@ -1,3 +1,36 @@
|
||||
Test calback buffer sanity
|
||||
test_callback_buffer_sanity:
|
||||
|
||||
Callback buffer test: Exercise simple write/read
|
||||
test_callback_buffer:50:25:25:25:25:0:0:0:0
|
||||
|
||||
Callback buffer test: Filling up the buffer
|
||||
test_callback_buffer:50:50:50:50:50:0:0:0:0
|
||||
|
||||
Callback buffer test: Filling up the buffer in two steps
|
||||
test_callback_buffer:50:20:20:0:0:30:30:50:50
|
||||
|
||||
Callback buffer test: Reading out the buffer in two steps
|
||||
test_callback_buffer:50:50:50:30:30:0:0:20:20
|
||||
|
||||
Callback buffer test: Data wraps in buffer
|
||||
test_callback_buffer:50:45:45:10:10:10:10:45:45
|
||||
|
||||
Callback buffer test: Data starts at the end
|
||||
test_callback_buffer:50:50:50:49:49:10:10:11:11
|
||||
|
||||
Callback buffer test: Can write less than requested
|
||||
test_callback_buffer:50:75:50:30:30:25:25:45:45
|
||||
|
||||
Callback buffer test: Can read less than requested
|
||||
test_callback_buffer:50:25:25:30:25:5:5:5:5
|
||||
|
||||
Callback buffer test: Writing to full buffer
|
||||
test_callback_buffer:50:50:50:0:0:10:0:60:50
|
||||
|
||||
Callback buffer test: Reading from empty buffer
|
||||
test_callback_buffer:50:0:0:10:0:0:0:0:0
|
||||
|
||||
SSL DTLS replay: initial state, seqnum 0
|
||||
ssl_dtls_replay:"":"000000000000":0
|
||||
|
||||
|
@ -2,6 +2,141 @@
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/ssl_internal.h>
|
||||
|
||||
|
||||
/*
|
||||
* Buffer structure for custom I/O callbacks.
|
||||
*/
|
||||
|
||||
typedef struct mbedtls_test_buffer
|
||||
{
|
||||
size_t start;
|
||||
size_t content_length;
|
||||
size_t capacity;
|
||||
unsigned char *buffer;
|
||||
} mbedtls_test_buffer;
|
||||
|
||||
/*
|
||||
* Initialises \p buf. After calling this function it is safe to call
|
||||
* `mbedtls_test_buffer_free()` on \p buf.
|
||||
*/
|
||||
void mbedtls_test_buffer_init( mbedtls_test_buffer *buf )
|
||||
{
|
||||
memset( buf, 0, sizeof( *buf ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets up \p buf. After calling this function it is safe to call
|
||||
* `mbedtls_test_buffer_put()` and `mbedtls_test_buffer_get()` on \p buf.
|
||||
*/
|
||||
int mbedtls_test_buffer_setup( mbedtls_test_buffer *buf, size_t capacity )
|
||||
{
|
||||
buf->buffer = (unsigned char*) mbedtls_calloc( capacity,
|
||||
sizeof(unsigned char) );
|
||||
if( NULL == buf->buffer )
|
||||
return MBEDTLS_ERR_SSL_ALLOC_FAILED;
|
||||
buf->capacity = capacity;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mbedtls_test_buffer_free( mbedtls_test_buffer *buf )
|
||||
{
|
||||
if( buf->buffer != NULL )
|
||||
mbedtls_free( buf->buffer );
|
||||
|
||||
memset( buf, 0, sizeof( *buf ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Puts \p input_len bytes from the \p input buffer into the ring buffer \p buf.
|
||||
*
|
||||
* \p buf must have been initialized and set up by calling
|
||||
* `mbedtls_test_buffer_init()` and `mbedtls_test_buffer_setup()`.
|
||||
*
|
||||
* \retval \p input_len, if the data fits.
|
||||
* \retval 0 <= value < \p input_len, if the data does not fit.
|
||||
* \retval -1, if \p buf is NULL, it hasn't been set up or \p input_len is not
|
||||
* zero and \p input is NULL.
|
||||
*/
|
||||
int mbedtls_test_buffer_put( mbedtls_test_buffer *buf,
|
||||
const unsigned char* input, size_t input_len )
|
||||
{
|
||||
size_t overflow = 0;
|
||||
|
||||
if( ( buf == NULL ) || ( buf->buffer == NULL ) )
|
||||
return -1;
|
||||
|
||||
/* Reduce input_len to a number that fits in the buffer. */
|
||||
if ( ( buf->content_length + input_len ) > buf->capacity )
|
||||
{
|
||||
input_len = buf->capacity - buf->content_length;
|
||||
}
|
||||
|
||||
if( input == NULL )
|
||||
{
|
||||
return ( input_len == 0 ) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Calculate the number of bytes that need to be placed at lower memory
|
||||
* address */
|
||||
if( buf->start + buf->content_length + input_len
|
||||
> buf->capacity )
|
||||
{
|
||||
overflow = ( buf->start + buf->content_length + input_len )
|
||||
% buf->capacity;
|
||||
}
|
||||
|
||||
memcpy( buf->buffer + buf->start + buf->content_length, input,
|
||||
input_len - overflow );
|
||||
memcpy( buf->buffer, input + input_len - overflow, overflow );
|
||||
buf->content_length += input_len;
|
||||
|
||||
return input_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets \p output_len bytes from the \p output buffer into the ring buffer
|
||||
* \p buf.
|
||||
*
|
||||
* \p buf must have been initialized and set up by calling
|
||||
* `mbedtls_test_buffer_init()` and `mbedtls_test_buffer_setup()`.
|
||||
*
|
||||
* \retval \p output_len, if the data is available.
|
||||
* \retval 0 <= value < \p output_len, if the data is not available.
|
||||
* \retval -1, if \buf is NULL, it hasn't been set up or \p output_len is not
|
||||
* zero and \p output is NULL
|
||||
*/
|
||||
int mbedtls_test_buffer_get( mbedtls_test_buffer *buf,
|
||||
unsigned char* output, size_t output_len )
|
||||
{
|
||||
size_t overflow = 0;
|
||||
|
||||
if( ( buf == NULL ) || ( buf->buffer == NULL ) )
|
||||
return -1;
|
||||
|
||||
if( output == NULL )
|
||||
{
|
||||
return ( output_len == 0 ) ? 0 : -1;
|
||||
}
|
||||
|
||||
if( buf->content_length < output_len )
|
||||
output_len = buf->content_length;
|
||||
|
||||
/* Calculate the number of bytes that need to be drawn from lower memory
|
||||
* address */
|
||||
if( buf->start + output_len > buf->capacity )
|
||||
{
|
||||
overflow = ( buf->start + output_len ) % buf->capacity;
|
||||
}
|
||||
|
||||
memcpy( output, buf->buffer + buf->start, output_len - overflow );
|
||||
memcpy( output + output_len - overflow, buf->buffer, overflow );
|
||||
buf->content_length -= output_len;
|
||||
buf->start = ( buf->start + output_len ) % buf->capacity;
|
||||
|
||||
return output_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function setting up inverse record transformations
|
||||
* using given cipher, hash, EtM mode, authentication tag length,
|
||||
@ -361,6 +496,175 @@ static int ssl_populate_session( mbedtls_ssl_session *session,
|
||||
* END_DEPENDENCIES
|
||||
*/
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void test_callback_buffer_sanity()
|
||||
{
|
||||
enum { MSGLEN = 10 };
|
||||
mbedtls_test_buffer buf;
|
||||
unsigned char input[MSGLEN];
|
||||
unsigned char output[MSGLEN];
|
||||
|
||||
memset( input, 0, sizeof(input) );
|
||||
|
||||
/* Make sure calling put and get on NULL buffer results in error. */
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( NULL, input, sizeof( input ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( NULL, output, sizeof( output ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( NULL, NULL, sizeof( input ) ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( NULL, NULL, sizeof( output ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( NULL, NULL, 0 ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( NULL, NULL, 0 ) == -1 );
|
||||
|
||||
/* Make sure calling put and get on a buffer that hasn't been set up results
|
||||
* in eror. */
|
||||
mbedtls_test_buffer_init( &buf );
|
||||
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( &buf, input, sizeof( input ) ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( &buf, output, sizeof( output ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( &buf, NULL, sizeof( input ) ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( &buf, NULL, sizeof( output ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( &buf, NULL, 0 ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( &buf, NULL, 0 ) == -1 );
|
||||
|
||||
/* Make sure calling put end get on NULL input and output only results in
|
||||
* error if the length is not zero. */
|
||||
|
||||
TEST_ASSERT( mbedtls_test_buffer_setup( &buf, sizeof( input ) ) == 0 );
|
||||
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( &buf, NULL, sizeof( input ) ) == -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( &buf, NULL, sizeof( output ) )
|
||||
== -1 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_put( &buf, NULL, 0 ) == 0 );
|
||||
TEST_ASSERT( mbedtls_test_buffer_get( &buf, NULL, 0 ) == 0 );
|
||||
|
||||
exit:
|
||||
|
||||
mbedtls_test_buffer_free( &buf );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/*
|
||||
* Test if the implementation of `mbedtls_test_buffer` related functions is
|
||||
* correct and works as expected.
|
||||
*
|
||||
* That is
|
||||
* - If we try to put in \p put1 bytes then we can put in \p put1_ret bytes.
|
||||
* - Afterwards if we try to get \p get1 bytes then we can get \get1_ret bytes.
|
||||
* - Next, if we try to put in \p put1 bytes then we can put in \p put1_ret
|
||||
* bytes.
|
||||
* - Afterwards if we try to get \p get1 bytes then we can get \get1_ret bytes.
|
||||
* - All of the bytes we got match the bytes we put in in a FIFO manner.
|
||||
*/
|
||||
|
||||
/* BEGIN_CASE */
|
||||
void test_callback_buffer( int size, int put1, int put1_ret,
|
||||
int get1, int get1_ret, int put2, int put2_ret,
|
||||
int get2, int get2_ret )
|
||||
{
|
||||
enum { ROUNDS = 2 };
|
||||
size_t put[ROUNDS];
|
||||
int put_ret[ROUNDS];
|
||||
size_t get[ROUNDS];
|
||||
int get_ret[ROUNDS];
|
||||
mbedtls_test_buffer buf;
|
||||
unsigned char* input = NULL;
|
||||
size_t input_len;
|
||||
unsigned char* output = NULL;
|
||||
size_t output_len;
|
||||
size_t i, written, read;
|
||||
int j;
|
||||
|
||||
mbedtls_test_buffer_init( &buf );
|
||||
TEST_ASSERT( mbedtls_test_buffer_setup( &buf, size ) == 0 );
|
||||
|
||||
/* Check the sanity of input parameters and initialise local variables. That
|
||||
* is, ensure that the amount of data is not negative and that we are not
|
||||
* expecting more to put or get than we actually asked for. */
|
||||
TEST_ASSERT( put1 >= 0 );
|
||||
put[0] = put1;
|
||||
put_ret[0] = put1_ret;
|
||||
TEST_ASSERT( put1_ret <= put1 );
|
||||
TEST_ASSERT( put2 >= 0 );
|
||||
put[1] = put2;
|
||||
put_ret[1] = put2_ret;
|
||||
TEST_ASSERT( put2_ret <= put2 );
|
||||
|
||||
TEST_ASSERT( get1 >= 0 );
|
||||
get[0] = get1;
|
||||
get_ret[0] = get1_ret;
|
||||
TEST_ASSERT( get1_ret <= get1 );
|
||||
TEST_ASSERT( get2 >= 0 );
|
||||
get[1] = get2;
|
||||
get_ret[1] = get2_ret;
|
||||
TEST_ASSERT( get2_ret <= get2 );
|
||||
|
||||
input_len = 0;
|
||||
/* Calculate actual input and output lengths */
|
||||
for( j = 0; j < ROUNDS; j++ )
|
||||
{
|
||||
if( put_ret[j] > 0 )
|
||||
{
|
||||
input_len += put_ret[j];
|
||||
}
|
||||
}
|
||||
/* In order to always have a valid pointer we always allocate at least 1
|
||||
* byte. */
|
||||
if( input_len == 0 )
|
||||
input_len = 1;
|
||||
ASSERT_ALLOC( input, input_len );
|
||||
|
||||
output_len = 0;
|
||||
for( j = 0; j < ROUNDS; j++ )
|
||||
{
|
||||
if( get_ret[j] > 0 )
|
||||
{
|
||||
output_len += get_ret[j];
|
||||
}
|
||||
}
|
||||
TEST_ASSERT( output_len <= input_len );
|
||||
/* In order to always have a valid pointer we always allocate at least 1
|
||||
* byte. */
|
||||
if( output_len == 0 )
|
||||
output_len = 1;
|
||||
ASSERT_ALLOC( output, output_len );
|
||||
|
||||
/* Fill up the buffer with structured data so that unwanted changes
|
||||
* can be detected */
|
||||
for( i = 0; i < input_len; i++ )
|
||||
{
|
||||
input[i] = i & 0xFF;
|
||||
}
|
||||
|
||||
written = read = 0;
|
||||
for( j = 0; j < ROUNDS; j++ )
|
||||
{
|
||||
TEST_ASSERT( put_ret[j] == mbedtls_test_buffer_put( &buf,
|
||||
input + written, put[j] ) );
|
||||
written += put_ret[j];
|
||||
TEST_ASSERT( get_ret[j] == mbedtls_test_buffer_get( &buf,
|
||||
output + read, get[j] ) );
|
||||
read += get_ret[j];
|
||||
TEST_ASSERT( read <= written );
|
||||
if( get_ret[j] > 0 )
|
||||
{
|
||||
TEST_ASSERT( memcmp( output + read - get_ret[j],
|
||||
input + read - get_ret[j], get_ret[j] )
|
||||
== 0 );
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
mbedtls_free( input );
|
||||
mbedtls_free( output );
|
||||
mbedtls_test_buffer_free( &buf );
|
||||
}
|
||||
/* END_CASE */
|
||||
|
||||
/* BEGIN_CASE depends_on:MBEDTLS_SSL_DTLS_ANTI_REPLAY */
|
||||
void ssl_dtls_replay( data_t * prevs, data_t * new, int ret )
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user