/*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file file_signature.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_signature" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #include #include #include #include /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the file signature info type typedef struct __tb_file_signature_info_t { // is the file digitally signed? tb_bool_t is_signed; // is the signature valid and trusted by the OS? tb_bool_t is_trusted; /* the name of the signer (e.g., "Microsoft Corporation") tbox uses UTF-8 by default for tb_char_t */ tb_char_t signer_name[256]; } tb_file_signature_info_t; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_bool_t tb_file_get_signature_info(tb_char_t const* filepath, tb_file_signature_info_t* info) { tb_assert_and_check_return_val(filepath && info, tb_false); // init info tb_memset(info, 0, sizeof(tb_file_signature_info_t)); // convert path tb_wchar_t wide_path[TB_PATH_MAXN]; if (!tb_path_absolute_w(filepath, wide_path, TB_PATH_MAXN)) { return tb_false; } // init file info WINTRUST_FILE_INFO file_data = {0}; file_data.cbStruct = sizeof(file_data); file_data.pcwszFilePath = wide_path; file_data.hFile = NULL; file_data.pgKnownSubject = NULL; // init trust data WINTRUST_DATA trust_data = {0}; trust_data.cbStruct = sizeof(trust_data); trust_data.dwUIChoice = WTD_UI_NONE; trust_data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; trust_data.dwUnionChoice = WTD_CHOICE_FILE; trust_data.dwStateAction = WTD_STATEACTION_VERIFY; trust_data.hWVTStateData = NULL; trust_data.pwszURLReference = NULL; trust_data.dwProvFlags = WTD_SAFER_FLAG; trust_data.dwUIContext = 0; trust_data.pFile = &file_data; // verify trust GUID guid_action = WINTRUST_ACTION_GENERIC_VERIFY_V2; LONG status = WinVerifyTrust(NULL, &guid_action, &trust_data); // clean up trust_data.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust(NULL, &guid_action, &trust_data); // check status if (status == ERROR_SUCCESS) { info->is_signed = tb_true; info->is_trusted = tb_true; } else if (status == TRUST_E_NOSIGNATURE) { return tb_true; } else if (status == TRUST_E_EXPLICIT_DISTRUST || status == TRUST_E_SUBJECT_NOT_TRUSTED) { info->is_signed = tb_true; info->is_trusted = tb_false; } else { return tb_false; } // extract signer name if (info->is_signed) { HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; DWORD dwEncoding = 0; DWORD dwContentType = 0; DWORD dwFormatType = 0; PCMSG_SIGNER_INFO pSignerInfo = NULL; PCCERT_CONTEXT pCertContext = NULL; BOOL bResult = FALSE; bResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, wide_path, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); if (bResult) { DWORD cbSignerInfo = 0; if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &cbSignerInfo)) { pSignerInfo = (PCMSG_SIGNER_INFO)tb_malloc(cbSignerInfo); if (pSignerInfo) { if (CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (void*)pSignerInfo, &cbSignerInfo)) { CERT_INFO certInfo; certInfo.Issuer = pSignerInfo->Issuer; certInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = CertFindCertificateInStore(hStore, (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING), 0, CERT_FIND_SUBJECT_CERT, (PVOID)&certInfo, NULL); if (pCertContext) { tb_wchar_t wName[256] = {0}; if (CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, wName, 256)) { tb_wtoa(info->signer_name, wName, sizeof(info->signer_name)); } CertFreeCertificateContext(pCertContext); } } tb_free(pSignerInfo); } } } if (hStore) CertCloseStore(hStore, 0); if (hMsg) CryptMsgClose(hMsg); } return tb_true; } /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ /* get the file signature info * * local info = winos.file_signature(filepath) * { * is_signed = true, * is_trusted = true, * signer_name = "Microsoft Corporation" * } */ tb_int_t xm_winos_file_signature(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // get the arguments tb_char_t const *filepath = luaL_checkstring(lua, 1); tb_check_return_val(filepath, 0); // get signature info tb_file_signature_info_t info = {0}; if (tb_file_get_signature_info(filepath, &info)) { lua_newtable(lua); lua_pushstring(lua, "is_signed"); lua_pushboolean(lua, info.is_signed); lua_settable(lua, -3); lua_pushstring(lua, "is_trusted"); lua_pushboolean(lua, info.is_trusted); lua_settable(lua, -3); if (info.is_signed) { lua_pushstring(lua, "signer_name"); lua_pushstring(lua, info.signer_name); lua_settable(lua, -3); } return 1; } return 0; }