Commit message: fix(plugin): Add default limits for chunks and message size

Based on a reported DoS vulnerability reported by Team82 (Claroty
Research).
CVE: CVE-2022-25761
CWE: CWE-703
Vulnerability description: The package open62541/open62541 before 1.2.5, from 1.3-rc1 and before 1.3.1 are vulnerable to Denial of Service (DoS) due to a missing limitation on the number of received chunks - per single session or in total for all concurrent sessions. An attacker can exploit this vulnerability by sending an unlimited number of huge chunks (e.g. 2GB each) without sending the Final closing chunk.

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendSymmetricMessage_modeSign) {
    // initialize dummy message
    UA_ReadRequest dummyMessage;
    UA_ReadRequest_init(&dummyMessage);
    UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];

    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGN;

    UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
                                                                 &dummyMessage, &dummyType);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_msg(fCalled.sym_sign, "Expected message to have been signed");
    ck_assert_msg(!fCalled.sym_enc, "Expected message to not have been encrypted");
} END_TEST

Project: open62541
File: check_securechannel.c

createDummyResponse(UA_OpenSecureChannelResponse *response) {
    UA_OpenSecureChannelResponse_init(response);
    memset(response, 0, sizeof(UA_OpenSecureChannelResponse));
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_SecurityModeSignAndEncrypt) {
    // Configure our channel correctly for OPN messages and setup dummy message
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);

    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected function to succeed");
    ck_assert_msg(fCalled.asym_enc, "Expected message to have been encrypted but it was not");
    ck_assert_msg(fCalled.asym_sign, "Expected message to have been signed but it was not");
}END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_withoutConnection) {
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);
    testChannel.securityMode = UA_MESSAGESECURITYMODE_NONE;

    // Remove connection to provoke error
    UA_Connection_detachSecureChannel(testChannel.connection);
    testChannel.connection = NULL;

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);

    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure without a connection");
}END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_SecurityModeNone) {
    // Configure our channel correctly for OPN messages and setup dummy message
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);
    testChannel.securityMode = UA_MESSAGESECURITYMODE_NONE;

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected function to succeed");
    ck_assert_msg(!fCalled.asym_enc, "Message encryption was called but should not have been");
    ck_assert_msg(!fCalled.asym_sign, "Message signing was called but should not have been");
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_SecurityModeInvalid) {
    // Configure our channel correctly for OPN messages and setup dummy message
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);

    testChannel.securityMode = UA_MESSAGESECURITYMODE_INVALID;

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_BADSECURITYMODEREJECTED,
                  "Expected SecurityMode rejected error");
}

Project: open62541
File: check_securechannel.c

setup_key_sizes(void) {
    memset(&keySizes, 0, sizeof(struct key_sizes));

    keySizes.sym_sig_keyLen = DEFAULT_SYM_SIGNING_KEY_LENGTH;
    keySizes.sym_enc_blockSize = DEFAULT_SYM_ENCRYPTION_BLOCK_SIZE;
    keySizes.sym_enc_keyLen = DEFAULT_SYM_ENCRYPTION_KEY_LENGTH;
    keySizes.sym_sig_size = DEFAULT_SYM_SIGNATURE_SIZE;

    keySizes.asym_lcl_sig_size = DEFAULT_ASYM_LOCAL_SIGNATURE_SIZE;
    keySizes.asym_rmt_sig_size = DEFAULT_ASYM_REMOTE_SIGNATURE_SIZE;

    keySizes.asym_rmt_ptext_blocksize = DEFAULT_ASYM_REMOTE_PLAINTEXT_BLOCKSIZE;
    keySizes.asym_rmt_blocksize = DEFAULT_ASYM_REMOTE_BLOCKSIZE;
    keySizes.asym_rmt_enc_key_size = 2048;
    keySizes.asym_lcl_enc_key_size = 1024;
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_initAndDelete) {
    TestingPolicy(&dummyPolicy, dummyCertificate, &fCalled, &keySizes);
    UA_StatusCode retval;

    UA_SecureChannel channel;
    UA_SecureChannel_init(&channel, &UA_ConnectionConfig_default);
    retval = UA_SecureChannel_setSecurityPolicy(&channel, &dummyPolicy, &dummyCertificate);

    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected StatusCode to be good");
    ck_assert_msg(channel.state == UA_SECURECHANNELSTATE_FRESH, "Expected state to be new/fresh");
    ck_assert_msg(fCalled.newContext, "Expected newContext to have been called");
    ck_assert_msg(fCalled.makeCertificateThumbprint,
                  "Expected makeCertificateThumbprint to have been called");
    ck_assert_msg(channel.securityPolicy == &dummyPolicy, "SecurityPolicy not set correctly");

    UA_SecureChannel_close(&channel);
    ck_assert_msg(fCalled.deleteContext, "Expected deleteContext to have been called");

    dummyPolicy.clear(&dummyPolicy);
}END_TEST

