diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 2a471d4..65950bb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -14,7 +14,7 @@ jobs: test-openssl1-1: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [macos-latest, windows-latest] # Stops killing other jobs when one fails fail-fast: false @@ -25,20 +25,25 @@ jobs: - name: Install OpenSSL on MacOS if: matrix.os == 'macos-latest' - # We want 1.1.1 version max as the 3.0 is default on MacOS otherwise - run: brew install openssl@1.1 - + run: | + brew uninstall openssl --ignore-dependencies openssl + brew install openssl@1.1 + - name: Install OpenSSL on Windows if: matrix.os == 'windows-latest' - run: choco install openssl + run: | + rd -r "C:/Program Files/OpenSSL" + choco install openssl --version=1.1.1.2100 - - name: Configure CMake - if: matrix.os != 'macos-latest' +# Copy-Item -Path "C:/Program Files/OpenSSL/lib/VC/x64/MD/*" -Destination "C:/Program Files/OpenSSL/lib/VC" -Recurse + + - name: Configure Windows CMake + if: matrix.os == 'windows-latest' run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON - name: Configure MacOS CMake if: matrix.os == 'macos-latest' - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl@1.1 - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} @@ -47,18 +52,30 @@ jobs: working-directory: ${{github.workspace}}/build run: ctest -C ${{env.BUILD_TYPE}} -VV - test-openssl3-0: - runs-on: macos-latest + test-openssl3: + strategy: + matrix: + os: [macos-latest, ubuntu-latest] + # Stops killing other jobs when one fails + fail-fast: false + + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 - name: Install OpenSSL on MacOS + if: matrix.os == 'macos-latest' run: brew install openssl@3 - name: Configure MacOS CMake + if: matrix.os == 'macos-latest' run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl + - name: Configure Ubuntu CMake + if: matrix.os == 'ubuntu-latest' + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_TESTS=ON + - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4176760..6a80915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project(authenticode_parser VERSION 1.0.0 LANGUAGES C) find_package(OpenSSL 1.1.1 REQUIRED) +message(STATUS "SSL library is ${OPENSSL_SSL_LIBRARY}") +message(STATUS "Crypto library is ${OPENSSL_SSL_LIBRARY}") +message(STATUS "All openssl libraries are ${OPENSSL_SSL_LIBRARY}") +message(STATUS "OpenSSL version is ${OPENSSL_SSL_LIBRARY}") + include(GNUInstallDirs) add_library(authenticode STATIC diff --git a/authenticode-config.cmake b/authenticode-config.cmake index da5957e..6b8ee3d 100644 --- a/authenticode-config.cmake +++ b/authenticode-config.cmake @@ -1,2 +1,2 @@ -find_package(OpenSSL 1.0.1 REQUIRED) +find_package(OpenSSL 1.1.1 REQUIRED) include(${CMAKE_CURRENT_LIST_DIR}/authenticode-targets.cmake) diff --git a/dev_scripts.py/dump_pe_signature.py b/dev_scripts.py/dump_pe_signature.py new file mode 100644 index 0000000..d6d12c9 --- /dev/null +++ b/dev_scripts.py/dump_pe_signature.py @@ -0,0 +1,23 @@ +import sys +import pefile + + +# Function to dump the signature from a PE file for tests +def dump_signature(path: str): + pe = pefile.PE(path) + security_directory = pe.OPTIONAL_HEADER.DATA_DIRECTORY[ + pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_SECURITY"] + ] + win_certificate = pe.__data__[ + security_directory.VirtualAddress + + 8 : security_directory.VirtualAddress + + security_directory.Size + ] # Extract WIN_CERTIFICATE + with open("dump.pkcs7.der", "wb") as fp: + fp.write(win_certificate) + + +# Use the function +file_path = sys.argv[1] +# To convert to ASCII PEM to use in tests, use +# openssl pkcs7 -inform der -in dump.pkcs7.der -out sig.pem diff --git a/dev_scripts.py/hex_to_c.py b/dev_scripts.py/hex_to_c.py new file mode 100644 index 0000000..8dc2ae6 --- /dev/null +++ b/dev_scripts.py/hex_to_c.py @@ -0,0 +1,18 @@ +"""Convert hex string like c7fef94e329bd9b66b281539265f989313356cbd9c345df9e670e9c4b6e0edce to C array init""" +import sys + + +def hex_to_c_array(hex_string: str) -> str: + # Split the hex string into bytes + bytes = [hex_string[i : i + 2] for i in range(0, len(hex_string), 2)] + + # Format the bytes as a C array + c_array = ", ".join("0x" + byte for byte in bytes) + c_array = "uint8_t array[] = {" + c_array + "};" + + return c_array + + +# Use the function +hex_string = sys.argv[1] +print(hex_to_c_array(hex_string)) diff --git a/examples/authenticode_dumper.c b/examples/authenticode_dumper.c index abf20b3..ab1a30f 100644 --- a/examples/authenticode_dumper.c +++ b/examples/authenticode_dumper.c @@ -69,7 +69,11 @@ void print_authenticode(Authenticode *auth) printf("%sDigest Algorithm : %s\n", indent, auth->digest_alg); printf("%sVerify flags : %d\n", indent, auth->verify_flags); printf("%sCertificate count : %ld\n", indent, auth->certs->count); - printf("%sCertificates: \n\n", indent); + printf("%sCertificates: \n", indent); + if (auth->signer->program_name) { + printf("%sProgram name : %s\n", indent, auth->signer->program_name); + } + printf("\n"); if (auth->certs) { for (size_t i = 0; i < auth->certs->count; ++i) { diff --git a/src/authenticode.c b/src/authenticode.c index 385ee9c..0b5f724 100644 --- a/src/authenticode.c +++ b/src/authenticode.c @@ -22,6 +22,7 @@ SOFTWARE. #include #include #include +#include #include #include #include @@ -274,7 +275,8 @@ static bool authenticode_verify(PKCS7* p7, PKCS7_SIGNER_INFO* si, X509* signCert } /* Creates all the Authenticode objects so we can parse them with OpenSSL, is not thread-safe, needs - * to be called once before any multi-threading environmentt - https://github.com/openssl/openssl/issues/13524 */ + * to be called once before any multi-threading environmentt - + * https://github.com/openssl/openssl/issues/13524 */ void initialize_authenticode_parser() { OBJ_create("1.3.6.1.4.1.311.2.1.12", "spcSpOpusInfo", "SPC_SP_OPUS_INFO_OBJID"); @@ -567,7 +569,8 @@ AuthenticodeArray* parse_authenticode(const uint8_t* pe_data, uint64_t pe_len) uint32_t dwLength = letoh32(*(uint32_t*)(pe_data + cert_addr)); if (pe_len < cert_addr + dwLength) return NULL; - /* dwLength = offsetof(WIN_CERTIFICATE, bCertificate) + (size of the variable-length binary array contained within bCertificate) */ + /* dwLength = offsetof(WIN_CERTIFICATE, bCertificate) + (size of the variable-length binary + * array contained within bCertificate) */ AuthenticodeArray* auth_array = authenticode_new(pe_data + cert_addr + 0x8, dwLength - 0x8); if (!auth_array) return NULL; diff --git a/src/certificate.c b/src/certificate.c index ce89a48..cf688e7 100644 --- a/src/certificate.c +++ b/src/certificate.c @@ -24,6 +24,7 @@ SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/countersignature.c b/src/countersignature.c index 9d806d5..88b7856 100644 --- a/src/countersignature.c +++ b/src/countersignature.c @@ -21,8 +21,11 @@ SOFTWARE. #include "countersignature.h" +#include +#include #include #include +#include #include #include #include @@ -36,6 +39,73 @@ SOFTWARE. #include "helper.h" #include "structs.h" +struct CountersignatureImplStruct; + +typedef TS_TST_INFO* get_ts_tst_info_func(struct CountersignatureImplStruct*); +typedef STACK_OF(X509) * get_signers_func(struct CountersignatureImplStruct*); +typedef STACK_OF(X509) * get_certs_func(struct CountersignatureImplStruct*); +typedef int +verify_digest_func(struct CountersignatureImplStruct*, uint8_t* digest, size_t digest_size); +typedef BIO* verify_signature_init_func(struct CountersignatureImplStruct*); +typedef int +verify_signature_finish_func(struct CountersignatureImplStruct*, BIO* bio, X509* signer); + +#define IMPL_FUNC_NAME(func, type) ms_countersig_impl_##func##_##type##_ + +#define DECLARE_FUNCS(type) \ + get_ts_tst_info_func IMPL_FUNC_NAME(get_ts_tst_info, type); \ + get_signers_func IMPL_FUNC_NAME(get_signers, type); \ + get_certs_func IMPL_FUNC_NAME(get_certs, type); \ + verify_digest_func IMPL_FUNC_NAME(verify_digest, type); \ + verify_signature_init_func IMPL_FUNC_NAME(verify_signature_init, type); \ + verify_signature_finish_func IMPL_FUNC_NAME(verify_signature_finish, type); + +DECLARE_FUNCS(pkcs7) +DECLARE_FUNCS(cms) + +typedef struct { + get_ts_tst_info_func* get_ts_tst_info; + get_signers_func* get_signers; + get_certs_func* get_certs; + verify_digest_func* verify_digest; + verify_signature_init_func* verify_signature_init; + verify_signature_finish_func* verify_signature_finish; +} CountersignatureImplFuncs; + +#define FUNC_ARRAY_NAME_FOR_IMPL(type) countersig_impl_funcs_##type##_ +#define FUNC_ARRAY_FOR_IMPL(type) \ + static const CountersignatureImplFuncs FUNC_ARRAY_NAME_FOR_IMPL(type) = { \ + &IMPL_FUNC_NAME(get_ts_tst_info, type), \ + &IMPL_FUNC_NAME(get_signers, type), \ + &IMPL_FUNC_NAME(get_certs, type), \ + &IMPL_FUNC_NAME(verify_digest, type), \ + &IMPL_FUNC_NAME(verify_signature_init, type), \ + &IMPL_FUNC_NAME(verify_signature_finish, type), \ + }; + +FUNC_ARRAY_FOR_IMPL(pkcs7) +FUNC_ARRAY_FOR_IMPL(cms) + +typedef enum { + CS_IMPL_PKCS7, + CS_IMPL_CMS, +} CountersignatureImplType; + +typedef struct CountersignatureImplStruct { + CountersignatureImplType type; + const CountersignatureImplFuncs* funcs; + union { + PKCS7* pkcs7; + CMS_ContentInfo* cms; + }; + // this is here to serve as a cache for CMS because the only way to obtain + // certs from CMS is to use CMS_get1_certs which leaves the deallocation + // to the caller but it just complicates things if you need to remember to + // deallocate also certs. This makes it easier if CountersignatureImpl itself + // is an owner of this thing. + STACK_OF(X509) * _certs; +} CountersignatureImpl; + Countersignature* pkcs9_countersig_new( const uint8_t* data, long size, STACK_OF(X509) * certs, ASN1_STRING* enc_digest) { @@ -133,7 +203,7 @@ Countersignature* pkcs9_countersig_new( /* compare the encrypted digest and calculated digest */ bool isValid = false; - + #if OPENSSL_VERSION_NUMBER >= 0x3000000fL size_t mdLen = EVP_MD_get_size(md); #else @@ -178,22 +248,264 @@ Countersignature* pkcs9_countersig_new( return result; } +TS_TST_INFO* IMPL_FUNC_NAME(get_ts_tst_info, pkcs7)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_PKCS7); + + return PKCS7_to_TS_TST_INFO(impl->pkcs7); +} + +TS_TST_INFO* IMPL_FUNC_NAME(get_ts_tst_info, cms)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_CMS); + + const ASN1_OBJECT* content_type = CMS_get0_eContentType(impl->cms); + if (OBJ_obj2nid(content_type) != NID_id_smime_ct_TSTInfo) { + return NULL; + } + + ASN1_OCTET_STRING** content = CMS_get0_content(impl->cms); + if (!content || !*content) { + return NULL; + } + + const uint8_t* data = (*content)->data; + TS_TST_INFO* ts_tst_info = d2i_TS_TST_INFO(NULL, &data, (*content)->length); + if (!ts_tst_info) { + return NULL; + } + + return ts_tst_info; +} + +STACK_OF(X509) * IMPL_FUNC_NAME(get_signers, pkcs7)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_PKCS7); + + return PKCS7_get0_signers(impl->pkcs7, impl->pkcs7->d.sign->cert, 0); +} + +STACK_OF(X509) * IMPL_FUNC_NAME(get_signers, cms)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_CMS); + + STACK_OF(CMS_SignerInfo)* signer_infos = CMS_get0_SignerInfos(impl->cms); + if (!signer_infos) { + return NULL; + } + + // Use our func points to cache the certs and don't create another copy + STACK_OF(X509)* certs = impl->funcs->get_certs(impl); + + int si_count = sk_CMS_SignerInfo_num(signer_infos); + int cert_count = certs ? sk_X509_num(certs) : 0; + STACK_OF(X509)* result = sk_X509_new_null(); + + // PKCS7_get0_signers() lets us specify the certificate array and looks up signer certificate + // there With CMS_ContentInfo, we don't have direct access to signer certificate, just all the + // certificates The only thing we can do is to go through all signer infos and find those which + // match some certificate in all certificates. It essentially simulates what + // PKCS7_get0_signers() does. + for (int i = 0; i < si_count; ++i) { + CMS_SignerInfo* si = sk_CMS_SignerInfo_value(signer_infos, i); + if (!si) { + continue; + } + + if (certs) { + for (int j = 0; j < cert_count; ++j) { + X509* cert = sk_X509_value(certs, j); + if (!cert) { + continue; + } + + if (CMS_SignerInfo_cert_cmp(si, cert) == 0) { + if (!sk_X509_push(result, cert)) { + return NULL; + } + } + } + } + } + + return result; +} + +STACK_OF(X509) * IMPL_FUNC_NAME(get_certs, pkcs7)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_PKCS7); + + return impl->pkcs7->d.sign->cert; +} + +STACK_OF(X509) * IMPL_FUNC_NAME(get_certs, cms)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_CMS); + + if (impl->_certs) { + return impl->_certs; + } + + impl->_certs = CMS_get1_certs(impl->cms); + return impl->_certs; +} + +int IMPL_FUNC_NAME(verify_digest, pkcs7)( + CountersignatureImpl* impl, uint8_t* digest, size_t digest_size) +{ + assert(impl->type == CS_IMPL_PKCS7); + + X509_STORE* store = X509_STORE_new(); + TS_VERIFY_CTX* ctx = TS_VERIFY_CTX_new(); + TS_VERIFY_CTX_init(ctx); + + TS_VERIFY_CTX_set_flags(ctx, TS_VFY_VERSION | TS_VFY_IMPRINT); + TS_VERIFY_CTX_set_store(ctx, store); +#if OPENSSL_VERSION_NUMBER >= 0x3000000fL + TS_VERIFY_CTX_set_certs(ctx, impl->funcs->get_certs(impl)); +#else + TS_VERIFY_CTS_set_certs(ctx, impl->funcs->get_certs(impl)); +#endif + TS_VERIFY_CTX_set_imprint(ctx, digest, digest_size); + + int result = TS_RESP_verify_token(ctx, impl->pkcs7); + + X509_STORE_free(store); + OPENSSL_free(ctx); + + return result; +} + +int IMPL_FUNC_NAME(verify_digest, cms)( + CountersignatureImpl* impl, uint8_t* digest, size_t digest_size) +{ + assert(impl->type == CS_IMPL_CMS); + + // This is essentially just reimplementation of TS_RESP_verify_token() from OpenSSL + TS_TST_INFO* ts_tst_info = impl->funcs->get_ts_tst_info(impl); + if (!ts_tst_info || TS_TST_INFO_get_version(ts_tst_info) != 1) { + if (ts_tst_info) + TS_TST_INFO_free(ts_tst_info); + return 0; + } + + TS_MSG_IMPRINT* ts_imprint = TS_TST_INFO_get_msg_imprint(ts_tst_info); + if (!ts_imprint) { + TS_TST_INFO_free(ts_tst_info); + return 0; + } + + ASN1_OCTET_STRING* ts_imprint_digest = TS_MSG_IMPRINT_get_msg(ts_imprint); + if (!ts_imprint_digest) { + TS_TST_INFO_free(ts_tst_info); + return 0; + } + + if (ts_imprint_digest->length != (int)digest_size || + memcmp(ts_imprint_digest->data, digest, digest_size) != 0) { + TS_TST_INFO_free(ts_tst_info); + return 0; + } + + TS_TST_INFO_free(ts_tst_info); + return 1; +} + +BIO* IMPL_FUNC_NAME(verify_signature_init, pkcs7)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_PKCS7); + + return PKCS7_dataInit(impl->pkcs7, NULL); +} + +BIO* IMPL_FUNC_NAME(verify_signature_init, cms)(CountersignatureImpl* impl) +{ + assert(impl->type == CS_IMPL_CMS); + + return CMS_dataInit(impl->cms, NULL); +} + +int IMPL_FUNC_NAME(verify_signature_finish, pkcs7)( + CountersignatureImpl* impl, BIO* bio, X509* signer) +{ + assert(impl->type == CS_IMPL_PKCS7); + + /* Verify signature with PKCS7_signatureVerify + because TS_RESP_verify_token would try to verify + chain and without trust anchors it always fails */ + PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(impl->pkcs7), 0); + return PKCS7_signatureVerify(bio, impl->pkcs7, si, signer); +} + +int IMPL_FUNC_NAME(verify_signature_finish, cms)(CountersignatureImpl* impl, BIO* bio, X509* signer) +{ + assert(impl->type == CS_IMPL_CMS); + + (void)signer; + CMS_SignerInfo* si = sk_CMS_SignerInfo_value(CMS_get0_SignerInfos(impl->cms), 0); + return CMS_SignerInfo_verify_content(si, bio); +} + +CountersignatureImpl* ms_countersig_impl_new(const uint8_t* data, long size) +{ + const uint8_t* d = data; + PKCS7* p7 = d2i_PKCS7(NULL, &d, size); + if (p7) { + CountersignatureImpl* result = + (CountersignatureImpl*)calloc(1, sizeof(CountersignatureImpl)); + result->type = CS_IMPL_PKCS7; + result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(pkcs7); + result->pkcs7 = p7; + return result; + } + + d = data; + CMS_ContentInfo* cms = d2i_CMS_ContentInfo(NULL, &d, size); + if (cms) { + CountersignatureImpl* result = + (CountersignatureImpl*)calloc(1, sizeof(CountersignatureImpl)); + result->type = CS_IMPL_CMS; + result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(cms); + result->cms = cms; + return result; + } + + return NULL; +} + +void ms_countersig_impl_free(CountersignatureImpl* impl) +{ + switch (impl->type) { + case CS_IMPL_PKCS7: + PKCS7_free(impl->pkcs7); + break; + case CS_IMPL_CMS: + if (impl->_certs) { + sk_X509_pop_free(impl->_certs, X509_free); + } + CMS_ContentInfo_free(impl->cms); + break; + } + + free(impl); +} + Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING* enc_digest) { Countersignature* result = (Countersignature*)calloc(1, sizeof(*result)); if (!result) return NULL; - PKCS7* p7 = d2i_PKCS7(NULL, &data, size); - if (!p7) { + CountersignatureImpl* impl = ms_countersig_impl_new(data, size); + if (!impl) { result->verify_flags = COUNTERSIGNATURE_VFY_CANT_PARSE; return result; } - TS_TST_INFO* ts = PKCS7_to_TS_TST_INFO(p7); + TS_TST_INFO* ts = impl->funcs->get_ts_tst_info(impl); if (!ts) { result->verify_flags = COUNTERSIGNATURE_VFY_CANT_PARSE; - PKCS7_free(p7); + ms_countersig_impl_free(impl); return result; } @@ -201,20 +513,21 @@ Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING* if (!rawTime) { result->verify_flags = COUNTERSIGNATURE_VFY_TIME_MISSING; TS_TST_INFO_free(ts); - PKCS7_free(p7); + ms_countersig_impl_free(impl); return result; } result->sign_time = ASN1_TIME_to_int64_t(rawTime); - STACK_OF(X509)* sigs = PKCS7_get0_signers(p7, p7->d.sign->cert, 0); + STACK_OF(X509)* sigs = impl->funcs->get_signers(impl); X509* signCert = sk_X509_value(sigs, 0); if (!signCert) { result->verify_flags = COUNTERSIGNATURE_VFY_NO_SIGNER_CERT; goto end; } - result->chain = parse_signer_chain(signCert, p7->d.sign->cert); + STACK_OF(X509)* certs = impl->funcs->get_certs(impl); + result->chain = parse_signer_chain(signCert, certs); /* Imprint == digest */ TS_MSG_IMPRINT* imprint = TS_TST_INFO_get_msg_imprint(ts); @@ -259,52 +572,30 @@ Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING* goto end; } - TS_VERIFY_CTX* ctx = TS_VERIFY_CTX_new(); - X509_STORE* store = X509_STORE_new(); - TS_VERIFY_CTX_init(ctx); - - TS_VERIFY_CTX_set_flags(ctx, TS_VFY_VERSION | TS_VFY_IMPRINT); - TS_VERIFY_CTX_set_store(ctx, store); -#if OPENSSL_VERSION_NUMBER >= 0x3000000fL - TS_VERIFY_CTX_set_certs(ctx, p7->d.sign->cert); -#else - TS_VERIFY_CTS_set_certs(ctx, p7->d.sign->cert); -#endif - TS_VERIFY_CTX_set_imprint(ctx, calc_digest, mdLen); - - bool isValid = TS_RESP_verify_token(ctx, p7) == 1; - - X509_STORE_free(store); - OPENSSL_free(ctx); - + bool isValid = impl->funcs->verify_digest(impl, calc_digest, mdLen) == 1; if (!isValid) { result->verify_flags = COUNTERSIGNATURE_VFY_INVALID; goto end; } - /* Verify signature with PKCS7_signatureVerify - because TS_RESP_verify_token would try to verify - chain and without trust anchors it always fails */ - BIO* p7bio = PKCS7_dataInit(p7, NULL); + BIO* bio = impl->funcs->verify_signature_init(impl); char buf[4096]; - /* We now have to 'read' from p7bio to calculate digests etc. */ - while (BIO_read(p7bio, buf, sizeof(buf)) > 0) + /* We now have to 'read' from bio to calculate digests etc. */ + while (BIO_read(bio, buf, sizeof(buf)) > 0) continue; - PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0); - - isValid = PKCS7_signatureVerify(p7bio, p7, si, signCert) == 1; + isValid = impl->funcs->verify_signature_finish(impl, bio, signCert) == 1; - BIO_free_all(p7bio); + BIO_free_all(bio); if (!isValid) result->verify_flags = COUNTERSIGNATURE_VFY_INVALID; end: sk_X509_free(sigs); - PKCS7_free(p7); TS_TST_INFO_free(ts); + ms_countersig_impl_free(impl); return result; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 30d85d9..45a157b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,7 +16,8 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) add_executable(tests - integration/test.cpp + integration/test_microsoft.cpp + integration/test_non_microsoft.cpp unit/countersignature.cpp unit/certificate.cpp unit/helper.cpp) diff --git a/tests/data.h b/tests/data.h index 4bf0c5a..70e8404 100644 --- a/tests/data.h +++ b/tests/data.h @@ -405,6 +405,189 @@ "76k3su0TSVhNZbXFb80ASw==\n" \ "-----END PKCS7-----\n" +#define VALID_SIGNATURE_PEM_MICROSOFT_COUNTER \ + "-----BEGIN PKCS7-----\n" \ + "MIIhXQYJKoZIhvcNAQcCoIIhTjCCIUoCAQExDzANBglghkgBZQMEAgEFADBcBgor\n" \ + "BgEEAYI3AgEEoE4wTDAXBgorBgEEAYI3AgEPMAkDAQCgBKICgAAwMTANBglghkgB\n" \ + "ZQMEAgEFAAQgx/75TjKb2bZrKBU5Jl+YkxM1bL2cNF355nDpxLbg7c6gggtYMIIF\n" \ + "bzCCBFegAwIBAgITMwAAALIPmthnlPMi9gAAAAAAsjANBgkqhkiG9w0BAQsFADCB\n" \ + "jjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl\n" \ + "ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE4MDYGA1UEAxMv\n" \ + "TWljcm9zb2Z0IFdpbmRvd3MgVGhpcmQgUGFydHkgQ29tcG9uZW50IENBIDIwMTIw\n" \ + "HhcNMjAxMjE1MjIxNTMwWhcNMjExMjAyMjIxNTMwWjCBkTELMAkGA1UEBhMCVVMx\n" \ + "EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT\n" \ + "FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE7MDkGA1UEAxMyTWljcm9zb2Z0IFdpbmRv\n" \ + "d3MgSGFyZHdhcmUgQ29tcGF0aWJpbGl0eSBQdWJsaXNoZXIwggEiMA0GCSqGSIb3\n" \ + "DQEBAQUAA4IBDwAwggEKAoIBAQCZ8Mvh97s1+NdSDuMQQmFP8WJfahRttWXzOsi1\n" \ + "91Lm8LgV4Hc1Dlp2xcP5VVHFo/t9VJn1GDzJca4vskbeCAUSjx+3LVhZMnkM3YB2\n" \ + "dy0WryH1libJD5USJNVnpqaJBx4laPD+BvZDcGO+MSlL4ADlje2q1YCov9m6Ob3t\n" \ + "fCVDkOSCrN1Rm5gWTdmGQZVl/zKIq/MO133qd4EPLfFWweOeNDknKw2PG1WfgyP1\n" \ + "rxLuPMPzTF3ItPv3M3B28JGQSxYKLVP60BqVTSaLByfkQRQw33Unj3nMrIEFW0ba\n" \ + "/96m6prXTr82/S3+XwW1PDnC0GKylnxRxmeObM0IMgMoRy2HAgMBAAGjggG/MIIB\n" \ + "uzAfBgNVHSUEGDAWBgorBgEEAYI3CgMFBggrBgEFBQcDAzAdBgNVHQ4EFgQUAacC\n" \ + "woi4cJdR/kAf/aPCsLeFqIgwUAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jv\n" \ + "c29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAxNTMrNDYz\n" \ + "MDM2MB8GA1UdIwQYMBaAFGFxp4ev/2nVIXZPUpMoAL55EquEMHQGA1UdHwRtMGsw\n" \ + "aaBnoGWGY2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jv\n" \ + "c29mdCUyMFdpbmRvd3MlMjBUaGlyZCUyMFBhcnR5JTIwQ29tcG9uZW50JTIwQ0El\n" \ + "MjAyMDEyLmNybDCBgQYIKwYBBQUHAQEEdTBzMHEGCCsGAQUFBzAChmVodHRwOi8v\n" \ + "d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFdpbmRv\n" \ + "d3MlMjBUaGlyZCUyMFBhcnR5JTIwQ29tcG9uZW50JTIwQ0ElMjAyMDEyLmNydDAM\n" \ + "BgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQAZmsxqhxfA21tLIxLczYux\n" \ + "4z70knMfuOHWC9b2kN4HS22SKTyCYAEtysxmimjxDnJqN9L/fuZrHupCT1bxBCSb\n" \ + "1tfn66jBdF9PEUO6x+ZI5IwbKhrfaVS13hZp3xnEvlYzt5G3o8uiNkEAb9WKwtSU\n" \ + "odANrbw7P+UKetAWPLOGaTgkEGtd2fm4pXnkX1xfiASDK4p3NwHgyjHe6aAS/OWR\n" \ + "FJLek77qRKOCL3qDxEikhO65N6T6f0Bnh5uRDlNMlm0mUL1ck/BmZWqg9MfDGBYd\n" \ + "Sos2cFbfQq9goKrQ6y3ju0e5a5SPLISfMwz+9Znxd1u21BzxUN7LQKg9WAByfZd+\n" \ + "MIIF4TCCA8mgAwIBAgIKYQuqwQAAAAAACTANBgkqhkiG9w0BAQsFADCBiDELMAkG\n" \ + "A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx\n" \ + "HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z\n" \ + "b2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTIwNDE4MjM0\n" \ + "ODM4WhcNMjcwNDE4MjM1ODM4WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh\n" \ + "c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD\n" \ + "b3Jwb3JhdGlvbjE4MDYGA1UEAxMvTWljcm9zb2Z0IFdpbmRvd3MgVGhpcmQgUGFy\n" \ + "dHkgQ29tcG9uZW50IENBIDIwMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" \ + "AoIBAQCjnDCECadjLs8KR/DqJPmjMCAPXlcxJoGaMQeyUNTOZwkIZQpapUuu1e0Q\n" \ + "LuelmbWfaC+Yi1gCrCC0KcRxvSgcpf08m2TkxevfYSW88O5ov9Gny34qAoFOZFwM\n" \ + "U4Z5Vxk3YbeY+QygTiJZm/kbLWc8JzxWkGbj/X9lfQ+GvTVH6IrM9NqO6WpOq6dV\n" \ + "7KKJHtUzRVPL+Z53vc0s+QW4f3QBHej7GOFD0Q3pqtw3b73+uA/tHU0BRk4KrPyC\n" \ + "6OxWgxOOOgHtFGR06mSyZhC2aG3IcAB9UEguPUPu4CSVxs2Ox/245JXP3X77lV6h\n" \ + "Ac1DsQfXpDDum4YaKm7BC1midG+LAgMBAAGjggFDMIIBPzAQBgkrBgEEAYI3FQEE\n" \ + "AwIBADAdBgNVHQ4EFgQUYXGnh6//adUhdk9SkygAvnkSq4QwGQYJKwYBBAGCNxQC\n" \ + "BAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYD\n" \ + "VR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZF\n" \ + "aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9v\n" \ + "Q2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcw\n" \ + "AoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJB\n" \ + "dXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAFqKZ9rM1f0NJkF3\n" \ + "vwpGeLSz3hJpK3cjwmUvAV/SA/RhulCdLow5cvNsPmqxHnZt7LfzgtzMu8VpcChz\n" \ + "Zhc/VOvuARZIxEbZG4CugTqND3ltaLCe6i0/OdPKOH69XnwIbhncxsL0ODNoYeJS\n" \ + "R4PhAAFW0rrLh4IFMQpBi07nf19f7V/TOS1F66ITv/0ewphBcWEWX8gKcCV8WWkx\n" \ + "JORx5wq7BBf3n3IeydK7Gr49Av4JDLJDtFkamVOTliFf4Na3JgFClTasJ/2+9IV3\n" \ + "aD0YvfS+mIgiEYZSFvNF7AOXEHCHo3BDcTzbyYYDFwz1c1vGfeFcZO3XxUjX7TLi\n" \ + "0arTz6f2V05h+XfrZ/KIs94A2gOP0Io0Nz4d2GK40rHz4S+LcjuBlnxv/OxmdnJg\n" \ + "GyTyoIltW20ALu8o3YaHBcK0ueW+ZMIq8koVXJjixCeF/1LjYn4PsgIL12bHCrLT\n" \ + "PSAEFFAyWYMKfZvtWjgSAVK6L14gco5K8f3ncQKMO+EHvslz9N1H2LTvtKSzMLmJ\n" \ + "PnbKuQCYVn6r6oq4pdA4q2l3EwsUL+mqQR/3ur06KzSK7gqrY+Zj94gkjiANKzud\n" \ + "48JJUqyfHw45O13UblBq5n1SOqp8MxUpDSZeAVinTqk9eoRvdD9gn+QyTzYAr21x\n" \ + "0z6mRmVfgXTx/sFx2kygQVqC3fEfMYIVeDCCFXQCAQEwgaYwgY4xCzAJBgNVBAYT\n" \ + "AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD\n" \ + "VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xODA2BgNVBAMTL01pY3Jvc29mdCBX\n" \ + "aW5kb3dzIFRoaXJkIFBhcnR5IENvbXBvbmVudCBDQSAyMDEyAhMzAAAAsg+a2GeU\n" \ + "8yL2AAAAAACyMA0GCWCGSAFlAwQCAQUAoIGuMBkGCSqGSIb3DQEJAzEMBgorBgEE\n" \ + "AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJ\n" \ + "BDEiBCAW78UlDE1KmaAO0q2aDj2PvCHaW+law1rTOz2cPzcZoTBCBgorBgEEAYI3\n" \ + "AgEMMTQwMqAQgA4AUAByAG8AYwBlAHgAcKEegBxodHRwczovL3d3dy5zeXNpbnRl\n" \ + "cm5hbHMuY29tMA0GCSqGSIb3DQEBAQUABIIBADFezXsgSTCtb/LuWnk3z2zPMi20\n" \ + "W3F/JeY8sjPVTwmoEHYhglcCh0a75ilUymow6ut8xCILl+7Evlm2e6U4A5goHn2y\n" \ + "X/06UUI5l0jXFjSXby6tyoD2xZZHhXN+o5gT5Ke92ryvXkKzYsOc37cO3Q5/7Jxr\n" \ + "5lqWqCGXJ3pOqBI4KDCA7mgyZtzSk6POoXHEbb+PBKvBB0Fj0HGF/j/q+8m2jpV3\n" \ + "iDEII1StD5C9BjlHdZeRiCKnAvvWjomSnGFg/VXJ6rzqahqij3JTcmBaYnrcJXub\n" \ + "5kY7OYXP4CDO+rrY14LY4VHEdHNOm3i2Ihae5wqIRjKyBdvg6iUz7D7H9bOhghLx\n" \ + "MIIS7QYKKwYBBAGCNwMDATGCEt0wghLZBgkqhkiG9w0BBwKgghLKMIISxgIBAzEP\n" \ + "MA0GCWCGSAFlAwQCAQUAMIIBVQYLKoZIhvcNAQkQAQSgggFEBIIBQDCCATwCAQEG\n" \ + "CisGAQQBhFkKAwEwMTANBglghkgBZQMEAgEFAAQg7d+KRTQOFrNVao5Ss/zS5zxc\n" \ + "R9NqpnFP/u8sGWA3Z28CBmD69yXH+BgTMjAyMTA4MTcwMjAxMzMuMDYzWjAEgAIB\n" \ + "9KCB1KSB0TCBzjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO\n" \ + "BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEp\n" \ + "MCcGA1UECxMgTWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNV\n" \ + "BAsTHVRoYWxlcyBUU1MgRVNOOjMyQkQtRTNENS0zQjFEMSUwIwYDVQQDExxNaWNy\n" \ + "b3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIORDCCBPUwggPdoAMCAQICEzMAAAFi\n" \ + "0P4C8wHlzUkAAAAAAWIwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzAR\n" \ + "BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p\n" \ + "Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh\n" \ + "bXAgUENBIDIwMTAwHhcNMjEwMTE0MTkwMjIyWhcNMjIwNDExMTkwMjIyWjCBzjEL\n" \ + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v\n" \ + "bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMgTWlj\n" \ + "cm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxlcyBU\n" \ + "U1MgRVNOOjMyQkQtRTNENS0zQjFEMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1T\n" \ + "dGFtcCBTZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA74ah\n" \ + "1Pa5wvcyvYNCy/YQs1tK8rIGlh1Qq1QFaJmYVXLXykb+m5yCStzmL227wJjsalZX\n" \ + "8JA2YcbaZV5Icwm9vAJz8AC/sk/dsUK3pmDvkhtVI04YDV6otuZCILpQB9Ipcs3d\n" \ + "0e1Dl2KKFvdibOk0/0rRxU9l+/Yxeb5lVTRERLxzI+Rd6Xv5QQYT6Sp2IE0N1vzI\n" \ + "Fd3yyO773T5XifNgL5lZbtIUnYUVmUBKlVoemO/54aiFeVBpIG+YzhDTF7cuHNAz\n" \ + "xWIbP1wt4VIqAV9JjuqLMvvBSD56pi8NTKM9fxrERAeaTS2HbfBYfmnRZ27Czjeo\n" \ + "0ijQ5DSZGi0ErvWfKQIDAQABo4IBGzCCARcwHQYDVR0OBBYEFMvEShFgSkO3Onzg\n" \ + "HlaVk3aQ/iprMB8GA1UdIwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1Ud\n" \ + "HwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3By\n" \ + "b2R1Y3RzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQRO\n" \ + "MEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2Vy\n" \ + "dHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYD\n" \ + "VR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAC1BrcOhdhtb9xcA\n" \ + "JtxVIUZ7iALwZewXFIdPcmDAVT810k5xuRwVNW9Onq+WZO8ebqwiOSdEEHReLU0F\n" \ + "Oo/DbS7q79PsKdz/PSBPqZ/1ysjRVH0L5HUK2N7NgpkR1lnt+41BaOzJ+00OFDL5\n" \ + "GqeqvK3RWh7MtqWF6KKcfNkP/hjiFlg9/S7xNK/Vl8q10HB5YbdBTQun8j1Jsih6\n" \ + "YMb3tFQsxw++ra5+FSnc4yJhAYvVaqTKRKepEmwzYhwDiXh2ag80/p0uDkOvs1Wh\n" \ + "gogwidpBVmNLAMxmFavK9+LNfRKvPIuCQw+EsxWR8vFBBJDfs14WTsXVF94CQ1YC\n" \ + "HqYI5EEwggZxMIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGI\n" \ + "MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk\n" \ + "bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylN\n" \ + "aWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3\n" \ + "MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI\n" \ + "EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv\n" \ + "ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD\n" \ + "QSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog\n" \ + "7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqV\n" \ + "Hc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRg\n" \ + "MlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcS\n" \ + "chohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrK\n" \ + "sajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1e\n" \ + "FpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYE\n" \ + "FNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBB\n" \ + "MAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP\n" \ + "6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWlj\n" \ + "cm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2\n" \ + "LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cu\n" \ + "bWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMu\n" \ + "Y3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcC\n" \ + "ARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0\n" \ + "Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBf\n" \ + "AFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3i\n" \ + "xuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5\n" \ + "vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/G\n" \ + "f/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9Z\n" \ + "Kby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZ\n" \ + "SnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCb\n" \ + "IjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D\n" \ + "8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHL\n" \ + "pwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp\n" \ + "9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8b\n" \ + "xyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8N\n" \ + "oFA12u8JJxzVs341Hgi62jbb01+P3nSISRKhggLSMIICOwIBATCB/KGB1KSB0TCB\n" \ + "zjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl\n" \ + "ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEpMCcGA1UECxMg\n" \ + "TWljcm9zb2Z0IE9wZXJhdGlvbnMgUHVlcnRvIFJpY28xJjAkBgNVBAsTHVRoYWxl\n" \ + "cyBUU1MgRVNOOjMyQkQtRTNENS0zQjFEMSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt\n" \ + "ZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCas/oKGtvPRrHuznufk+in\n" \ + "dULyDKCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u\n" \ + "MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp\n" \ + "b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqG\n" \ + "SIb3DQEBBQUAAgUA5MUY7TAiGA8yMDIxMDgxNjIxMDM0MVoYDzIwMjEwODE3MjEw\n" \ + "MzQxWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDkxRjtAgEAMAoCAQACAg4WAgH/\n" \ + "MAcCAQACAhEqMAoCBQDkxmptAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQB\n" \ + "hFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEA\n" \ + "KNml34ZXWEvO8kgJa9uw7u+F2acSHsoxOHOZ/so7COqb+iwKmVx74jfqyqorssnn\n" \ + "Vmm8+hRy4zFbEo5lACNtYIlCMB6uIgcfJlHvHAf18unlj3U7H4+BisX27wXJDshB\n" \ + "lyX3cr7ib4AVQhXjGPEUqj2MBZS/bVda3ZhDwLKqGFkxggMNMIIDCQIBATCBkzB8\n" \ + "MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk\n" \ + "bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N\n" \ + "aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAWLQ/gLzAeXNSQAAAAAB\n" \ + "YjANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE\n" \ + "MC8GCSqGSIb3DQEJBDEiBCBPYkNXIBZ7/hs5bcFJ60pVHV91A+hbat8GKp+oVfgL\n" \ + "sTCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIIqqGJX7PA0OulTsNEHsyLnv\n" \ + "GLoYE1iwaOBmqrapUwoyMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" \ + "Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m\n" \ + "dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB\n" \ + "IDIwMTACEzMAAAFi0P4C8wHlzUkAAAAAAWIwIgQggc576of3UYTIpBYSSlOC3fTU\n" \ + "CdPUhARDA3k0nsKK9iUwDQYJKoZIhvcNAQELBQAEggEATYtDaVhvhu0N8/NxvA4r\n" \ + "7MuRznFgDqSp3kMNY9vl0mRZZodTTzmbJvy35qAB36qm5FvEtLASS8oCJnhokn/3\n" \ + "qIMEJpwyvd3r/oWRElnF0sWrhDW3m1zJ5aILJVwEK+h1tXSTNVxzyM2m7SmlEb35\n" \ + "Wr5URlinyoOJ74AL2CTCLuq47sx68ZdaPCHXXDn94Ofayk+kPMWh9SswJ2yvhjZf\n" \ + "HSGSLyJ3X14M4dSxJPazz8b5887FOyvmK5Vitci5/Gcou2ydyESC4DGozGMTMW07\n" \ + "ii94+89h6CigWDLhgq3p8YUuO45tzZbN7YrPnS3KHl6DmfxcCbQtfCo40WWOm8vs\n" \ + "kA==\n" \ + "-----END PKCS7-----" + #define CERTIFICATE_PEM \ "-----BEGIN CERTIFICATE-----\n" \ "MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\n" \ diff --git a/tests/integration/test_microsoft.cpp b/tests/integration/test_microsoft.cpp new file mode 100644 index 0000000..8cc58ba --- /dev/null +++ b/tests/integration/test_microsoft.cpp @@ -0,0 +1,243 @@ +/* Copyright (c) 2021 Avast Software + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "../data.h" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +class MicrosoftSignatureTest : public testing::Test +{ + protected: + unsigned char *data = nullptr; + long data_len = 0; + + void SetUp() override + { + BIO *bio = BIO_new(BIO_s_mem()); + BIO_write( + bio, + VALID_SIGNATURE_PEM_MICROSOFT_COUNTER, + std::strlen(VALID_SIGNATURE_PEM_MICROSOFT_COUNTER)); + char *name = nullptr; + char *header = nullptr; + PEM_read_bio(bio, &name, &header, &data, &data_len); + BIO_free_all(bio); + OPENSSL_free(name); + OPENSSL_free(header); + + initialize_authenticode_parser(); + } + + void TearDown() override { OPENSSL_free(data); } +}; + +TEST_F(MicrosoftSignatureTest, ResultOverview) +{ + AuthenticodeArray *auth = authenticode_new(data, data_len); + ASSERT_NE(auth, nullptr); + + ASSERT_EQ(auth->count, 1); + ASSERT_NE(auth->signatures, nullptr); + + for (size_t i = 0; i < auth->count; ++i) { + ASSERT_TRUE(auth->signatures[i]); + } + + authenticode_array_free(auth); +} + +TEST_F(MicrosoftSignatureTest, SignatureContent) +{ + AuthenticodeArray *auth = authenticode_new(data, data_len); + ASSERT_NE(auth, nullptr); + + ASSERT_EQ(auth->count, 1); + ASSERT_NE(auth->signatures, nullptr); + + const Authenticode *first_sig = auth->signatures[0]; + ASSERT_TRUE(first_sig); + + //***********************************// + // Check the first signature content // + EXPECT_EQ(first_sig->version, 1); + + EXPECT_TRUE(first_sig->digest.data); + uint8_t file_digest[32] = {0xc7, 0xfe, 0xf9, 0x4e, 0x32, 0x9b, 0xd9, 0xb6, 0x6b, 0x28, 0x15, + 0x39, 0x26, 0x5f, 0x98, 0x93, 0x13, 0x35, 0x6c, 0xbd, 0x9c, 0x34, + 0x5d, 0xf9, 0xe6, 0x70, 0xe9, 0xc4, 0xb6, 0xe0, 0xed, 0xce}; + EXPECT_EQ(first_sig->digest.len, 32); + EXPECT_TRUE(std::memcmp(file_digest, first_sig->digest.data, 32) == 0); + EXPECT_STREQ(first_sig->digest_alg, "sha256"); + + EXPECT_EQ(first_sig->verify_flags, AUTHENTICODE_VFY_VALID); + + //****************************// + // Check SignerInfo structure // + ASSERT_TRUE(first_sig->signer); + EXPECT_STREQ(first_sig->signer->digest_alg, "sha256"); + + ASSERT_TRUE(first_sig->signer->digest.data); + ASSERT_EQ(first_sig->signer->digest.len, 32); + uint8_t message_digest[32] = {0x16, 0xef, 0xc5, 0x25, 0x0c, 0x4d, 0x4a, 0x99, 0xa0, 0x0e, 0xd2, + 0xad, 0x9a, 0x0e, 0x3d, 0x8f, 0xbc, 0x21, 0xda, 0x5b, 0xe9, 0x5a, + 0xc3, 0x5a, 0xd3, 0x3b, 0x3d, 0x9c, 0x3f, 0x37, 0x19, 0xa1}; + EXPECT_TRUE(std::memcmp(message_digest, first_sig->signer->digest.data, 32) == 0); + ASSERT_TRUE(first_sig->signer->program_name); + ASSERT_STREQ(first_sig->signer->program_name, "Procexp"); + + //******************************************// + // Test all certificates of first signature // + ASSERT_TRUE(first_sig->certs); + ASSERT_TRUE(first_sig->certs->certs); + ASSERT_EQ(first_sig->certs->count, 2); + + //**************************// + // Check the 1. certificate // + const Certificate *cert = first_sig->certs->certs[0]; + ASSERT_TRUE(cert->sha1.data); + ASSERT_EQ(cert->sha1.len, 20); + unsigned char first_cert_sha1[20] = {0x92, 0xd7, 0x19, 0x2a, 0x7c, 0x31, 0x80, + 0x91, 0x2f, 0xf8, 0x41, 0x4f, 0x79, 0x09, + 0x73, 0xa0, 0x5c, 0x28, 0xf8, 0xb0}; + EXPECT_TRUE(std::memcmp(first_cert_sha1, cert->sha1.data, 20) == 0); + EXPECT_EQ(cert->version, 2); + EXPECT_STREQ( + cert->subject, + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Hardware " + "Compatibility Publisher"); + EXPECT_STREQ( + cert->issuer, + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Windows Third Party " + "Component CA 2012"); + + //**************************// + // Check the 2. certificate // + cert = first_sig->certs->certs[1]; + ASSERT_TRUE(cert->sha1.data); + ASSERT_EQ(cert->sha1.len, 20); + unsigned char second_cert_sha1[20] = {0x77, 0xa1, 0x0e, 0xbf, 0x07, 0x54, 0x27, + 0x25, 0x21, 0x8c, 0xd8, 0x3a, 0x01, 0xb5, + 0x21, 0xc5, 0x7b, 0xc6, 0x7f, 0x73}; + EXPECT_TRUE(std::memcmp(second_cert_sha1, cert->sha1.data, 20) == 0); + + //**************************// + // Check the Counter signature // + const Countersignature *countersig = first_sig->countersigs->counters[0]; + + EXPECT_EQ(countersig->verify_flags, COUNTERSIGNATURE_VFY_VALID); + EXPECT_STREQ(countersig->digest_alg, "sha256"); + EXPECT_EQ(countersig->sign_time, 1629165693); + unsigned char first_countersig_digest[32] = {0xed, 0xdf, 0x8a, 0x45, 0x34, 0x0e, 0x16, 0xb3, + 0x55, 0x6a, 0x8e, 0x52, 0xb3, 0xfc, 0xd2, 0xe7, + 0x3c, 0x5c, 0x47, 0xd3, 0x6a, 0xa6, 0x71, 0x4f, + 0xfe, 0xef, 0x2c, 0x19, 0x60, 0x37, 0x67, 0x6f}; + ASSERT_TRUE(countersig->digest.data); + ASSERT_EQ(countersig->digest.len, 32); + EXPECT_TRUE(std::memcmp(first_countersig_digest, countersig->digest.data, 32) == 0); + + ASSERT_TRUE(countersig->chain); + EXPECT_EQ(countersig->chain->count, 2); + + //**************************// + // Check the 1. certificate // + cert = countersig->chain->certs[0]; + ASSERT_TRUE(cert->sha1.data); + ASSERT_EQ(cert->sha1.len, 20); + unsigned char first_countercert_sha1[20] = {0x9a, 0xb3, 0xfa, 0x0a, 0x1a, 0xdb, 0xcf, + 0x46, 0xb1, 0xee, 0xce, 0x7b, 0x9f, 0x93, + 0xe8, 0xa7, 0x75, 0x42, 0xf2, 0x0c}; + EXPECT_TRUE(std::memcmp(first_countercert_sha1, cert->sha1.data, 20) == 0); + ASSERT_EQ(cert->sha256.len, 32); + unsigned char first_countercert_sha256[32] = {0x8a, 0xaa, 0x18, 0x95, 0xfb, 0x3c, 0x0d, 0x0e, + 0xba, 0x54, 0xec, 0x34, 0x41, 0xec, 0xc8, 0xb9, + 0xef, 0x18, 0xba, 0x18, 0x13, 0x58, 0xb0, 0x68, + 0xe0, 0x66, 0xaa, 0xb6, 0xa9, 0x53, 0x0a, 0x32}; + EXPECT_TRUE(std::memcmp(first_countercert_sha256, cert->sha256.data, 32) == 0); + + EXPECT_EQ(cert->version, 2); + EXPECT_STREQ( + cert->subject, + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Microsoft Operations Puerto " + "Rico/OU=Thales TSS ESN:32BD-E3D5-3B1D/CN=Microsoft Time-Stamp Service"); + EXPECT_STREQ( + cert->issuer, + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Time-Stamp PCA 2010"); + EXPECT_EQ(cert->not_after, 1649703742); + EXPECT_EQ(cert->not_before, 1610650942); + EXPECT_STREQ( + cert->key, + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA74ah1Pa5wvcyvYNCy/" + "YQs1tK8rIGlh1Qq1QFaJmYVXLXykb+m5yCStzmL227wJjsalZX8JA2YcbaZV5Icwm9vAJz8AC/sk/" + "dsUK3pmDvkhtVI04YDV6otuZCILpQB9Ipcs3d0e1Dl2KKFvdibOk0/0rRxU9l+/" + "Yxeb5lVTRERLxzI+Rd6Xv5QQYT6Sp2IE0N1vzIFd3yyO773T5XifNgL5lZbtIUnYUVmUBKlVoemO/" + "54aiFeVBpIG+" + "YzhDTF7cuHNAzxWIbP1wt4VIqAV9JjuqLMvvBSD56pi8NTKM9fxrERAeaTS2HbfBYfmnRZ27Czjeo0ijQ5DSZGi0Er" + "vWfKQIDAQAB"); + EXPECT_STREQ(cert->serial, "33:00:00:01:62:d0:fe:02:f3:01:e5:cd:49:00:00:00:00:01:62"); + EXPECT_STREQ(cert->sig_alg, "sha256WithRSAEncryption"); + EXPECT_STREQ(cert->key_alg, "rsaEncryption"); + + //**************************// + // Check the 2. certificate // + cert = countersig->chain->certs[1]; + ASSERT_TRUE(cert->sha1.data); + ASSERT_EQ(cert->sha1.len, 20); + unsigned char second_countercert_sha1[20] = {0x2a, 0xa7, 0x52, 0xfe, 0x64, 0xc4, 0x9a, + 0xbe, 0x82, 0x91, 0x3c, 0x46, 0x35, 0x29, + 0xcf, 0x10, 0xff, 0x2f, 0x04, 0xee}; + EXPECT_TRUE(std::memcmp(second_countercert_sha1, cert->sha1.data, 20) == 0); + + ASSERT_TRUE(cert->sha256.data); + ASSERT_EQ(cert->sha256.len, 32); + unsigned char second_countercert_sha256[32] = {0x86, 0xec, 0x11, 0x8d, 0x1e, 0xe6, 0x96, 0x70, + 0xa4, 0x6e, 0x2b, 0xe2, 0x9c, 0x4b, 0x42, 0x08, + 0xbe, 0x04, 0x3e, 0x36, 0x60, 0x0d, 0x4e, 0x1d, + 0xd3, 0xf3, 0xd5, 0x15, 0xca, 0x11, 0x90, 0x20}; + EXPECT_TRUE(std::memcmp(second_countercert_sha256, cert->sha256.data, 32) == 0); + + EXPECT_EQ(cert->version, 2); + EXPECT_STREQ( + cert->subject, "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Time-Stamp PCA 2010"); + EXPECT_STREQ( + cert->issuer, + "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Root Certificate Authority 2010"); + EXPECT_EQ(cert->not_after, 1751406415); + EXPECT_EQ(cert->not_before, 1278020215); + EXPECT_STREQ( + cert->key, + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQAB"); + EXPECT_STREQ(cert->serial, "61:09:81:2a:00:00:00:00:00:02"); + EXPECT_STREQ(cert->sig_alg, "sha256WithRSAEncryption"); + EXPECT_STREQ(cert->key_alg, "rsaEncryption"); + + authenticode_array_free(auth); +} diff --git a/tests/integration/test.cpp b/tests/integration/test_non_microsoft.cpp similarity index 100% rename from tests/integration/test.cpp rename to tests/integration/test_non_microsoft.cpp