プログラムによってアプリ パッケージに署名する方法 (C++)
SignerSignEx2 関数を使用してアプリ パッケージに署名する方法について説明します。
パッケージ化 API を使用して Windows アプリ パッケージをプログラムで作成する場合は、アプリ パッケージをデプロイする前に署名する必要もあります。 パッケージ化 API には、アプリ パッケージに署名するための特殊な方法は用意されていません。 代わりに、標準 暗号化関数 を使用してアプリ パッケージに署名します。
知っておくべきこと
テクノロジ
前提条件
- パッケージ化された Windows アプリが必要です。 アプリ パッケージの作成の詳細については、「アプリ パッケージを作成する方法」を参照してください。
- アプリ パッケージの署名に適したコード署名証明書が必要です。 テスト コード署名証明書の作成についての詳細、「アプリ パッケージ署名証明書 アプリ パッケージ署名証明書を作成する方法」を参照してください。 この署名証明書を CERT_CONTEXT 構造に読み込みます。 たとえば、PFXImportCertStore と CertFindCertificateInStore を使用して署名証明書を読み込むことができます。
- Windows 8 では、SignerSignEx2 関数が導入されています。 Windows アプリ パッケージに署名するときは、SignerSignEx2 を使用します。
手順
手順 1: SignerSignEx2 に必要な構造体を定義する
SignerSignEx2 関数は、Wincrypt.h ヘッダーに加えて、SDK ヘッダー ファイルで定義されていない多くの構造体に依存します。 SignerSignEx2SignerSignEx2 を使用するには、次の構造体を自分で定義する必要があります。
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;
手順 2: SignerSignEx2 を呼び出してアプリ パッケージに署名する
前の手順で指定した必要な構造を定義したら、SignerSignEx2 関数で使用できるオプションのいずれかを使用してアプリ パッケージに署名できます。 Windows アプリ パッケージで SignerSignEx2 を使用する場合、次の制限が適用されます。
- アプリ パッケージに署名するときに、pSipData パラメーターとして APPX_SIP_CLIENT_DATA 構造体へのポインターを指定する必要があります。 アプリ パッケージの署名に使用するのと同じパラメーターを APPX_SIP_CLIENT_DATA の pSignerParams メンバーに設定する必要があります。 これを行うには、SIGNER_SIGN_EX2_PARAMS 構造体に必要なパラメーターを定義し、この構造体のアドレスを pSignerParams に割り当ててから、SignerSignEx2 を呼び出すときにも構造体のメンバーを直接参照します。
- SignerSignEx2 を呼び出した後、NULL でない場合は pAppxSipState で IUnknown::Release を呼び出して、pSipData の pAppxSipState を解放する必要があります。
- SIGNER_SIGNATURE_INFO 構造体の algidHash メンバーは、アプリ パッケージの作成に使用されたハッシュ アルゴリズムと同じである必要があります。 アプリ パッケージからハッシュ アルゴリズムを決定する方法については、「SignTool を使用してアプリ パッケージに署名する方法」を参照してください。 MakeAppx と Visual Studio がアプリ パッケージの作成に使用する Windows 8 の既定のアルゴリズムは、algidHash = CALG_SHA_256 です。
- アプリ パッケージの署名にもタイム スタンプを設定する場合は、SignerSignEx2 の省略可能なタイム スタンプ パラメーター (dwTimestampFlags、pszTimestampAlgorithmOid、pwszHttpTimeStamp、psRequest) を指定して、SignerSignEx2 の呼び出し中にこれを行う必要があります。 既に署名されているアプリ パッケージで SignerTimeStampEx3 またはそのバリアントを呼び出すことはサポートされていません。
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;
}
解説
アプリ パッケージに署名した後は、WinVerifyTrust 関数と WINTRUST_ACTION_GENERIC_VERIFY_V2 を使用して、プログラムで署名の検証を試みることもできます。 この場合、Windows アプリ パッケージで WinVerifyTrust を使用する場合の特別な考慮事項はありません。
関連トピック