Project: open62541
File: check_securechannel.c

process_callback(void *application, UA_SecureChannel *channel,
                 UA_MessageType messageType, UA_UInt32 requestId,
                 UA_ByteString *message) {
    ck_assert_ptr_ne(message, NULL);
    ck_assert_ptr_ne(application, NULL);
    if(message == NULL || application == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    ck_assert_uint_ne(message->length, 0);
    ck_assert_ptr_ne(message->data, NULL);
    int *chunks_processed = (int *)application;
    ++*chunks_processed;
    return UA_STATUSCODE_GOOD;
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_SecurityModeSign) {
    // Configure our channel correctly for OPN messages and setup dummy message
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);
    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGN;

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected function to succeed");
    ck_assert_msg(fCalled.asym_enc, "Expected message to have been encrypted but it was not");
    ck_assert_msg(fCalled.asym_sign, "Expected message to have been signed but it was not");
}END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendSymmetricMessage) {
    // initialize dummy message
    UA_ReadRequest dummyMessage;
    UA_ReadRequest_init(&dummyMessage);
    UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];

    UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
                                                                 &dummyMessage, &dummyType);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    // TODO: expand test
}

Project: open62541
File: check_securechannel.c

main(void) {
    Suite *s = testSuite_SecureChannel();
    SRunner *sr = srunner_create(s);
    srunner_set_fork_status(sr, CK_NOFORK);
    srunner_run_all(sr, CK_NORMAL);
    int number_failed = srunner_ntests_failed(sr);
    srunner_free(sr);
    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

Project: open62541
File: check_securechannel.c

testSuite_SecureChannel(void) {
    Suite *s = suite_create("SecureChannel");

    TCase *tc_initAndDelete = tcase_create("Initialize and delete Securechannel");
    tcase_add_checked_fixture(tc_initAndDelete, setup_funcs_called, teardown_funcs_called);
    tcase_add_checked_fixture(tc_initAndDelete, setup_key_sizes, teardown_key_sizes);
    tcase_add_test(tc_initAndDelete, SecureChannel_initAndDelete);
    suite_add_tcase(s, tc_initAndDelete);

    TCase *tc_sendAsymmetricOPNMessage = tcase_create("Test sendAsymmetricOPNMessage function");
    tcase_add_checked_fixture(tc_sendAsymmetricOPNMessage, setup_funcs_called, teardown_funcs_called);
    tcase_add_checked_fixture(tc_sendAsymmetricOPNMessage, setup_key_sizes, teardown_key_sizes);
    tcase_add_checked_fixture(tc_sendAsymmetricOPNMessage, setup_secureChannel, teardown_secureChannel);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_withoutConnection);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_invalidParameters);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_SecurityModeInvalid);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_SecurityModeNone);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_sentDataIsValid);
#ifdef UA_ENABLE_ENCRYPTION
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_SecurityModeSign);
    tcase_add_test(tc_sendAsymmetricOPNMessage, SecureChannel_sendAsymmetricOPNMessage_SecurityModeSignAndEncrypt);
    tcase_add_test(tc_sendAsymmetricOPNMessage,
                   Securechannel_sendAsymmetricOPNMessage_extraPaddingPresentWhenKeyLargerThan2048Bits);
#endif
    suite_add_tcase(s, tc_sendAsymmetricOPNMessage);

    TCase *tc_sendSymmetricMessage = tcase_create("Test sendSymmetricMessage function");
    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_funcs_called, teardown_funcs_called);
    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_key_sizes, teardown_key_sizes);
    tcase_add_checked_fixture(tc_sendSymmetricMessage, setup_secureChannel, teardown_secureChannel);
    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage);
    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_invalidParameters);
    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeNone);
