Cara menandatangani paket aplikasi secara terprogram (C++)
Pelajari cara menandatangani paket aplikasi dengan menggunakan fungsi SignerSignEx2.
Jika Anda ingin membuat paket aplikasi Windows secara terprogram dengan menggunakan API Kemasan, Anda juga perlu menandatangani paket aplikasi sebelum dapat disebarkan. API Kemasan tidak menyediakan metode khusus untuk menandatangani paket aplikasi. Sebagai gantinya, gunakan fungsi kriptografi standar untuk menandatangani paket aplikasi Anda.
Apa yang perlu Anda ketahui
Teknologi
- Pengantar Penandatanganan Kode
- Pengemasan, penyebaran, dan kueri aplikasi Windows
- fungsi kriptografi
Prasyarat
- Anda harus memiliki aplikasi Windows yang dipaketkan. Untuk informasi tentang membuat paket aplikasi, lihat Cara membuat paket aplikasi.
- Anda harus memiliki sertifikat penandatanganan kode yang sesuai untuk menandatangani paket aplikasi. Untuk informasi tentang membuat sertifikat penandatanganan kode pengujian, lihat Cara membuat sertifikat penandatanganan paket aplikasi. Muat sertifikat penandatanganan ini ke dalam struktur CERT_CONTEXT. Misalnya, Anda dapat menggunakan PFXImportCertStore dan CertFindCertificateInStore untuk memuat sertifikat penandatanganan.
- Windows 8 memperkenalkan fungsi SignerSignEx2. Gunakan SignerSignEx2 saat Anda menandatangani paket aplikasi Windows.
Petunjuk
Langkah 1: Tentukan struktur yang diperlukan untuk SignerSignEx2
Selain header Wincrypt.h, fungsi SignerSignEx2 bergantung pada banyak struktur yang tidak ditentukan dalam file header SDK apa pun. Untuk menggunakan SignerSignEx2, Anda harus menentukan struktur ini sendiri:
typedef struct _SIGNER_FILE_INFO
{
DWORD cbSize;
LPCWSTR pwszFileName;
HANDLE hFile;
}SIGNER_FILE_INFO, *PSIGNER_FILE_INFO;
typedef struct _SIGNER_BLOB_INFO
{
DWORD cbSize;
GUID *pGuidSubject;
DWORD cbBlob;
BYTE *pbBlob;
LPCWSTR pwszDisplayName;
}SIGNER_BLOB_INFO, *PSIGNER_BLOB_INFO;
typedef struct _SIGNER_SUBJECT_INFO
{
DWORD cbSize;
DWORD *pdwIndex;
DWORD dwSubjectChoice;
union
{
SIGNER_FILE_INFO *pSignerFileInfo;
SIGNER_BLOB_INFO *pSignerBlobInfo;
};
}SIGNER_SUBJECT_INFO, *PSIGNER_SUBJECT_INFO;
// dwSubjectChoice should be one of the following:
#define SIGNER_SUBJECT_FILE 0x01
#define SIGNER_SUBJECT_BLOB 0x02
typedef struct _SIGNER_ATTR_AUTHCODE
{
DWORD cbSize;
BOOL fCommercial;
BOOL fIndividual;
LPCWSTR pwszName;
LPCWSTR pwszInfo;
}SIGNER_ATTR_AUTHCODE, *PSIGNER_ATTR_AUTHCODE;
typedef struct _SIGNER_SIGNATURE_INFO
{
DWORD cbSize;
ALG_ID algidHash;
DWORD dwAttrChoice;
union
{
SIGNER_ATTR_AUTHCODE *pAttrAuthcode;
};
PCRYPT_ATTRIBUTES psAuthenticated;
PCRYPT_ATTRIBUTES psUnauthenticated;
}SIGNER_SIGNATURE_INFO, *PSIGNER_SIGNATURE_INFO;
// dwAttrChoice should be one of the following:
#define SIGNER_NO_ATTR 0x00
#define SIGNER_AUTHCODE_ATTR 0x01
typedef struct _SIGNER_PROVIDER_INFO
{
DWORD cbSize;
LPCWSTR pwszProviderName;
DWORD dwProviderType;
DWORD dwKeySpec;
DWORD dwPvkChoice;
union
{
LPWSTR pwszPvkFileName;
LPWSTR pwszKeyContainer;
};
}SIGNER_PROVIDER_INFO, *PSIGNER_PROVIDER_INFO;
//dwPvkChoice should be one of the following:
#define PVK_TYPE_FILE_NAME 0x01
#define PVK_TYPE_KEYCONTAINER 0x02
typedef struct _SIGNER_SPC_CHAIN_INFO
{
DWORD cbSize;
LPCWSTR pwszSpcFile;
DWORD dwCertPolicy;
HCERTSTORE hCertStore;
}SIGNER_SPC_CHAIN_INFO, *PSIGNER_SPC_CHAIN_INFO;
typedef struct _SIGNER_CERT_STORE_INFO
{
DWORD cbSize;
PCCERT_CONTEXT pSigningCert;
DWORD dwCertPolicy;
HCERTSTORE hCertStore;
}SIGNER_CERT_STORE_INFO, *PSIGNER_CERT_STORE_INFO;
//dwCertPolicy can be a combination of the following flags:
#define SIGNER_CERT_POLICY_STORE 0x01
#define SIGNER_CERT_POLICY_CHAIN 0x02
#define SIGNER_CERT_POLICY_SPC 0x04
#define SIGNER_CERT_POLICY_CHAIN_NO_ROOT 0x08
typedef struct _SIGNER_CERT
{
DWORD cbSize;
DWORD dwCertChoice;
union
{
LPCWSTR pwszSpcFile;
SIGNER_CERT_STORE_INFO *pCertStoreInfo;
SIGNER_SPC_CHAIN_INFO *pSpcChainInfo;
};
HWND hwnd;
}SIGNER_CERT, *PSIGNER_CERT;
//dwCertChoice should be one of the following
#define SIGNER_CERT_SPC_FILE 0x01
#define SIGNER_CERT_STORE 0x02
#define SIGNER_CERT_SPC_CHAIN 0x03
typedef struct _SIGNER_CONTEXT
{
DWORD cbSize;
DWORD cbBlob;
BYTE *pbBlob;
}SIGNER_CONTEXT, *PSIGNER_CONTEXT;
typedef struct _SIGNER_SIGN_EX2_PARAMS
{
DWORD dwFlags;
PSIGNER_SUBJECT_INFO pSubjectInfo;
PSIGNER_CERT pSigningCert;
PSIGNER_SIGNATURE_INFO pSignatureInfo;
PSIGNER_PROVIDER_INFO pProviderInfo;
DWORD dwTimestampFlags;
PCSTR pszAlgorithmOid;
PCWSTR pwszTimestampURL;
PCRYPT_ATTRIBUTES pCryptAttrs;
PVOID pSipData;
PSIGNER_CONTEXT *pSignerContext;
PVOID pCryptoPolicy;
PVOID pReserved;
} SIGNER_SIGN_EX2_PARAMS, *PSIGNER_SIGN_EX2_PARAMS;
typedef struct _APPX_SIP_CLIENT_DATA
{
PSIGNER_SIGN_EX2_PARAMS pSignerParams;
IUnknown* pAppxSipState;
} APPX_SIP_CLIENT_DATA, *PAPPX_SIP_CLIENT_DATA;
Langkah 2: Panggil SignerSignEx2 untuk menandatangani paket aplikasi
Setelah menentukan struktur yang diperlukan yang ditentukan di langkah sebelumnya, Anda dapat menggunakan salah satu opsi yang tersedia pada fungsi SignerSignEx2 untuk menandatangani paket aplikasi. Saat Anda menggunakan SignerSignEx2 dengan paket aplikasi Windows, pembatasan ini berlaku:
- Anda harus menyediakan penunjuk ke struktur APPX_SIP_CLIENT_DATA sebagai parameter pSipData saat Anda menandatangani paket aplikasi. Anda harus mengisi anggota pSignerParams dari APPX_SIP_CLIENT_DATA dengan parameter yang sama dengan yang Anda gunakan untuk menandatangani paket aplikasi. Untuk melakukan ini, tentukan parameter yang Anda inginkan pada struktur SIGNER_SIGN_EX2_PARAMS , tetapkan alamat struktur ini ke pSignerParams, lalu langsung referensikan anggota struktur juga ketika Anda memanggil SignerSignEx2.
- Setelah Anda memanggil SignerSignEx2, Anda harus membebaskan pAppxSipState di pSipData dengan memanggil IUnknown::Release di pAppxSipState jika bukan NULL.
- Anggota algidHash dari struktur SIGNER_SIGNATURE_INFO harus memiliki algoritma hash yang sama yang digunakan dalam membuat paket aplikasi. Untuk informasi tentang cara menentukan algoritma hash dari paket aplikasi, lihat Cara menandatangani paket aplikasi menggunakan SignTool. Algoritma default Windows 8 yang digunakan MakeAppx dan Visual Studio untuk membuat paket aplikasi adalah "algidHash = CALG_SHA_256".
- Jika Anda ingin memberi stempel waktu tanda tangan pada paket aplikasi juga, Anda harus melakukannya selama panggilan ke SignerSignEx2 dengan menyediakan parameter stempel waktu opsional SignerSignEx2 (dwTimestampFlags, pszTimestampAlgorithmOid, pwszHttpTimeStamp, psRequest). Memanggil SignerTimeStampEx3 atau variannya pada paket aplikasi yang sudah ditandatangani tidak didukung.
Berikut adalah beberapa contoh kode yang menunjukkan cara memanggil SignerSignEx2:
HRESULT SignAppxPackage(
_In_ PCCERT_CONTEXT signingCertContext,
_In_ LPCWSTR packageFilePath)
{
HRESULT hr = S_OK;
// Initialize the parameters for SignerSignEx2
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_CHAIN_NO_ROOT;
certStoreInfo.pSigningCert = signingCertContext;
SIGNER_CERT cert = {};
cert.cbSize = sizeof(SIGNER_CERT);
cert.dwCertChoice = SIGNER_CERT_STORE;
cert.pCertStoreInfo = &certStoreInfo;
// The algidHash of the signature to be created must match the
// hash algorithm used to create the app package
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;
APPX_SIP_CLIENT_DATA sipClientData = {};
sipClientData.pSignerParams = &signerParams;
signerParams.pSipData = &sipClientData;
// Type definition for invoking SignerSignEx2 via GetProcAddress
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);
// Load the SignerSignEx2 function from MSSign32.dll
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);
}
// Free any state used during app package signing
if (sipClientData.pAppxSipState)
{
sipClientData.pAppxSipState->Release();
}
return hr;
}
Keterangan
Setelah menandatangani paket aplikasi, Anda juga dapat mencoba memvalidasi tanda tangan secara terprogram dengan menggunakan fungsi WinVerifyTrust dengan WINTRUST_ACTION_GENERIC_VERIFY_V2. Tidak ada pertimbangan khusus dalam hal ini untuk menggunakan WinVerifyTrust dengan paket aplikasi Windows.
Topik terkait