EternalWindows
ファイル署名 / MakeCert Functions

特定のCAに対して証明書の発行を申請し、 実際に.spcファイルや.pvkファイルを取得したユーザーからすれば、 SIPによる署名方法は決して使いやすいものとはいえないでしょう。 .spcファイルは複数の証明書を格納し、.pvkファイルは秘密鍵を格納していますが、 SIPはこれらをファイルとして受け取るのではなく、 ファイル内に格納されているデータを受け取る必要になっているため、 データの取得や変換という作業が重荷になってしまうのです。 MakeCert Functionsとは、証明書作成ツールであるmakecert.exeが呼び出している関数であり、 これらの関数は.spcファイルや.pvkファイルのファイル名を受け取ることができるため、 複雑な作業を行うことなくファイルに署名することができます。

MakeCert Functionsというと、makecert.exeが実装している関数のように思えますが、 実際に関数を実装しているのはmssign32.dllです。 このDLLの関数をmakecert.exeが呼び出しており、通常のアプリケーションからも利用できることになっています。 ただし、これらの関数を実装するヘッダーファイルやインポートライブラリは存在しないため、 関数は明示的にリンクしなければならず、 各種必要な構造体も明示的に定義しておくことになります。 mssign32.dllが実装する関数の中で、署名を行う機能を持っているのはSignerSignという関数ですが、 非常に多くの構造体を必要とするため、ヘッダーファイルとして下記にその定義を示します。 次節のプログラムを実行する場合は、このファイルをsigner.hとしてインクルードするようにしてください。

#define SIGNER_SUBJECT_BLOB 2
#define SIGNER_SUBJECT_FILE 1

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;

#define SIGNER_CERT_POLICY_CHAIN 2
#define SIGNER_CERT_POLICY_CHAIN_NO_ROOT 8
#define SIGNER_CERT_POLICY_STORE 1

typedef struct _SIGNER_CERT_STORE_INFO {
	DWORD cbSize;
	PCCERT_CONTEXT pSigningCert;
	DWORD dwCertPolicy;
	HCERTSTORE hCertStore;
} SIGNER_CERT_STORE_INFO,  *PSIGNER_CERT_STORE_INFO;

typedef struct _SIGNER_SPC_CHAIN_INFO {
	DWORD cbSize;
	LPCWSTR pwszSpcFile;
	DWORD dwCertPolicy;
	HCERTSTORE hCertStore;
} SIGNER_SPC_CHAIN_INFO,  *PSIGNER_SPC_CHAIN_INFO;

#define SIGNER_CERT_SPC_FILE 1
#define SIGNER_CERT_STORE 2
#define SIGNER_CERT_SPC_CHAIN 3

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;

typedef struct _SIGNER_ATTR_AUTHCODE {
	DWORD cbSize;
	BOOL fCommercial;
	BOOL fIndividual;
	LPCWSTR pwszName;
	LPCWSTR pwszInfo;
} SIGNER_ATTR_AUTHCODE,  *PSIGNER_ATTR_AUTHCODE;

#define SIGNER_AUTHCODE_ATTR 1
#define SIGNER_NO_ATTR 0

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;

#define PVK_TYPE_FILE_NAME 1
#define PVK_TYPE_KEYCONTAINER 2

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;

typedef struct _SIGNER_CONTEXT {
  DWORD cbSize;
  DWORD cbBlob;
  BYTE *pbBlob;
} SIGNER_CONTEXT,  *PSIGNER_CONTEXT;

ページハッシュについて

WindowsVistaでは、署名に含まれるspcIndirectDataContextデータに ページハッシュと呼ばれる情報を含むことが可能になっています。 この情報が何を意味するのかは定かではありませんが、 SIP_INDIRECT_DATA.Value.pbDataで示されるデータに、 SPC_SERIALIZED_OBJECT構造体が含まれることになり、 同構造体のSerializedDataがページハッシュの値となります。 デフォルトでは署名時にページハッシュが含まれることはありませんが、 WintrustSetDefaultIncludePEPageHashesを呼び出せば、 デフォルトでページハッシュを含むことができるようになります。

MakeCert Functionsの1つであるSignerSignExという関数は、 ページハッシュを含むかどうかを指定する引数を持っています。 この引数に0を指定した場合はデフォルトの設定が適応されることになりますが、 SPC_EXC_PE_PAGE_HASHES_FLAGを指定した場合は、デフォルト値に関係なく、 ページハッシュが含まれることはありません。 また、SPC_INC_PE_PAGE_HASHES_FLAGを指定した場合は、必ずページハッシュが含まれます。 なお、この2つの定数は、SIP_SUBJECTINFO構造体のdwFlagsに指定することも可能です。



戻る