Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Unit Tests For SSL Operations #1845

Open
wants to merge 17 commits into
base: BABEL_3_X_DEV
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ runs:
if [[ ${{inputs.tap_tests}} == "yes" ]]; then
./configure CC='ccache gcc' --prefix=$HOME/${{ inputs.install_dir }}/ --with-python PYTHON=/usr/bin/python3.8 --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu --enable-tap-tests --with-gssapi
else
./configure CC='ccache gcc' --prefix=$HOME/${{ inputs.install_dir }}/ --with-python PYTHON=/usr/bin/python3.8 --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu
./configure CC='ccache gcc' --prefix=$HOME/${{ inputs.install_dir }}/ --with-python PYTHON=/usr/bin/python3.8 --enable-cassert CFLAGS="-ggdb" --with-libxml --with-uuid=ossp --with-icu --with-openssl
fi
make -j 4 2>error.txt
make install
Expand Down
73 changes: 68 additions & 5 deletions contrib/babelfishpg_tds/src/backend/tds/tdssecure.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@

int tds_ssl_min_protocol_version;
int tds_ssl_max_protocol_version;

static TdsSecureSocketApi tds_secure_raw_read = secure_raw_read;
static TdsSecureSocketApiConst tds_secure_raw_write = secure_raw_write;
vikashprajapati-cell marked this conversation as resolved.
Show resolved Hide resolved

#ifdef USE_SSL

/*
Expand All @@ -61,6 +65,8 @@ typedef union TDSPacketHeader {
static int pkt_bytes_read = 0;
static TDSPacketHeader pkt_data = {0};

static bool unit_testing = false;

/*
* SslRead - TDS secure read function, similar to my_sock_read
*/
Expand All @@ -71,7 +77,7 @@ SslRead(BIO * h, char *buf, int size)

if (buf != NULL)
{
res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size);
res = tds_secure_raw_read(((Port *) BIO_get_data(h)), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
Expand Down Expand Up @@ -126,7 +132,7 @@ SslHandShakeRead(BIO * h, char *buf, int size)
}