#ifdef UA_ENABLE_ENCRYPTION
    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeSign);
    tcase_add_test(tc_sendSymmetricMessage, SecureChannel_sendSymmetricMessage_modeSignAndEncrypt);
#endif
    suite_add_tcase(s, tc_sendSymmetricMessage);

    TCase *tc_processBuffer = tcase_create("Test chunk assembly");
    tcase_add_checked_fixture(tc_processBuffer, setup_funcs_called, teardown_funcs_called);
    tcase_add_checked_fixture(tc_processBuffer, setup_key_sizes, teardown_key_sizes);
    tcase_add_checked_fixture(tc_processBuffer, setup_secureChannel, teardown_secureChannel);
    tcase_add_test(tc_processBuffer, SecureChannel_assemblePartialChunks);
    suite_add_tcase(s, tc_processBuffer);

    return s;
}

Project: open62541
File: check_securechannel.c

teardown_secureChannel(void) {
    UA_SecureChannel_close(&testChannel);
    dummyPolicy.clear(&dummyPolicy);
    testingConnection.close(&testingConnection);
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_assemblePartialChunks) {
    int chunks_processed = 0;
    UA_ByteString buffer = UA_BYTESTRING_NULL;

    buffer.data = (UA_Byte *)"HELF \x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
                             "\x10\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff";
    buffer.length = 32;

    UA_StatusCode retval = UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 1);

    buffer.length = 16;

    UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 1);

    buffer.data = &buffer.data[16];
    UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 2);

    buffer.data = (UA_Byte *)"HELF \x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
                             "\x10\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff"
                             "HELF \x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
                             "\x10\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff"
                             "HELF \x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00"
                             "\x10\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff";
    buffer.length = 48;

    UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 3);

    buffer.data = &buffer.data[48];
    buffer.length = 32;

    UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 4);

    buffer.data = &buffer.data[32];
    buffer.length = 16;
    UA_SecureChannel_processBuffer(&testChannel, &chunks_processed, process_callback, &buffer);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_int_eq(chunks_processed, 5);
} END_TEST

Project: open62541
File: check_securechannel.c

teardown_key_sizes(void) {
    memset(&keySizes, 0, sizeof(struct key_sizes));
}

Project: open62541
File: check_securechannel.c

