I came across the need to use SignerSignEx2() during to the process of submitting Kernel drivers for Microsoft’s approval.
SignerSignEx2()[
^] is used to programmatically sign these drivers. Microsoft requires the use of an
EV (Extended Validation) Code Signing Certificate[
^] for Kernel Drivers targeted to Windows 10, and that requires a hardware token (
Safenet eToekn[
^], in most cases).
We access our token from a tool we developed, which makes it easy, otherwise you need to key in the token’s password each time, which is the case had we used
SignTool.exe[
^].
However, in order to cross sign, there is no much documentation as for how to use SignerSignEx2() (or the more recent SignerSignEx2() for that matter) to combine the EV certificate we bought, with the CA root certificate along with Microsoft’s root certificate.
See also
this page about the need to cross sign.[
^]
What I have tried:
Basically, following the instructions in
this article[
^] and in Microsoft Docs
documentation. The article guides throughout the process of using SignerSignEx2().[
^]
SignerSignEx2Function SignerSignEx2 = reinterpret_cast<SignerSignEx2Function>(
GetProcAddress(msSignModule, "SignerSignEx2"));
if (SignerSignEx2)
{
hr = SignerSignEx2(
signerParams.dwFlags,
signerParams.pSubjectInfo,
signerParams.pSigningCert,
signerParams.pSignatureInfo,
signerParams.pProviderInfo,
signerParams.dwTimestampFlags,
signerParams.pszAlgorithmOid,
signerParams.pwszTimestampURL,
signerParams.pCryptAttrs,
signerParams.pSipData,
signerParams.pSignerContext,
signerParams.pCryptoPolicy,
signerParams.pReserved);
There is explanation about time stamping but nothing about cross signing. Several attempts we have made caused the Root Certificate to replace our own certificate instead of being added to it in a chain.
My function assumes the EV Certificate has already been read to memory (that allows me to either read it from a .pfx file or from the eToken as PCCERT_CONTEXT ). As you can see, I tried reading the Cross Certificate (
CROSSCERTPATH) and somehow combining it and that part doesn't work. I am also predefining
SIGNER_TIMESTAMP_AUTHENTICODE which is the time stamping URL, and that parts does work.
HRESULT SignAppxPackage(
_In_ PCCERT_CONTEXT signingCertContext,
_In_ LPCWSTR packageFilePath)
{
PCCERT_CONTEXT Root = OpenCert(CROSSCERTPATH);
HRESULT hr = S_OK;
DWORD signerIndex = 0;
SIGNER_FILE_INFO fileInfo = {};
fileInfo.cbSize = sizeof(SIGNER_FILE_INFO);
fileInfo.pwszFileName = packageFilePath;
SIGNER_SUBJECT_INFO subjectInfo = {};
subjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO);
subjectInfo.pdwIndex = &signerIndex;
subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE;
subjectInfo.pSignerFileInfo = &fileInfo;
SIGNER_CERT_STORE_INFO certStoreInfo = {};
certStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO);
certStoreInfo.dwCertPolicy = SIGNER_CERT_POLICY_STORE;
certStoreInfo.pSigningCert = Root;
SIGNER_CERT cert = {};
cert.cbSize = sizeof(SIGNER_CERT);
cert.dwCertChoice = SIGNER_CERT_POLICY_CHAIN;
cert.pCertStoreInfo = &certStoreInfo;
SIGNER_SIGNATURE_INFO signatureInfo = {};
signatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);
signatureInfo.algidHash = CALG_SHA_256;
signatureInfo.dwAttrChoice = SIGNER_NO_ATTR;
SIGNER_SIGN_EX2_PARAMS signerParams = {};
signerParams.pSubjectInfo = &subjectInfo;
signerParams.pSigningCert = &cert;
signerParams.pSignatureInfo = &signatureInfo;
signerParams.dwTimestampFlags = SIGNER_TIMESTAMP_AUTHENTICODE;
signerParams.pszAlgorithmOid = NULL;
signerParams.pwszTimestampURL = TIMESTAMPURL;
APPX_SIP_CLIENT_DATA sipClientData = {};
sipClientData.pSignerParams = &signerParams;
signerParams.pSipData = &sipClientData;
typedef HRESULT(WINAPI *SignerSignEx2Function)(
DWORD,
PSIGNER_SUBJECT_INFO,
PSIGNER_CERT,
PSIGNER_SIGNATURE_INFO,
PSIGNER_PROVIDER_INFO,
DWORD,
PCSTR,
PCWSTR,
PCRYPT_ATTRIBUTES,
PVOID,
PSIGNER_CONTEXT *,
PVOID,
PVOID);
HMODULE msSignModule = LoadLibraryEx(
L"MSSign32.dll",
NULL,
LOAD_LIBRARY_SEARCH_SYSTEM32);
if (msSignModule)
{
SignerSignEx2Function SignerSignEx2 = reinterpret_cast<SignerSignEx2Function>(
GetProcAddress(msSignModule, "SignerSignEx2"));
if (SignerSignEx2)
{
hr = SignerSignEx2(
signerParams.dwFlags,
signerParams.pSubjectInfo,
signerParams.pSigningCert,
signerParams.pSignatureInfo,
signerParams.pProviderInfo,
signerParams.dwTimestampFlags,
signerParams.pszAlgorithmOid,
signerParams.pwszTimestampURL,
signerParams.pCryptAttrs,
signerParams.pSipData,
signerParams.pSignerContext,
signerParams.pCryptoPolicy,
signerParams.pReserved);
}
else
{
DWORD lastError = GetLastError();
hr = HRESULT_FROM_WIN32(lastError);
}
FreeLibrary(msSignModule);
}
else
{
DWORD lastError = GetLastError();
hr = HRESULT_FROM_WIN32(lastError);
}
if (sipClientData.pAppxSipState)
{
sipClientData.pAppxSipState->Release();
}
return hr;
}