if (unlikely(pkt_data.header.pkt_type != TDS_PRELOGIN))
ereport(FATAL,
ereport(unit_testing ? ERROR : FATAL,
(errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating connection due to unexpected ssl packet header")));

Expand Down Expand Up @@ -163,6 +169,35 @@ SslHandShakeRead(BIO * h, char *buf, int size)
return res;
}


ssize_t
test_ssl_handshake_read(BIO * h, char *buf, int size, TdsSecureSocketApi mock_socket_read, int ReadPointer)
vikashprajapati-cell marked this conversation as resolved.
Show resolved Hide resolved
{

/*
* Accessing SslHandShakeRead() function directly from our testing functions created in the test_ssl_read.c file is not possible due to its static nature
* This intermediary function serves as a gateway, allowing us to invoke the SslHandShakeRead() function from our testing function
*/

int res;
tds_secure_raw_read = mock_socket_read;
unit_testing = true;
pkt_bytes_read = ReadPointer;
PG_TRY();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

{
res = SslHandShakeRead(h, buf, size);
}
PG_FINALLY();
{
unit_testing = false;
tds_secure_raw_read = secure_raw_read;
}
PG_END_TRY();

return res;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

}


/*
* SslWrite - Tds secure write function, similar to my_sock_write.
*/
Expand All @@ -171,7 +206,7 @@ SslWrite(BIO * h, const char *buf, int size)
{
int res = 0;

res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size);
res = tds_secure_raw_write(((Port *) BIO_get_data(h)), buf, size);
BIO_clear_retry_flags(h);
if (res <= 0)
{
Expand Down Expand Up @@ -245,6 +280,34 @@ SslHandShakeWrite(BIO * h, const char *buf, int size)
return (res - TDS_PACKET_HEADER_SIZE);
}


ssize_t
test_ssl_handshake_write(BIO * h, char *buf, int size, TdsSecureSocketApiConst mock_socket_write)
{

/*
* Accessing SslHandShakeWrite() function directly from our testing functions created in the test_ssl_write.c file is not possible due to its static nature
* This intermediary function serves as a gateway, allowing us to invoke the SslHandShakeWrite() function from our testing function
*/

int res;
tds_secure_raw_write = mock_socket_write;
unit_testing = true;
PG_TRY();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation, also put write API reset in finally block

{
res = SslHandShakeWrite(h, buf, size);
}
PG_FINALLY();
{
unit_testing = false;
tds_secure_raw_write = secure_raw_write;
}
PG_END_TRY();

return res;
}


/*
* TdsBioSecureSocket - Similar to my_BIO_s_socket
* Used to setup, TDS listener read and write API
Expand Down Expand Up @@ -337,7 +400,7 @@ tds_secure_read(Port *port, void *ptr, size_t len)
else
#endif
{
n = secure_raw_read(port, ptr, len);
n = tds_secure_raw_read(port, ptr, len);
waitfor = WL_SOCKET_READABLE;
}

Expand Down Expand Up @@ -422,7 +485,7 @@ tds_secure_write(Port *port, void *ptr, size_t len)
else
#endif
{
n = secure_raw_write(port, ptr, len);
n = tds_secure_raw_write(port, ptr, len);
waitfor = WL_SOCKET_WRITEABLE;
}

Expand Down
6 changes: 6 additions & 0 deletions contrib/babelfishpg_tds/src/include/tds_secure.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#endif
#endif

typedef ssize_t (*TdsSecureSocketApi) (Port *port, void *ptr, size_t len);
typedef ssize_t (*TdsSecureSocketApiConst) (Port *port, const void *ptr, size_t len);

BIO_METHOD *TdsBioSecureSocket(BIO_METHOD * my_bio_methods);

extern int tds_ssl_min_protocol_version;
Expand All @@ -60,3 +63,6 @@ ssize_t

/* function defined in tdssecure.c and called from tdslogin.c */
void TdsFreeSslStruct(Port *port);

extern ssize_t test_ssl_handshake_read(BIO * h, char *buf, int size, TdsSecureSocketApi mock_socket_read, int ReadPointer);
extern ssize_t test_ssl_handshake_write(BIO * h, char *buf, int size, TdsSecureSocketApiConst mock_socket_write);
1 change: 1 addition & 0 deletions contrib/babelfishpg_unit/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ OBJS = $(SRCS:.c=.o) # object files

# source code files
SRCS = babelfishpg_unit.c test_money.c \
test_ssl_read.c test_ssl_write.c

# for posgres build
PG_CONFIG = pg_config
Expand Down
9 changes: 9 additions & 0 deletions contrib/babelfishpg_unit/babelfishpg_unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ TestInfo tests[]=
{&test_fixeddecimal_int2_gt, true, "GreaterThanCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"},
{&test_fixeddecimal_int2_ne, true, "NotEqualToCheck_FIXEDDECIMAL_INT2", "babelfish_money_datatype"},
{&test_fixeddecimal_int2_cmp, true, "Comparison_FIXEDDECIMAL_INT2", "babelfish_money_datatype"},

#ifdef USE_SSL
{&test_ssl_handshakeRead, true, "Testing_SSL_HANDSHAKE_READ", "babelfishpg_tds_ssl_read"},
{&test_ssl_handshakeRead_oversize, true, "TestingOverSize_SSL_HANDSHAKE_READ", "babelfishpg_tds_ssl_read"},
{&test_ssl_handshakeRead_pkt_type, true, "TestingPacketType_SSL_HANDSHAKE_READ", "babelfishpg_tds_ssl_read"},

{&test_ssl_handshakeWrite, true, "Testing_SSL_HANDSHAKE_WRITE", "babelfishpg_tds_ssl_write"},
{&test_ssl_handshakeWrite_sizeCheck, true, "TestingSizeCheck_SSL_HANDSHAKE_WRITE", "babelfishpg_tds_ssl_write"},
#endif
};


Expand Down
9 changes: 9 additions & 0 deletions contrib/babelfishpg_unit/babelfishpg_unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,12 @@ extern TestResult *test_fixeddecimal_int2_le(void);
extern TestResult *test_fixeddecimal_int2_gt(void);
extern TestResult *test_fixeddecimal_int2_ne(void);
extern TestResult *test_fixeddecimal_int2_cmp(void);

#ifdef USE_SSL
extern TestResult *test_ssl_handshakeRead(void);
extern TestResult *test_ssl_handshakeRead_pkt_type(void);
extern TestResult *test_ssl_handshakeRead_oversize(void);

extern TestResult *test_ssl_handshakeWrite(void);
extern TestResult *test_ssl_handshakeWrite_sizeCheck(void);
#endif
173 changes: 173 additions & 0 deletions contrib/babelfishpg_unit/test_ssl_read.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include "babelfishpg_unit.h"
#include "../babelfishpg_tds/src/include/tds_secure.h"

#ifdef USE_SSL
static char *prelogin_request;
static int ReadPointer = 0;


static ssize_t
mock_socket_read(Port *port, void *ptr, size_t len)
{

/*
* Mock function of tds_secure_raw_read() present in tdssecure.c file
*/

int i;
for (i = ReadPointer; i < ReadPointer + len; i++)
sscanf(&prelogin_request[i * 2], "%2hhx", (unsigned char *)ptr + i);
ReadPointer += len;
return len;
}


TestResult*
test_ssl_handshakeRead(void)
{

/*
* We will generate a prelogin request message and pass it to the handshake read function for processing
* By comparing the number of bytes read against the expected value and comparing actual bytes, we can verify the accuracy of the read operation
*/

BIO *h = NULL;
char *buf = NULL;
char *expected_str;
int expected;
int obtained;

TestResult* testResult = palloc0(sizeof(TestResult));
testResult->result = true;

h = BIO_new(BIO_s_mem());
ReadPointer = 0;

prelogin_request = strdup("1201000F0000010011A25E4571");
buf = malloc(strlen(prelogin_request)/2);
expected = strlen(prelogin_request)/2 - 8;

expected_str = (char *)malloc(strlen(prelogin_request)/2);
for (int i = 0; i < expected; i++)
sscanf(&prelogin_request [i * 2], "%2hhx", (char *)expected_str + i);

obtained = test_ssl_handshake_read(h, buf, expected, mock_socket_read, ReadPointer);

expected_str[expected] = '\0';
buf[obtained] = '\0';

/*
* if number of bytes are same then we will compare actual data
*/
if(expected == obtained)
{
TEST_ASSERT_TESTCASE(strcmp(buf, expected_str) == 0, testResult);
}
TEST_ASSERT(strcmp(buf, expected_str) == 0, testResult);

free(buf);
free(prelogin_request);
free(expected_str);
return testResult;

}

TestResult*
test_ssl_handshakeRead_oversize(void)
{

/*
* In this scenario, we will send a message size that exceeds the total packet length
* We will examine whether the function effectively detects the oversized message and generates the appropriate response
*/

BIO *h = NULL;
char *buf = NULL;

int expected;
int obtained;

TestResult* testResult = palloc0(sizeof(TestResult));
testResult->result = true;

prelogin_request = strdup("1201000B00000100115461A23E");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, why are we manipulating length here?

buf = malloc(strlen(prelogin_request)/2);

h = BIO_new(BIO_s_mem());
ReadPointer = 0;

expected = strlen(prelogin_request)/2 - 8;
obtained = test_ssl_handshake_read(h, buf, expected, mock_socket_read, ReadPointer);

TEST_ASSERT_TESTCASE(expected != obtained, testResult);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not clear, what do we expect here that multi packet message should be handled properly, if yes why results should not match

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the logic in the latest commit.

TEST_ASSERT(expected != obtained, testResult);
if(testResult->result == true)
{
strncpy(testResult->message, "SSL packet expand more than one TDS packet", MAX_TEST_MESSAGE_LENGTH);
}

free(buf);
free(prelogin_request);
ReadPointer = 0;

return testResult;

}


TestResult*
test_ssl_handshakeRead_pkt_type(void)
{

/*
* We will generate a message other than the prelogin request by modifying the packet type field within the packet.
* We will verify if the function correctly identifies and handles messages other than the prelogin request
* ensuring appropriate error handling and response generation.
*/

BIO *h = NULL;
char *buf = NULL;

ErrorData *errorData;
MemoryContext oldcontext;

TestResult* testResult = palloc0(sizeof(TestResult));
testResult->result = false;

prelogin_request = strdup("100100090000010011");
buf = malloc(strlen(prelogin_request)/2);

h = BIO_new(BIO_s_mem());
ReadPointer = 0;

oldcontext = CurrentMemoryContext;
PG_TRY();
{
test_ssl_handshake_read(h, buf, 0, mock_socket_read, ReadPointer);
}
PG_CATCH();
{
MemoryContextSwitchTo(oldcontext);
errorData = CopyErrorData();
FlushErrorState();
snprintf(testResult->message, MAX_TEST_MESSAGE_LENGTH, "%s", testResult->message, errorData->message);
testResult->result = true;
FreeErrorData(errorData);
}
PG_END_TRY();

// If the error doesn't occurr, then the following message gets displayed
if(testResult->result == false)
{
strncpy(testResult->message, "Error doesn't occur since packet type is PRE_LOGIN", MAX_TEST_MESSAGE_LENGTH);
}

free(buf);
free(prelogin_request);
ReadPointer = 0;

return testResult;

}

#endif
Loading
Loading