START_TEST(Securechannel_sendAsymmetricOPNMessage_extraPaddingPresentWhenKeyLargerThan2048Bits) {
    keySizes.asym_rmt_enc_key_size = 4096;
    keySizes.asym_rmt_blocksize = 4096;
    keySizes.asym_rmt_ptext_blocksize = 4096;

    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);

    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
    UA_UInt32 requestId = UA_UInt32_random();

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, requestId, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected function to succeed");

    size_t offset = 0;
    UA_TcpMessageHeader header;
    UA_TcpMessageHeader_decodeBinary(&sentData, &offset, &header);
    UA_UInt32 secureChannelId;
    UA_UInt32_decodeBinary(&sentData, &offset, &secureChannelId);

    UA_AsymmetricAlgorithmSecurityHeader asymSecurityHeader;
    UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&sentData, &offset, &asymSecurityHeader);
    ck_assert_msg(UA_ByteString_equal(&dummyCertificate, &asymSecurityHeader.senderCertificate),
                  "Expected the certificate to be equal to the one used  by the secureChannel");
    ck_assert_msg(UA_ByteString_equal(&testChannel.securityPolicy->policyUri,
                                      &asymSecurityHeader.securityPolicyUri),
                  "Expected securityPolicyUri to be equal to the one used by the secureChannel");
    UA_ByteString thumbPrint = {20, testChannel.remoteCertificateThumbprint};
    ck_assert_msg(UA_ByteString_equal(&thumbPrint,
                                      &asymSecurityHeader.receiverCertificateThumbprint),
                  "Expected receiverCertificateThumbprint to be equal to the one set "
                  "in the secureChannel");

    for(size_t i = offset; i < header.messageSize; ++i) {
        sentData.data[i] = (UA_Byte)((sentData.data[i] - 1) % (UA_BYTE_MAX + 1));
    }

    UA_SequenceHeader sequenceHeader;
    UA_SequenceHeader_decodeBinary(&sentData, &offset, &sequenceHeader);
    ck_assert_msg(sequenceHeader.requestId == requestId, "Expected requestId to be %i but was %i",
                  requestId, sequenceHeader.requestId);

    UA_NodeId requestTypeId;
    UA_NodeId_decodeBinary(&sentData, &offset, &requestTypeId);
    ck_assert_msg(UA_NodeId_equal(&UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId, &requestTypeId), "Expected nodeIds to be equal");

    UA_OpenSecureChannelResponse sentResponse;
    UA_OpenSecureChannelResponse_decodeBinary(&sentData, &offset, &sentResponse);

    ck_assert_msg(memcmp(&sentResponse, &dummyResponse, sizeof(UA_OpenSecureChannelResponse)) == 0,
                  "Expected the sent response to be equal to the one supplied to the send function");

    UA_Byte paddingByte = sentData.data[offset];
    UA_Byte extraPaddingByte = sentData.data[sentData.length - keySizes.asym_lcl_sig_size - 1];
    size_t paddingSize = (size_t)paddingByte;
    paddingSize |= extraPaddingByte << 8;

    for(size_t i = 0; i <= paddingSize; ++i) {
        ck_assert_msg(sentData.data[offset + i] == paddingByte,
                      "Expected padding byte %i to be %i but got value %i",
                      (int)i, paddingByte, sentData.data[offset + i]);
    }

    ck_assert_msg(sentData.data[offset + paddingSize + 1] == extraPaddingByte,
                  "Expected extra padding byte to be %i but got %i",
                  extraPaddingByte, sentData.data[offset + paddingSize + 1]);
    ck_assert_msg(sentData.data[offset + paddingSize + 2] == '*',
                  "Expected first byte 42 of signature but got %i",
                  sentData.data[offset + paddingSize + 2]);

    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymSecurityHeader);
    UA_SequenceHeader_clear(&sequenceHeader);
    UA_OpenSecureChannelResponse_clear(&sentResponse);
}END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendSymmetricMessage_invalidParameters) {
    // initialize dummy message
    UA_ReadRequest dummyMessage;
    UA_ReadRequest_init(&dummyMessage);
    UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];

    UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(NULL, 42, UA_MESSAGETYPE_MSG,
                                                                 &dummyMessage, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_HEL, &dummyMessage, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_ACK, &dummyMessage, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_ERR, &dummyMessage, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_OPN, &dummyMessage, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_MSG, NULL, &dummyType);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42,
                                                   UA_MESSAGETYPE_MSG, &dummyMessage, NULL);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");
} END_TEST

Project: open62541
File: check_securechannel.c

