XMLの電子署名:署名値の算出について - PHPプロ!Q&A掲示板
2805
- 0P
- 0P
XMLの電子署名:署名値の算出について
質問日時 / 2010年7月13日 09:28 (最終編集:7月13日 18:45) 回答数 / 2件
Questioner: oka_hoccs
Tweet
XMLの正規化についてご教授いただけないかと思い、質問させていただきます。
開発に使用しているPHPのバージョンは5.2.6です。
またDOMのDOM/XML API Versionは2.6.32、OpenSSLのバージョンは0.9.8gとなります。
上記はXAMPP for Windowsの1.6.8のものです。
今回ご教授いただきたいのは、以下サンプルの署名値の算出についてです。
ハッシュ値の計算や署名に使用された証明書のBase64エンコード値の算出にはOpenSSLを使用しています。
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="20090101010101">
- <SignedInfo>
- <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
- <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
- <Reference URI="#%E6%A7%8B%E6%88%90%E6%83%85%E5%A0%B1">
- <Transforms>
- <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
- </Transforms>
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
- <DigestValue>[申請書に対する構成情報.xmlのハッシュ値]</DigestValue>
- </Reference>
- <Reference URI="999999999999999999_01.xml">
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
- <DigestValue>[999999999999999999_01.xmlのハッシュ値]</DigestValue>
- </Reference>
- </SignedInfo>
- <SignatureValue>[署名値]</SignatureValue>
- <KeyInfo>
- <X509Data>
- <X509Certificate>[署名に使用された証明書のBase64エンコード]</X509Certificate>
- <X509Certificate>[ルート証明書のBase64エンコード]</X509Certificate>
- </X509Data>
- </KeyInfo>
- </Signature>
署名値の算出を行うにあたり、仕様書には以下のような記載があります。
「Signature 要素は署名対象の内容に挿入されており、それによって包含署名になっています。
必須の SignedInfo 要素には、実際に署名される次の情報が含まれています。
必須の CanonicalizationMethod 要素は、署名または検証の前に SignedInfo 要素を正規化するために使用されるアルゴリズムを定義します。
正規化とは、そのデータに対する署名を無効化する可能性がある変更を考慮するために、XML の内容を正規形に変換する処理のことを意味します。
正規化は、XMLの性質および異なるプロセッサと中間的存在による解析のために必要です。
正規化により、署名が無効になっても署名されたデータが論理的に同等であるようにデータを変更できます。
必須の SignatureMethod 要素は、署名の生成に使用されるデジタル署名アルゴリズムを定義します。この場合は、SHA-1 を使用する DSA です。
必須の SignatureValue 要素には、SignedInfo 要素に対する署名の Base64- 符号化された署名値が含まれています。
XMLの正規化はW3Cに定義され公開されています。(http://www.w3.org/TR/xml-c14n)」
この仕様から以下のようなソースを作成し署名値を算出しようとしています。
該当ソース部分のみ抜粋しています。不足部分があれば追記させていただきます。
注)署名値を算出するために使用しているOpenssl関数のopenssl_signの第三引数の $certs[0][2] は署名付与の際に使用する電子証明書(.p12ファイル)から取得したRSA PRIVATE KEY(秘密鍵)の値となります。
- //署名値計算のため<SignedInfo>エレメント部分を変数に格納
- $strSigInfo = <<<XML
- <SignedInfo>
- <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
- <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
- <Reference URI="#%E6%A7%8B%E6%88%90%E6%83%85%E5%A0%B1">
- <Transforms>
- <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
- </Transforms>
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
- <DigestValue>[申請書に対する構成情報.xmlのハッシュ値]</DigestValue>
- </Reference>
- <Reference URI="999999999999999999_01.xml">
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
- <DigestValue>[999999999999999999_01.xmlのハッシュ値]</DigestValue>
- </Reference>
- </SignedInfo>
- XML;
- //Windows のCRLF改行(\r\n)をLF改行(\n)に変更
- $strSigInfo = str_replace("\r\n","\n",$strSigInfo);
- $dom = new domDocument;
- $dom->loadXML($strSigInfo);
- //SignedInfo 要素の正規化
- $dom->normalize();
- $signature = "" ;
- //署名値計算
- //第一引数:署名値の生成対象、第二引数:算出した署名値、
- //第三引数:暗号化キー(秘密鍵)、第四引数:署名アルゴリズム
- openssl_sign($dom->savexml(), $signature, $certs[0][2], OPENSSL_ALGO_SHA1);
- //署名値をBase64エンコード
- $strSigVale = base64_encode($signature) ;
上記ソースで算出した署名値がテスト環境でエラーとなり、正しい値を算出できないため、以下の点を教えていただければと思っております。
1.上記に記載した仕様の署名値を算出するためにopenssl_signを使用することは間違いないものなのかどうか。
2.openssl_signを使用して間違いない場合、SignedInfo 要素を正規化するためにDOMNode::normalizeを使用していますが、
うまく正規化できません。DOMNode::normalizeは正しく機能するものなのでしょうか。
正しく機能するというのはW3Cに定義されている形の正規化できるものかどうかということです。
私の上記ソース上ではW3Cに定義されている形の正規化の結果にはなっていないようです。むしろ逆の結果になっている感じがします。
3.DOMNode::normalizeが機能する場合は上記ソースではどのように使用することが正しいのでしょうか。
正しい署名値が算出できていないため、使用方法が間違っていると思っています。
4.DOMNode::normalizeが機能しない場合、PHPを使ってDOMNode::normalize以外の他の関数あるいはメソッドでSignedInfo 要素をW3Cに定義されている形で正規化する方法はあるのでしょうか。
色々と検索を行っていますが、DOMNode::normalize以外に見当たらず、DOMNode::normalize自体の情報もあまりありません。
XMLの電子署名に関しては情報がほとんどなく困っております。
よろしくお願いいたします。
引き続き調べたことを追記させていただきます。(2010/07/13)
XMLの正規化については、「ノーマライズ(normalize)」と「カノニカライズ(canonicalize)」というものが存在するようで、電子署名の正規化には「カノニカライズ(canonicalize)」が必要だということがわかりました。
http://japan.zdnet.com/glossary/exp/%E6%AD%A3%E8%A6%8F%E5%8C%96/
私がソース上で使用している以下部分については「ノーマライズ(normalize)」であり、これでは本来必要な「カノニカライズ(canonicalize)」の正規化を行うことは出来ないようです。
- $dom = new domDocument;
- $dom->loadXML($strSigInfo);
- //SignedInfo 要素の正規化
- $dom->normalize();
そこで質問を変更させていただきたいと思います。
・<SignedInfo>エレメントを「カノニカライズ(canonicalize)」で正規化するためのPHPで使用可能な関数・メソッドはあるのでしょうか。
・あるいは、<SignedInfo>エレメントを「カノニカライズ(canonicalize)」で正規化した結果というのはどのような形になるのか教えていただけませんか。
私としては、<SignedInfo>エレメント部分が正しく正規化できれば、関数やメソッドを使わずに$strSigInfoの文字列に格納することで署名値の算出が出来るのではないかと考えています。
XMLの正規化なので、PHPとは関係ない部分になってしまうかもしれませんが、ご存知の方おられましたら何卒よろしくお願いいたします。
この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。




ページのトップへ


今回のような実践的な経験がエンジニアのキャリアに繋がると思います。是非サービスを成功させて下さい!