// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #ifdef __cplusplus #include #else #include #endif static void* my_gballoc_malloc(size_t size) { return malloc(size); } static void my_gballoc_free(void* s) { free(s); } #ifdef __cplusplus #include #else #include #endif #include "testrunnerswitcher.h" #include "umock_c/umock_c.h" #include "openssl/ssl.h" #include "openssl/x509.h" #include "openssl/err.h" #include "openssl/opensslv.h" #include "openssl/pem.h" #include "openssl/bio.h" #include "openssl/rsa.h" #include "openssl/evp.h" #ifndef OPENSSL_NO_ENGINE #include "openssl/engine.h" #endif // OPENSSL_NO_ENGINE #include "azure_c_shared_utility/x509_openssl.h" #include "umock_c/umocktypes_charptr.h" #include "umock_c/umock_c_negative_tests.h" #define ENABLE_MOCKS #include "azure_c_shared_utility/gballoc.h" #include "umock_c/umock_c_prod.h" #ifndef VALIDATED_PTR_ARG #define VALIDATED_PTR_ARG NULL #endif #ifndef VALIDATED_NUM_ARG #define VALIDATED_NUM_ARG 0 #endif /*from openssl/bio.h*/ /*the below function has different signatures on different versions of OPENSSL*/ /* |openssl version (number) | openssl string | BIO_new_mem_buf prototype | Observations | |-------------------------|----------------------------------|---------------------------------------------------|---------------------------------| | 0x1000106fL | OpenSSL 1.0.1f 6 Jan 2014 | BIO *BIO_new_mem_buf(void *buf, int len); | Ubuntu 14.04 | | 0x1000204fL | OpenSSL 1.0.2d 9 Jul 2015 | BIO *BIO_new_mem_buf(void *buf, int len); | Ubuntu 15.10 | | 0x1000207fL | OpenSSL 1.0.2g-fips 1 Mar 2016 | BIO *BIO_new_mem_buf(const void *buf, int len); | Ubuntu 16.10 | | 0x1010007fL | OpenSSL 1.0.2g-fips 1 Mar 2016 | BIO *BIO_new(const BIO_METHOD *type); | Ubuntu 18.04 | */ MOCKABLE_FUNCTION(,int, BIO_free, BIO *,a); #if OPENSSL_VERSION_NUMBER >= 0x1010007fL MOCKABLE_FUNCTION(, BIO *, BIO_new, const BIO_METHOD *, type); MOCKABLE_FUNCTION(, const BIO_METHOD *, BIO_s_mem); #else MOCKABLE_FUNCTION(, BIO *, BIO_new, BIO_METHOD *, type); MOCKABLE_FUNCTION(, BIO_METHOD *, BIO_s_mem); #endif MOCKABLE_FUNCTION(, BIO *, BIO_mem, BIO_METHOD *, type); MOCKABLE_FUNCTION(, int, BIO_puts, BIO *, bp, const char *, buf); #if OPENSSL_VERSION_NUMBER >= 0x1000207fL MOCKABLE_FUNCTION(,BIO *,BIO_new_mem_buf, const void *,buf, int, len); #else MOCKABLE_FUNCTION(, BIO *, BIO_new_mem_buf, void *, buf, int, len); #endif /*from openssl/rsa.h*/ MOCKABLE_FUNCTION(, void, RSA_free, RSA *,rsa); /*from openssl/x509.h*/ MOCKABLE_FUNCTION(, void, X509_free, X509 *, a); /*from openssl/pem.h*/ MOCKABLE_FUNCTION(, X509 *, PEM_read_bio_X509, BIO *, bp, X509 **, x, pem_password_cb *, cb, void *, u); MOCKABLE_FUNCTION(, RSA *, PEM_read_bio_RSAPrivateKey, BIO *,bp, RSA **,x, pem_password_cb *,cb, void *,u); MOCKABLE_FUNCTION(, RSA*, EVP_PKEY_get1_RSA, EVP_PKEY*, pkey); /*from openssl/ssl.h*/ MOCKABLE_FUNCTION(,int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *,ctx, RSA *,rsa); MOCKABLE_FUNCTION(,int, SSL_CTX_use_certificate, SSL_CTX *,ctx, X509*, x); MOCKABLE_FUNCTION(, X509_STORE *, SSL_CTX_get_cert_store, const SSL_CTX *, ssl_ctx); /*from openssl/err.h*/ MOCKABLE_FUNCTION(,unsigned long, ERR_get_error); MOCKABLE_FUNCTION(, char *,ERR_error_string, unsigned long, e, char *,buf); MOCKABLE_FUNCTION(, unsigned long, ERR_peek_error); /*from openssl/x509_vfy.h*/ MOCKABLE_FUNCTION(,int, X509_STORE_add_cert, X509_STORE *, ctx, X509 *, x); typedef void (*x509_FREE_FUNC)(void*); MOCKABLE_FUNCTION(, void, sk_pop_free, _STACK*, st, x509_FREE_FUNC, free_func); MOCKABLE_FUNCTION(, void, EVP_PKEY_free, EVP_PKEY*, pkey); MOCKABLE_FUNCTION(, X509*, PEM_read_bio_X509_AUX, BIO*, bp, X509**, x, pem_password_cb*, cb, void*, u); MOCKABLE_FUNCTION(, EVP_PKEY*, PEM_read_bio_PrivateKey, BIO*, bp, EVP_PKEY**, x, pem_password_cb*, cb, void*, u); MOCKABLE_FUNCTION(, int, SSL_CTX_use_PrivateKey, SSL_CTX*, ctx, EVP_PKEY*, pkey); MOCKABLE_FUNCTION(, long, SSL_CTX_ctrl, SSL_CTX*, ctx, int, cmd, long, larg, void*, parg); MOCKABLE_FUNCTION(, unsigned long, ERR_peek_last_error); MOCKABLE_FUNCTION(, void, ERR_clear_error); #ifndef OPENSSL_NO_ENGINE MOCKABLE_FUNCTION(, int, ENGINE_init, ENGINE*, e); MOCKABLE_FUNCTION(, int, ENGINE_set_default, ENGINE*, e, unsigned int, flags); MOCKABLE_FUNCTION(, EVP_PKEY*, ENGINE_load_private_key, ENGINE*, e, const char*, key_id, UI_METHOD*, ui_method, void*, callback_data); MOCKABLE_FUNCTION(, int, ENGINE_finish, ENGINE*, e); #endif // OPENSSL_NO_ENGINE #ifndef __APPLE__ MOCKABLE_FUNCTION(, int, EVP_PKEY_id, const EVP_PKEY*, pkey); #endif #undef ENABLE_MOCKS /*the below function has different signatures on different versions of OPENSSL*/ #if OPENSSL_VERSION_NUMBER >= 0x1000207fL static BIO* my_BIO_new_mem_buf(const void * buf, int len) #else static BIO* my_BIO_new_mem_buf(void * buf, int len) #endif { (void)len, (void)buf; return (BIO*)my_gballoc_malloc(1); } static int my_BIO_free(BIO * a) { my_gballoc_free(a); return 0; } #if OPENSSL_VERSION_NUMBER >= 0x1010007fL static BIO *my_BIO_new(const BIO_METHOD *type) #else static BIO *my_BIO_new(BIO_METHOD *type) #endif { (void)type; return (BIO*)my_gballoc_malloc(1); } static void my_RSA_free(RSA * rsa) { my_gballoc_free(rsa); } static void my_X509_free(X509 * a) { my_gballoc_free(a); } static X509* my_PEM_read_bio_X509_AUX(BIO* bp, X509** x, pem_password_cb* cb, void* u) { (void)u, (void)cb, (void)x, (void)bp; return (X509*)my_gballoc_malloc(1); } static long my_SSL_CTX_ctrl(SSL_CTX* ctx, int cmd, long larg, void* parg) { (void)ctx; (void)cmd; (void)larg; my_gballoc_free(parg); return 1; } static RSA* my_EVP_PKEY_get1_RSA(EVP_PKEY* pkey) { (void)pkey; return (RSA*)my_gballoc_malloc(1); } static X509 * my_PEM_read_bio_X509(BIO * bp, X509 ** x, pem_password_cb * cb, void * u) { (void)u, (void)cb, (void)x, (void)bp; return (X509*)my_gballoc_malloc(1); } static RSA * my_PEM_read_bio_RSAPrivateKey(BIO * bp, RSA ** x, pem_password_cb * cb, void * u) { (void)u, (void)cb, (void)x, (void)bp; return (RSA*)my_gballoc_malloc(1); } static TEST_MUTEX_HANDLE g_testByTest; static TEST_MUTEX_HANDLE g_dllByDll; static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code) { (void)error_code; ASSERT_FAIL("umock_c reported error"); } typedef struct SSL_TEST_CTX_tag { void* extra_certs; } SSL_TEST_CTX; typedef struct replace_evp_pkey_st_tag { int type; } replace_evp_pkey_st; #define TEST_SSL_CTX ((SSL_CTX*)(0x42)) #define TEST_CERTIFICATE_1 "one certificate" #define TEST_X509_STORE (X509_STORE *)"le store" #define TEST_BIO_METHOD (BIO_METHOD*)"le method" #define TEST_BIO (BIO*)"le bio" #ifndef OPENSSL_NO_ENGINE #define TEST_ENGINE (ENGINE*)"the engine" #endif // OPENSSL_NO_ENGINE #define TEST_KEY_ID "the key id" static const char* TEST_PUBLIC_CERTIFICATE = "PUBLIC CERTIFICATE"; static const char* TEST_PRIVATE_CERTIFICATE = "PRIVATE KEY"; static BIO* TEST_BIO_CERT = (BIO*)0x11; static X509* TEST_X509 = (X509*)0x13; static SSL_CTX* TEST_SSL_CTX_STRUCTURE; static SSL_TEST_CTX g_replace_ctx; static EVP_PKEY* g_evp_pkey; static replace_evp_pkey_st g_replace_evp_key; BEGIN_TEST_SUITE(x509_openssl_unittests) TEST_SUITE_INITIALIZE(a) { g_evp_pkey = (EVP_PKEY*)&g_replace_evp_key; g_testByTest = TEST_MUTEX_CREATE(); ASSERT_IS_NOT_NULL(g_testByTest); (void)umock_c_init(on_umock_c_error); (void)umocktypes_charptr_register_types(); REGISTER_GLOBAL_MOCK_HOOK(gballoc_malloc, my_gballoc_malloc); REGISTER_GLOBAL_MOCK_FAIL_RETURN(gballoc_malloc, NULL); REGISTER_GLOBAL_MOCK_HOOK(gballoc_free, my_gballoc_free); REGISTER_GLOBAL_MOCK_HOOK(BIO_new_mem_buf, my_BIO_new_mem_buf); REGISTER_GLOBAL_MOCK_FAIL_RETURN(BIO_new_mem_buf, NULL); REGISTER_GLOBAL_MOCK_HOOK(PEM_read_bio_X509, my_PEM_read_bio_X509); REGISTER_GLOBAL_MOCK_FAIL_RETURN(PEM_read_bio_X509, NULL); REGISTER_GLOBAL_MOCK_HOOK(PEM_read_bio_RSAPrivateKey, my_PEM_read_bio_RSAPrivateKey); REGISTER_GLOBAL_MOCK_FAIL_RETURN(PEM_read_bio_X509, NULL); REGISTER_GLOBAL_MOCK_RETURNS(SSL_CTX_use_certificate, 1, 0); REGISTER_GLOBAL_MOCK_RETURNS(BIO_s_mem, TEST_BIO_METHOD, NULL); REGISTER_GLOBAL_MOCK_HOOK(BIO_new, my_BIO_new); REGISTER_GLOBAL_MOCK_FAIL_RETURN(BIO_new, NULL); REGISTER_GLOBAL_MOCK_RETURNS(BIO_puts, strlen(TEST_CERTIFICATE_1), strlen(TEST_CERTIFICATE_1)-1); REGISTER_GLOBAL_MOCK_RETURNS(SSL_CTX_get_cert_store, TEST_X509_STORE, NULL); REGISTER_GLOBAL_MOCK_RETURNS(X509_STORE_add_cert, __LINE__, 0); REGISTER_GLOBAL_MOCK_RETURNS(SSL_CTX_use_RSAPrivateKey, 1, 0); REGISTER_GLOBAL_MOCK_HOOK(BIO_free, my_BIO_free); REGISTER_GLOBAL_MOCK_HOOK(RSA_free, my_RSA_free); REGISTER_GLOBAL_MOCK_HOOK(X509_free, my_X509_free); REGISTER_GLOBAL_MOCK_HOOK(EVP_PKEY_get1_RSA, my_EVP_PKEY_get1_RSA); REGISTER_GLOBAL_MOCK_FAIL_RETURN(EVP_PKEY_get1_RSA, NULL); REGISTER_GLOBAL_MOCK_RETURNS(PEM_read_bio_PrivateKey, g_evp_pkey, NULL); REGISTER_GLOBAL_MOCK_RETURNS(BIO_new_mem_buf, TEST_BIO_CERT, NULL); REGISTER_GLOBAL_MOCK_HOOK(PEM_read_bio_X509_AUX, my_PEM_read_bio_X509_AUX); REGISTER_GLOBAL_MOCK_RETURNS(SSL_CTX_use_PrivateKey, 1, 0); REGISTER_GLOBAL_MOCK_HOOK(SSL_CTX_ctrl, my_SSL_CTX_ctrl); #ifndef OPENSSL_NO_ENGINE REGISTER_GLOBAL_MOCK_RETURNS(ENGINE_init, 1, 0); REGISTER_GLOBAL_MOCK_RETURNS(ENGINE_set_default, 1, 0); REGISTER_GLOBAL_MOCK_RETURNS(ENGINE_load_private_key, g_evp_pkey, NULL); REGISTER_GLOBAL_MOCK_RETURNS(ENGINE_finish, 1, 0); #endif // OPENSSL_NO_ENGINE } TEST_SUITE_CLEANUP(TestClassCleanup) { umock_c_deinit(); TEST_MUTEX_DESTROY(g_testByTest); } TEST_FUNCTION_INITIALIZE(initialize) { umock_c_reset_all_calls(); memset(&g_replace_ctx, 0, sizeof(SSL_TEST_CTX) ); TEST_SSL_CTX_STRUCTURE = (SSL_CTX*)&g_replace_ctx; memset(&g_replace_evp_key, 0, sizeof(replace_evp_pkey_st)); g_evp_pkey = (EVP_PKEY*)&g_replace_evp_key; } TEST_FUNCTION_CLEANUP(cleans) { } static int should_skip_index(size_t current_index, const size_t skip_array[], size_t length) { int result = 0; for (size_t index = 0; index < length; index++) { if (current_index == skip_array[index]) { result = __LINE__; break; } } return result; } static void setup_load_alias_key_cert_mocks(bool is_rsa_cert) { if (is_rsa_cert) { g_replace_evp_key.type = EVP_PKEY_RSA; STRICT_EXPECTED_CALL(EVP_PKEY_get1_RSA(g_evp_pkey)); STRICT_EXPECTED_CALL(SSL_CTX_use_RSAPrivateKey(TEST_SSL_CTX_STRUCTURE, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(RSA_free(IGNORED_PTR_ARG) ); } else { g_replace_evp_key.type = EVP_PKEY_EC; STRICT_EXPECTED_CALL(SSL_CTX_use_PrivateKey(TEST_SSL_CTX_STRUCTURE, g_evp_pkey)); } } static void setup_load_certificate_chain_mocks() { STRICT_EXPECTED_CALL(BIO_new_mem_buf((void*)TEST_PUBLIC_CERTIFICATE, -1)); STRICT_EXPECTED_CALL(PEM_read_bio_X509_AUX(IGNORED_PTR_ARG, NULL, NULL, NULL)); STRICT_EXPECTED_CALL(SSL_CTX_use_certificate(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) // Actual macro name: SSL_CTX_clear_extra_chain_certs: STRICT_EXPECTED_CALL(SSL_CTX_ctrl(TEST_SSL_CTX_STRUCTURE, SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS, 0, NULL)); #endif STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, NULL, NULL, NULL)); // Actual macro name: SSL_CTX_add_extra_chain_cert: STRICT_EXPECTED_CALL(SSL_CTX_ctrl(TEST_SSL_CTX_STRUCTURE, SSL_CTRL_EXTRA_CHAIN_CERT, IGNORED_NUM_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, NULL, NULL, NULL)) .SetReturn(NULL); // Needed because the x509 needs not to be free STRICT_EXPECTED_CALL(X509_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(BIO_free(IGNORED_PTR_ARG)); } static void setup_add_credentials_pem_file(bool is_rsa_cert) { // x509_openssl_add_pem_file_key STRICT_EXPECTED_CALL(BIO_new_mem_buf((char*)TEST_PRIVATE_CERTIFICATE, -1)); STRICT_EXPECTED_CALL(PEM_read_bio_PrivateKey(IGNORED_PTR_ARG, NULL, NULL, NULL)); #ifndef __APPLE__ STRICT_EXPECTED_CALL(EVP_PKEY_id(IGNORED_PTR_ARG)).SetReturn(is_rsa_cert ? EVP_PKEY_RSA : EVP_PKEY_EC); #endif setup_load_alias_key_cert_mocks(is_rsa_cert); STRICT_EXPECTED_CALL(EVP_PKEY_free(g_evp_pkey)); STRICT_EXPECTED_CALL(BIO_free(IGNORED_PTR_ARG)); setup_load_certificate_chain_mocks(); } #ifndef OPENSSL_NO_ENGINE static void setup_add_credentials_engine() { // x509_openssl_add_pem_file_key STRICT_EXPECTED_CALL(ENGINE_init(TEST_ENGINE)); STRICT_EXPECTED_CALL(ENGINE_set_default(TEST_ENGINE, ENGINE_METHOD_ALL)); STRICT_EXPECTED_CALL(ENGINE_load_private_key(TEST_ENGINE, TEST_KEY_ID, NULL, NULL)); setup_load_alias_key_cert_mocks(false); STRICT_EXPECTED_CALL(EVP_PKEY_free(g_evp_pkey)); STRICT_EXPECTED_CALL(ENGINE_finish(TEST_ENGINE)); setup_load_certificate_chain_mocks(); } #endif // OPENSSL_NO_ENGINE /*Tests_SRS_X509_OPENSSL_02_001: [ If any argument is NULL then x509_openssl_add_credentials shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_credentials_with_NULL_SSL_CTX_fails) { //arrange //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(NULL, TEST_PUBLIC_CERTIFICATE, "privatekey", KEY_TYPE_DEFAULT, NULL); #else // OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(NULL, TEST_PUBLIC_CERTIFICATE, "privatekey", KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } /*Tests_SRS_X509_OPENSSL_02_001: [ If any argument is NULL then x509_openssl_add_credentials shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_credentials_with_NULL_certificate_fails) { //arrange //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, NULL, "privatekey", KEY_TYPE_DEFAULT, NULL); #else // OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, NULL, "privatekey", KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } /*Tests_SRS_X509_OPENSSL_02_001: [ If any argument is NULL then x509_openssl_add_credentials shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_credentials_with_NULL_privatekey_fails) { //arrange //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, TEST_PUBLIC_CERTIFICATE, NULL, KEY_TYPE_DEFAULT, TEST_ENGINE); #else // OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, TEST_PUBLIC_CERTIFICATE, NULL, KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } TEST_FUNCTION(x509_openssl_engine_add_credentials_with_NULL_certificate_fails) { //arrange //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, NULL, "privatekey", KEY_TYPE_ENGINE, TEST_ENGINE); #else int result = x509_openssl_add_credentials(TEST_SSL_CTX, NULL, "privatekey", KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } TEST_FUNCTION(x509_openssl_engine_add_credentials_with_NULL_privatekey_fails) { //arrange //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX, TEST_PUBLIC_CERTIFICATE, NULL, KEY_TYPE_ENGINE, TEST_ENGINE); #else int result = x509_openssl_add_credentials(TEST_SSL_CTX, TEST_PUBLIC_CERTIFICATE, NULL, KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } #ifndef OPENSSL_NO_ENGINE TEST_FUNCTION(x509_openssl_engine_add_credentials_with_NULL_engine_fails) { //arrange //act int result = x509_openssl_add_credentials(TEST_SSL_CTX, TEST_PUBLIC_CERTIFICATE, "privatekey", KEY_TYPE_ENGINE, NULL); //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //cleanup } #endif // OPENSSL_NO_ENGINE /*Tests_SRS_X509_OPENSSL_02_002: [ x509_openssl_add_credentials shall use BIO_new_mem_buf to create a memory BIO from the x509 certificate. ] */ /*Tests_SRS_X509_OPENSSL_02_003: [ x509_openssl_add_credentials shall use PEM_read_bio_X509 to read the x509 certificate. ] */ /*Tests_SRS_X509_OPENSSL_02_004: [ x509_openssl_add_credentials shall use BIO_new_mem_buf to create a memory BIO from the x509 privatekey. ] */ /*Tests_SRS_X509_OPENSSL_02_005: [ x509_openssl_add_credentials shall use PEM_read_bio_RSAPrivateKey to read the x509 private key. ] */ /*Tests_SRS_X509_OPENSSL_02_006: [ x509_openssl_add_credentials shall use SSL_CTX_use_certificate to load the certicate into the SSL context. ] */ /*Tests_SRS_X509_OPENSSL_02_007: [ x509_openssl_add_credentials shall use SSL_CTX_use_RSAPrivateKey to load the private key into the SSL context. ]*/ /*Tests_SRS_X509_OPENSSL_02_008: [ If no error occurs, then x509_openssl_add_credentials shall succeed and return 0. ] */ TEST_FUNCTION(x509_openssl_add_credentials_rsa_happy_path) { setup_add_credentials_pem_file(true); //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT, NULL); #else // OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_EQUAL(int, 0, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup } TEST_FUNCTION(x509_openssl_add_credentials_ecc_happy_path) { setup_add_credentials_pem_file(false); //act #ifndef OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT, NULL); #else // OPENSSL_NO_ENGINE int result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_EQUAL(int, 0, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup } #ifndef OPENSSL_NO_ENGINE TEST_FUNCTION(x509_openssl_engine_add_credentials_happy_path) { setup_add_credentials_engine(); //act int result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_KEY_ID, KEY_TYPE_ENGINE, TEST_ENGINE); //assert ASSERT_ARE_EQUAL(int, 0, result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup } #endif // OPENSSL_NO_ENGINE void x509_openssl_add_credentials_fails(bool is_rsa, bool use_engine) { //arrange umock_c_reset_all_calls(); int negativeTestsInitResult = umock_c_negative_tests_init(); ASSERT_ARE_EQUAL(int, 0, negativeTestsInitResult); if (!use_engine) { setup_add_credentials_pem_file(is_rsa); } #ifndef OPENSSL_NO_ENGINE else { setup_add_credentials_engine(); } #endif // OPENSSL_NO_ENGINE umock_c_negative_tests_snapshot(); #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) #ifdef __APPLE__ size_t calls_cannot_fail_rsa[] = { 4, 5, 6, 10, 12, 13, 14 }; size_t calls_cannot_fail_ecc[] = { 3, 4, 8, 10, 11, 12} ; size_t calls_cannot_fail_engine[] = { 4, 9, 11, 12, 13 }; #else size_t calls_cannot_fail_rsa[] = { 2, 5, 6, 7, 11, 12, 14, 15, 16 }; size_t calls_cannot_fail_ecc[] = { 2, 4, 5, 9, 10, 12, 13, 14 }; size_t calls_cannot_fail_engine[] = { 4, 9, 10, 12, 13, 14 }; #endif #else #ifdef __APPLE__ size_t calls_cannot_fail_rsa[] = { 4, 5, 6, 10, 12, 13, 14 }; size_t calls_cannot_fail_ecc[] = { 3, 4, 8, 10, 11, 12 }; size_t calls_cannot_fail_engine[] = {4, 9, 11, 12, 13}; #else size_t calls_cannot_fail_rsa[] = { 2, 5, 6, 7, 11, 13, 14, 15, 16 }; size_t calls_cannot_fail_ecc[] = { 2, 4, 5, 9, 11, 12, 13, 14 }; size_t calls_cannot_fail_engine[] = { 4, 9, 11, 12, 13, 14 }; #endif #endif size_t *calls_cannot_fail; size_t calls_cannot_fail_size; if (!use_engine) { calls_cannot_fail = is_rsa ? calls_cannot_fail_rsa : calls_cannot_fail_ecc; calls_cannot_fail_size = is_rsa ? sizeof(calls_cannot_fail_rsa) / sizeof(calls_cannot_fail_rsa[0]) : sizeof(calls_cannot_fail_ecc) / sizeof(calls_cannot_fail_ecc[0]); } #ifndef OPENSSL_NO_ENGINE else { calls_cannot_fail = calls_cannot_fail_engine; calls_cannot_fail_size = sizeof(calls_cannot_fail_engine) / sizeof(calls_cannot_fail_engine[0]); } #endif // OPENSSL_NO_ENGINE //act int result; size_t count = umock_c_negative_tests_call_count(); for (size_t index = 0; index < count; index++) { if (should_skip_index(index, calls_cannot_fail, calls_cannot_fail_size) != 0) { continue; } umock_c_negative_tests_reset(); umock_c_negative_tests_fail_call(index); char tmp_msg[128]; sprintf(tmp_msg, "x509_openssl_add_credentials failure in test %lu/%lu", (unsigned long)index, (unsigned long)count); g_replace_ctx.extra_certs = NULL; if (!use_engine) { #ifndef OPENSSL_NO_ENGINE result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT, NULL); #else // OPENSSL_NO_ENGINE result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_PRIVATE_CERTIFICATE, KEY_TYPE_DEFAULT); #endif // OPENSSL_NO_ENGINE } #ifndef OPENSSL_NO_ENGINE else { result = x509_openssl_add_credentials(TEST_SSL_CTX_STRUCTURE, TEST_PUBLIC_CERTIFICATE, TEST_KEY_ID, KEY_TYPE_ENGINE, TEST_ENGINE); } #endif // OPENSSL_NO_ENGINE //assert ASSERT_ARE_NOT_EQUAL(int, 0, result, tmp_msg); } //cleanup umock_c_negative_tests_deinit(); } /*Tests_SRS_X509_OPENSSL_02_009: [ Otherwise x509_openssl_add_credentials shall fail and return a non-zero number. ]*/ TEST_FUNCTION(x509_openssl_add_rsa_credentials_fails) { x509_openssl_add_credentials_fails(/* is_rsa: */ true, /* use_engine: */ false); } /*Tests_SRS_X509_OPENSSL_02_009: [ Otherwise x509_openssl_add_credentials shall fail and return a non-zero number. ]*/ TEST_FUNCTION(x509_openssl_add_ecc_credentials_fails) { x509_openssl_add_credentials_fails(/* is_rsa: */ false, /* use_engine: */ false); } #ifndef OPENSSL_NO_ENGINE TEST_FUNCTION(x509_openssl_add_engine_credentials_fails) { x509_openssl_add_credentials_fails(/* is_rsa: */ false, /* use_engine: */ true); } #endif // OPENSSL_NO_ENGINE /*Tests_SRS_X509_OPENSSL_02_010: [ If ssl_ctx is NULL then x509_openssl_add_certificates shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_certificates_with_NULL_ssl_ctx_fails) { //arrange //act int result = x509_openssl_add_certificates(NULL, "a"); //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //clean } /*Tests_SRS_X509_OPENSSL_02_011: [ If certificates is NULL then x509_openssl_add_certificates shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_certificates_with_NULL_certificates_fails) { //arrange //act int result = x509_openssl_add_certificates(TEST_SSL_CTX, NULL); //assert ASSERT_ARE_NOT_EQUAL(int, 0, result); //clean } /*Tests_SRS_X509_OPENSSL_02_012: [ x509_openssl_add_certificates shall get the memory BIO method function by calling BIO_s_mem. ]*/ /*Tests_SRS_X509_OPENSSL_02_013: [ x509_openssl_add_certificates shall create a new memory BIO by calling BIO_new. ]*/ /*Tests_SRS_X509_OPENSSL_02_014: [ x509_openssl_add_certificates shall load certificates into the memory BIO by a call to BIO_puts. ]*/ /*Tests_SRS_X509_OPENSSL_02_015: [ x509_openssl_add_certificates shall retrieve each certificate by a call to PEM_read_bio_X509. ]*/ /*Tests_SRS_X509_OPENSSL_02_016: [ x509_openssl_add_certificates shall add the certificate to the store by a call to X509_STORE_add_cert. ]*/ /*Tests_SRS_X509_OPENSSL_02_019: [ Otherwise, x509_openssl_add_certificates shall succeed and return 0. ]*/ TEST_FUNCTION(x509_openssl_add_certificates_1_certificate_happy_path) { //arrange int result; STRICT_EXPECTED_CALL(SSL_CTX_get_cert_store(TEST_SSL_CTX)); STRICT_EXPECTED_CALL(BIO_s_mem()); STRICT_EXPECTED_CALL(BIO_new(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(BIO_puts(IGNORED_PTR_ARG, TEST_CERTIFICATE_1)); STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(X509_STORE_add_cert(IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(X509_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .SetReturn(NULL); //act result = x509_openssl_add_certificates(TEST_SSL_CTX, TEST_CERTIFICATE_1); //assert ASSERT_ARE_EQUAL(int, 0, result); //clean } void x509_openssl_add_certificates_1_certificate_which_exists_inert_path(void) { STRICT_EXPECTED_CALL(SSL_CTX_get_cert_store(TEST_SSL_CTX)); STRICT_EXPECTED_CALL(BIO_s_mem()); STRICT_EXPECTED_CALL(BIO_new(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(BIO_puts(IGNORED_PTR_ARG, TEST_CERTIFICATE_1)); STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(X509_STORE_add_cert(IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .SetReturn(0); STRICT_EXPECTED_CALL(ERR_peek_error()) .SetReturn(X509_R_CERT_ALREADY_IN_HASH_TABLE); STRICT_EXPECTED_CALL(X509_free(IGNORED_PTR_ARG)); STRICT_EXPECTED_CALL(PEM_read_bio_X509(IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG, IGNORED_PTR_ARG)) .SetReturn(NULL); } /*Tests_SRS_X509_OPENSSL_02_017: [ If X509_STORE_add_cert returns with error and that error is X509_R_CERT_ALREADY_IN_HASH_TABLE then x509_openssl_add_certificates shall ignore it as the certificate is already in the store. ]*/ TEST_FUNCTION(x509_openssl_add_certificates_1_certificate_which_exists_happy_path) { //arrange int result; x509_openssl_add_certificates_1_certificate_which_exists_inert_path(); //act result = x509_openssl_add_certificates(TEST_SSL_CTX, TEST_CERTIFICATE_1); //assert ASSERT_ARE_EQUAL(int, 0, result); //clean } /*Tests_SRS_X509_OPENSSL_02_018: [ In case of any failure x509_openssl_add_certificates shall fail and return a non-zero value. ]*/ TEST_FUNCTION(x509_openssl_add_certificates_1_certificate_which_exists_unhappy_paths) { //arrange umock_c_reset_all_calls(); int negativeTestsInitResult = umock_c_negative_tests_init(); ASSERT_ARE_EQUAL(int, 0, negativeTestsInitResult); x509_openssl_add_certificates_1_certificate_which_exists_inert_path(); umock_c_negative_tests_snapshot(); size_t calls_cannot_fail[] = { 4, 5, 7, 8 }; int result; size_t count = umock_c_negative_tests_call_count(); for (size_t index = 0; index < count; index++) { if (should_skip_index(index, calls_cannot_fail, sizeof(calls_cannot_fail) / sizeof(calls_cannot_fail[0])) != 0) { continue; } umock_c_negative_tests_reset(); umock_c_negative_tests_fail_call(index); char tmp_msg[128]; sprintf(tmp_msg, "x509_openssl_add_credentials failure in test %lu/%lu", (unsigned long)index, (unsigned long)count); //act result = x509_openssl_add_certificates(TEST_SSL_CTX, TEST_CERTIFICATE_1); //assert ASSERT_ARE_NOT_EQUAL(int, 0, result, tmp_msg); } //clean umock_c_negative_tests_deinit(); } END_TEST_SUITE(x509_openssl_unittests)