2

openSSL を使用して XML デジタル署名を検証しようとしています。実際に EVP_VerifyFinal を使用すると、エラーコード 0D07209B (ASN1_get_object:too long) が表示されます。彼は私が証明書から KeyInfo をロードする方法です:

<KeyInfo>
 <KeyValue>
  <DSAKeyValue>
    <P>/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFw==</P>
    <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q>
    <G>Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA==</G>
    <Y>butK4tBy8dwSJFjTRpTvmYZYnsDGO4CzMVgcD8EQ2UJrQZd0ZapQI/Ea2DZzQBTFjjdnNkFuNOtjVI615lhiBQ==</Y>
  </DSAKeyValue>
 </KeyValue>
</KeyInfo>

PDSA をロードするための私の (疑似コード) メソッド:

 pDSA = DSA_new();
 pDSA.p = BN_bin2bn(base64Decode(text of P element));
 pDSA.q = BN_bin2bn(base64Decode(text of Q element));
 pDSA.g = BN_bin2bn(base64Decode(text of G element));
 pDSA.pub_key = BN_bin2bn(base64Decode(text of Y element));

この後に BN_bn2hex を使用すると、次の値が得られます。

p: FCA682CE8E12CABA26EFCCF7110E526DB078B05EDECBCD1EB4A208F3AE1617AE01F35B91A47E6DF63413C5E12ED0899BCD132ACD50D99151BDC43EE737592E17
q: 962EDDCC369CBA8EBB260EE6B6A126D9346E38C5
g: 678471B27A9CF44EE91A49C5147DB1A9AAF244F05A434D6486931D2D14271B9E35030B71FD73DA179069B32E2935630E1C2062354D0DA20A6C416E50BE794CA4
pub_key: 6EEB4AE2D072F1DC122458D34694EF9986589EC0C63B80B331581C0FC110D9426B41977465AA5023F11AD836734014C58E376736416E34EB63548EB5E6586205

、署名の検証:

  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
      <Reference URI="">
        <Transforms>
         <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
       </Transforms>
       <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>      
       <DigestValue>uooqbWYa5VCqcJCbuymBKqm17vY=</DigestValue>
      </Reference>
    </SignedInfo>    
    <SignatureValue>L4h4TFDj5rDKCHm0D+aH2LeSfAMV2t0V5S91Afu6U0NlfpjxdTXRUA==</SignatureValue> 
    <KeyInfo>
     <KeyValue>
      <DSAKeyValue>         
       <P>/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFw=</P> 
       <Q>li7dzDacuo67Jg7mtqEm2TRuOMU=</Q> 
       <G>Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOHCBiNU0NogpsQW5QvnlMpA==</G>
       <Y>POKkQtGuazaz6OEWi91P4C9z1tREpeP9f7L3piRD/3TiNFzvt0BmYzNO0CoPSjEVTXYKIRo/+HXK6MhBRk2eUw=</Y>
     </DSAKeyValue>
    </KeyValue>
   </KeyInfo>
  </Signature>
</Envelope>

署名を検証する方法は次のとおりです。

  pkey = EVP_PKEY_new;
  EVP_PKEY_set1_DSA(pkey, pdsa)
  EVP_MD_CTX_init(ctx);
  EVP_VerifyInit(@ctx, EVP_sha1)
  EVP_VerifyUpdate(@ctx, digest of SignedInfo);
  bytes = unbase64(text of SignatureValue)
  EVP_VerifyFinal(@ctx, btes, length(bytes)}, pKey);

final が次のエラーを返すことを確認します。

0D07207B:asn1 encoding routines:ASN1_get_object:header too long)
0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header)
0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error)

したがって、証明書または署名値を間違ってロードしています。仕様によると、署名値は「署名値は、値 r と s をその順序でオクテット エンコーディングした結果、2 つのオクテット ストリームを連結した base64 エンコーディングで構成されています」ですが、どこにも見つかりません。 DSA署名の署名値のためにEVP_VerifyInitに渡す必要があるopenSSLドキュメント。私が知る限り、同じ形式を指定しているように見える RFC 3279 を指す電子メール アーカイブで 1 つの参照を見つけました (Dss-Sig-Value ::= SEQUENCE { r INTEGER, s INTEGER }

4

1 に答える 1

1

はい、実際にはすでにあなた自身の質問に答えています。受信した署名を 2 つ (XML-DSig で指定されている 2 つの 20 バイト値) に分割してから、ASN.1 署名を作成する必要があります。実際には、次の ASN.1 DER 構造で構成されます。

Dss-Sig-Value ::= SEQUENCE {
    r INTEGER,
    s INTEGER
}

DER は「タグ、長さ、値」の構造です。現在、SEQUENCE にはタグ encodingがあり、次に 2 つのエンコードされ30た整数の DER の長さがあり、r と s は INTEGER 値であり、tag でエンコードされ、その後に符号付きビッグ エンディアン整数の最短表現が続きます。02

ASN.1 のプログラミングは良くてもトリッキーであり、最悪の場合はまったく脆弱です (OpenSSL の 1.0.1 までのすべてのバージョンにはメモリ破損のバグがあり、古い Windows NT 認証は完全に壊れていました)。疑似を使用してこの構造を作成する方法を示します。コード:

  • base64 をバイトに変換します (符号なし文字、40 個)
  • 最初の 20 バイトをrDataに使用し、2 番目をsData(または、半分に分割) に使用します。
  • andのすべての先頭 (左端)00の値のバイトを取り除きますrDatasData
  • 先頭のバイトが80以上の場合は、00バイトの前rDatasData
  • 30 LL { 02 LL { rData } 02 LL { sData } }LL が中かっこの間の構造体のバイト単位のサイズである構造体を作成します

エンコードはお任せします。LLこれは、値が 128 以上でない限り機能することに注意してください(これは DSA の場合です)。

ところで、ECDSA に切り替えたいと思うかもしれません。上記と同じ構造が必要になる可能性が高いことに注意してください。また、ダイジェストの入力が正しいかどうかはわかりませんが、少なくとも ASN.1 エラーは解決されるはずです。


最後に、現在の署名のこの構造00を取得する必要があります (これには初期値が含まれておらず、128 以上の初期バイトも含ま れていないため、少し退屈であることに注意してください)。

于 2014-10-06T23:33:38.560 に答える