teardown_funcs_called(void) {
    memset(&fCalled, 0, sizeof(struct funcs_called));
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_invalidParameters) {
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, NULL,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

    retval = UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, 42, &dummyResponse, NULL);
    ck_assert_msg(retval != UA_STATUSCODE_GOOD, "Expected failure");

}END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendAsymmetricOPNMessage_sentDataIsValid) {
    UA_OpenSecureChannelResponse dummyResponse;
    createDummyResponse(&dummyResponse);

    /* Enable encryption for the SecureChannel */
#ifdef UA_ENABLE_ENCRYPTION
    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
#else
    testChannel.securityMode = UA_MESSAGESECURITYMODE_NONE;
#endif

    UA_UInt32 requestId = UA_UInt32_random();

    UA_StatusCode retval =
        UA_SecureChannel_sendAsymmetricOPNMessage(&testChannel, requestId, &dummyResponse,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected function to succeed");

    size_t offset = 0;
    UA_TcpMessageHeader header;
    UA_TcpMessageHeader_decodeBinary(&sentData, &offset, &header);
    UA_UInt32 secureChannelId;
    UA_UInt32_decodeBinary(&sentData, &offset, &secureChannelId);

    UA_AsymmetricAlgorithmSecurityHeader asymSecurityHeader;
    UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&sentData, &offset, &asymSecurityHeader);

    ck_assert_msg(UA_ByteString_equal(&testChannel.securityPolicy->policyUri,
                                      &asymSecurityHeader.securityPolicyUri),
                  "Expected securityPolicyUri to be equal to the one used by the secureChannel");

#ifdef UA_ENABLE_ENCRYPTION
    ck_assert_msg(UA_ByteString_equal(&dummyCertificate, &asymSecurityHeader.senderCertificate),
                  "Expected the certificate to be equal to the one used  by the secureChannel");

    UA_ByteString thumbPrint = {20, testChannel.remoteCertificateThumbprint};
    ck_assert_msg(UA_ByteString_equal(&thumbPrint,
                                      &asymSecurityHeader.receiverCertificateThumbprint),
                  "Expected receiverCertificateThumbprint to be equal to the one set "
                  "in the secureChannel");

    /* Dummy encryption */
    for(size_t i = offset; i < header.messageSize; ++i) {
        sentData.data[i] = (UA_Byte)((sentData.data[i] - 1) % (UA_BYTE_MAX + 1));
    }
#endif

    UA_SequenceHeader sequenceHeader;
    UA_SequenceHeader_decodeBinary(&sentData, &offset, &sequenceHeader);
    ck_assert_msg(sequenceHeader.requestId == requestId, "Expected requestId to be %i but was %i",
                  requestId,
                  sequenceHeader.requestId);

    UA_NodeId requestTypeId;
    UA_NodeId_decodeBinary(&sentData, &offset, &requestTypeId);
    ck_assert_msg(UA_NodeId_equal(&UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId, &requestTypeId), "Expected nodeIds to be equal");

    UA_OpenSecureChannelResponse sentResponse;
    UA_OpenSecureChannelResponse_decodeBinary(&sentData, &offset, &sentResponse);

    ck_assert_msg(memcmp(&sentResponse, &dummyResponse, sizeof(UA_OpenSecureChannelResponse)) == 0,
                  "Expected the sent response to be equal to the one supplied to the send function");

#ifdef UA_ENABLE_ENCRYPTION
    UA_Byte paddingByte = sentData.data[offset];
    size_t paddingSize = (size_t)paddingByte;

    for(size_t i = 0; i <= paddingSize; ++i) {
        ck_assert_msg(sentData.data[offset + i] == paddingByte,
                      "Expected padding byte %i to be %i but got value %i",
                      (int)i, paddingByte, sentData.data[offset + i]);
    }

    ck_assert_msg(sentData.data[offset + paddingSize + 1] == '*', "Expected first byte of signature");
#endif

    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymSecurityHeader);
    UA_SequenceHeader_clear(&sequenceHeader);
    UA_OpenSecureChannelResponse_clear(&sentResponse);
} END_TEST

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendSymmetricMessage_modeSignAndEncrypt)
{
    // initialize dummy message
    UA_ReadRequest dummyMessage;
    UA_ReadRequest_init(&dummyMessage);
    UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];

    testChannel.securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;

    UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
                                                                 &dummyMessage, &dummyType);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_msg(fCalled.sym_sign, "Expected message to have been signed");
    ck_assert_msg(fCalled.sym_enc, "Expected message to have been encrypted");
} END_TEST

Project: open62541
File: check_securechannel.c

setup_secureChannel(void) {
    TestingPolicy(&dummyPolicy, dummyCertificate, &fCalled, &keySizes);
    UA_SecureChannel_init(&testChannel, &UA_ConnectionConfig_default);
    UA_SecureChannel_setSecurityPolicy(&testChannel, &dummyPolicy, &dummyCertificate);

    testingConnection =
        createDummyConnection(UA_ConnectionConfig_default.sendBufferSize, &sentData);
    UA_Connection_attachSecureChannel(&testingConnection, &testChannel);
    testChannel.connection = &testingConnection;

    testChannel.state = UA_SECURECHANNELSTATE_OPEN;
}

Project: open62541
File: check_securechannel.c

setup_funcs_called(void) {
    memset(&fCalled, 0, sizeof(struct funcs_called));
}

Project: open62541
File: check_securechannel.c

START_TEST(SecureChannel_sendSymmetricMessage_modeNone) {
    // initialize dummy message
    UA_ReadRequest dummyMessage;
    UA_ReadRequest_init(&dummyMessage);
    UA_DataType dummyType = UA_TYPES[UA_TYPES_READREQUEST];

    testChannel.securityMode = UA_MESSAGESECURITYMODE_NONE;

    UA_StatusCode retval = UA_SecureChannel_sendSymmetricMessage(&testChannel, 42, UA_MESSAGETYPE_MSG,
                                                                 &dummyMessage, &dummyType);
    ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Expected success");
    ck_assert_msg(!fCalled.sym_sign, "Expected message to not have been signed");
    ck_assert_msg(!fCalled.sym_enc, "Expected message to not have been encrypted");
} END_TEST