SignedData型とエンコード今回は、データをSignedData型にエンコードする方法について説明します。実際には必ずしもそれが含まれるわけではありません。署名者が存在しないことから、署名データは含まれていません。単純に証明書を維持するための形式としても利用することができます。データをエンコードするには、CryptMsgOpenToEncodeを呼び出します。pStreamInfo);dwMsgEncodingTypeは、エンコーディングタイプを指定します。dwFlagsは、基本的に0を指定します。dwMsgTypeは、メッセージタイプを指定します。SignedData型ならCMSG_SIGNEDを指定し、EnvelopedData型ならCMSG_ENVELOPEDを指定します。pvMsgEncodeInfoは、メッセージタイプに関連する構造体を指定します。pszInnerContentObjIDは、コンテンツのOIDを指定することができますが、NULLで問題ありません。pStreamInfoは、ストリーミングに関する引数ですが、基本的にNULLを指定します。戻り値は、メッセージのハンドルが返ります。pvMsgEncodeInfoにCMSG_SIGNED_ENCODE_INFO構造体のアドレスを指定します。*PCMSG_SIGNED_ENCODE_INFO;cbSizeは、この構造体のサイズをバイト単位で指定します。cSignersは、rgSignersの要素数を指定します。rgSignersは、CMSG_SIGNER_ENCODE_INFO構造体のアドレスを指定します。この構造体は署名者の情報を含んでおり、NULLを指定した場合は署名は行われません。cCertEncodedは、rgCertEncodedの要素数を指定します。rgCertEncodedは、証明書のバイトデータの配列を指定します。cCrlEncodedは、rgCrlEncodedの要素数を指定します。rgCrlEncodedは、CRLの配列を指定します。cAttrCertEncodedは、rgAttrCertEncodedを指定します。rgAttrCertEncodedは、証明書の属性を格納したデータの配列を指定します。今回のプログラムは、データをSignedData型にエンコードとしてファイルに保存します。TEXT("証明書の取得に失敗しました。TEXT("署名に失敗しました。TEXT("署名に成功しました。CMSG_SIGNED_ENCODE_INFO構造体を初期化することになります。署名者の情報を表すCMSG_SIGNER_ENCODE_INFO構造体を初期化することにします。署名者の証明書とハッシュアルゴリズムが必要です。ハッシュアルゴリズムはszOID_RSA_MD5とします。これらの情報は証明書に関連付けられているはずなので、CryptAcquireCertificatePrivateKeyで取得することができます。続いて、CMSG_SIGNED_ENCODE_INFO構造体の初期化について見ていきます。エンコードされたデータに追加したい証明書をCERT_BLOB構造体の形で指定します。署名者の証明書を追加したいので、そのサイズとバイトデータをsignerCertBlobに指定しています。メッセージのハンドルを取得することができます。第2引数のデータがSignedData型にエンコードされてメッセージのコンテンツとして格納されています。メッセージのコンテンツは、CMSG_CONTENT_PARAMを指定したCryptMsgGetParamで取得できます。署名データを含まない場合は、CryptMsgUpdateの呼び出しは必要ありません。実際に署名を検証するコードを次に示します。TEXT("検証に失敗しました。0;}ファイルからSignedData型のデータを取得し、それをCryptMsgUpdateに指定します。メッセージのコンテンツはデコードされたデータが格納されています。その前にデータが改ざんされていないかの検証が必要です。事前に検証に使うためのCERT_INFO構造体を取得しておく必要があります。この取得部分は、次のようになっています。署名者の情報をCERT_INFO構造体で取得することができます。IssuerとSerialNumberだけであり、CryptMsgControlに指定する情報としては不十分です。このバイトデータをIssuerとSerialNumberを基に取得する必要があります。同一の値を持つ証明書コンテキストを返すことができます。CertOpenStoreでメッセージのハンドルをを証明書ストアと見立ておきます。証明書コンテキストに含まれるCERT_INFO構造体は適切に初期化されています。