2011-01-18 14 views
5

私はブラジルの "Nota Fiscal Eletronica"プロジェクトを使用しています。このプロジェクトでは、XML文書に署名するための標準的な方法が定義されています。Javaで空白や改行がないXML署名を生成するにはどうすればよいですか?

最近では、署名タグ(*)を含むタグ間に空白がまったくないことを要求し始めました。

私はApacheのXMLSignatureを使用することがあり、インデントされていない署名が生成されていないようです。

署名後に空白を削除すると、署名が破損します。

canonicalizer /トランスセットは、あらかじめ定義されているため変更できません。

インデントまたは空白を制御するためにXMLSignature APIでオプションまたはパラメータが見つかりませんでした。以下

// the element where to insert the signature 
    Element element = ...; 
    X509Certificate cert = ...; 
    PrivateKey privateKey = ...; 

    XMLSignature signer = 
      new XMLSignature(doc, "http://xml-security", 
      XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1); 

    element.appendChild(signer.getElement()); 

    Transforms transforms = new Transforms(doc); 

    // Define as regras de transformação e canonicalização do documento 
    // XML, necessário para fazer a verificação do parsing e da 
    // assinatura pelos destinatários 
    transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); //, xpath.getElementPlusReturns()); 

    transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS); //,xpath.getElementPlusReturns()); 

    String id = ""; 

    id = ((Element) element.getElementsByTagName("infNFe").item(0)).getAttributeNode("Id").getNodeValue(); 

    signer.addDocument("#" + id, transforms, 
         Constants.ALGO_ID_DIGEST_SHA1); 
    signer.addKeyInfo(cert); 
    signer.sign(privateKey); 

得られた署名(スニペット)は:

<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#rsa-sha1"/> 
<Reference URI="#NFe43110189716583000165550010000076011492273645"> 
<Transforms> 
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
</Transforms> 
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
<DigestValue>fas0ra5uRskQgRHSrIYhEjFEjKQ=</DigestValue> 
</Reference> 
</SignedInfo> 
<SignatureValue> 
2RGltUZy0HfNoiKtVanAeN+JUPyglWDuQNnMudSgA7kESoHBZ/q/GMbc+xMSN1eV8u7+2PxSKl1T 
Zl592FWmCSAkL8pwMujDxJ4iTLU20Hf0dNF7oGcyB+g9GgbipW2udq0kwJLz6HzXUD/Evf/0y+3T 
NtsXeIaA6A29ttD/UEs= 
</SignatureValue> 
<KeyInfo> 
<X509Data> 
<X509Certificate> 
MIIFqTCCBJGgAwIBAgIEQeNSuzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJicjETMBEGA1UE 
ChMKSUNQLUJyYXNpbDEgMB4GA1UECxMXQ2FpeGEgRWNvbm9taWNhIEZlZGVyYWwxFDASBgNVBAMT 
C0FDIENBSVhBIFBKMB4XDTEwMDYwODE5MjQwNVoXDTExMDYwODE5NTQwNVowgYQxCzAJBgNVBAYT 
AmJyMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYDVQQLExdDYWl4YSBFY29ub21pY2EgRmVkZXJh 
bDEUMBIGA1UECxMLQUMgQ0FJWEEgUEoxKDAmBgNVBAMTH0EgQlVITEVSIFNBIENVUlRVTUU6NDA5 
NDI0OTAwMTAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOFxgvG35RQWgXec4zVrzoUHolnJ 
fP76rpO2Vo40593W9Gf0WwHt36gVmli0ZeQitFmzFSoE5KhgXQGZg6RpV3WJUFcIrPBHPdqOSfiB 
988kf962P+j8fZ38BNmo7TV9H9hMBkV9bD/QOe73wFDc+rT6/9io++Z+7/wup/3glKntAgMBAAGj 
ggLOMIICyjAOBgNVHQ8BAf8EBAMCBeAwVwYDVR0gBFAwTjBMBgZgTAECAQkwQjBABggrBgEFBQcC 
ARY0aHR0cDovL2ljcC5jYWl4YS5nb3YuYnIvcmVwb3NpdG9yaW8vZHBjYWNjYWl4YXBqLnBkZjAp 
BgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwgbYGA1UdEQSBrjCBq4EV 
YnVobGVyQGFidWhsZXIuY29tLmJyoD4GBWBMAQMEoDUEMzE0MDkxOTQ2NDA5NDI0OTAwMTAxMDg0 
NDcwODE3NTAwMDAwODAzMjkyMjM1NlNTUCBSU6AeBgVgTAEDAqAVBBNOQUlSIEJVSExFUiBTQ0hO 
RUNLoBkGBWBMAQMDoBAEDjg5NzE2NTgzMDAwMTY1oBcGBWBMAQMHoA4EDDAwMDAwMDAwMDAwMDCC 
ATIGA1UdHwSCASkwggElMIGuoIGroIGohjJodHRwOi8vaWNwLmNhaXhhLmdvdi5ici9yZXBvc2l0 
b3Jpby9BQ0NBSVhBUEoxLmNybIY0aHR0cDovL2ljcDIuY2FpeGEuZ292LmJyL3JlcG9zaXRvcmlv 
Mi9BQ0NBSVhBUEoxLmNybIY8aHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5nb3YuYnIvbGNy 
L2NhaXhhL0FDQ0FJWEFQSjEuY3JsMHKgcKBupGwwajELMAkGA1UEBhMCYnIxEzARBgNVBAoTCklD 
UC1CcmFzaWwxIDAeBgNVBAsTF0NhaXhhIEVjb25vbWljYSBGZWRlcmFsMRQwEgYDVQQDEwtBQyBD 
QUlYQSBQSjEOMAwGA1UEAxMFQ1JMNDEwHwYDVR0jBBgwFoAUjkAvCv4T1ao5oHZ0htO8fcfx5c8w 
CQYDVR0TBAIwADAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIDqDANBgkqhkiG9w0BAQUFAAOCAQEA 
nZHUvdnZsiCIDjKm1zHehbtuDtDJha4O4FZ03J74Y+AxyAFs/4JED+xUvZ5jFuEsdqgA0V/dxUFy 
Uz/ca10Ievd578GQdGwYl1GFhRtO/SlxeaOEf7eDdGOWXO3VmUA3NmNo0X8RRTIoifnhpDXu7RbN 
5sijyH/uXyRFWX9XH2N0U/r3oJtNKXsvoUlbDrkalgkuLzLKsaEj0TkwisXO3cmMoWGuBpAZC+46 
e4x/2vTqOvYkzZO+O9NLi0YWSYY7OJKiKBjMC6MzdlPM9VTkIwO9WvWEMdbU0/jhO2cMcVMzNZc1 
r6ZmdTDrwqV3elSTkQtJ0RIZNgMJUn+Y8c7Aog== 
</X509Certificate> 
</X509Data> 
</KeyInfo> 
</Signature> 

お知らせ(望ましくない)改行以下

コードです。

ご協力いただければ幸いです。

ありがとうございます。

(*)明確化:新しいルールは、要素のみのタグ間の空白(または他のテキスト)を禁止します。一例として、これはを許可されるであろう:

<a><b> 
    text 
    inside 
    tag 
</b></a> 

このをを禁止されることになるつつ:

<a> 
<b>text</b> 
</a> 

なぜなら後者の場合には、空白(改行)は、2つのタグの間にありますつまり、要素のみのタグの内部に配置されます。

+6

問題は、その要件はXMLとビューのXMLDSIGポイントから意味をなさないということです。おそらく彼らはコードで間違いを犯してしまいましたが、今は間違いを確認してコードを修正する代わりに、他のすべての人が壊れた実装を処理してもらいたいと思います。 –

+0

私は@Eugene Mayevski 'EldoS Corpをサポートしています。上記のようなXMLを問題なく処理しました。 – Bozho

+0

彼らは、ネットワークトラヒックを減らすために(実際には巨大な)このルールを述べていると主張している。何故ならば、いくつかのソフトウェアには酷使されたくぼみの空白が含まれているからだ。署名を正常に検証できます。メッセージが拒否された場合に適用される、この他の(無関係で新しい)ルールが適用されます。私は署名部分にこの制限を課すべきではない、と私は同意する。 –

答えて

7

XML生成で '\ n'を無効にする場合は、-Dorg.apache.xml.security.ignoreLineBreaks = trueを設定するだけです。 original mail

bug description

+0

私がこのソリューションをテストすることはできませんでした。回答した時点で、別の署名APIを選択して回避策のソリューションを既に適用していたためです。しかし、私はリンクを見て、これはまさに私が戻って探していた単純ではるかに少ないトラウマの解決策であるようです。 –

+0

リンクが機能しない –

3

シグネチャブロックは、バイナリ情報をBase64としてエンコードしています。は、である必要があります(改行を含む)。http://en.wikipedia.org/wiki/Base64を参照してください。したがって、情報を変更することなく削除することはできません。

ネットワークトラフィックを再描画するには、データを送信する前にコンセンティブを使用することをお勧めします。

+0

+1、非常に良い答えです。ウィキペディアの記事には、最大行の長さと行の区切りがあると書かれています。これを修正するには、圧縮を使用するのが正しい方法です。 – Bozho

+0

新しいルールは、タグ間の空白だけを禁止します。リーフタグ内のテキスト(base64エンコードされた情報など)には、空白が含まれることがあります。これを明確にするために質問を更新します。 –

+0

私たちは私たちをあきらめています。この場合、あなたはそれを働かせるかもしれません(私の他の答えを見てください)。 – lweller

2

幸運にもXMLSignature is opensourceなので、ソースコードを入手して自分自身をハックする必要があります。

おそらく、あなたのソリューションは今後他の人に役立つので、パッチを作成してプロジェクトに送り返すことができます。

幸運を祈る!

:)

0

XML署名兆候がC14Nアルゴリズムで正規化した後、指定された要素(DOMに即ちサブツリー)で始まるXML文書の一部。使用する標準のC14Nアルゴリズムは改行と空白を保持します(http://www.w3.org/TR/xml-c14n#Example-WhitespaceInContent参照)。

署名を変更しないようには(最後のデータのタグと<Signature>タグとの間、及び</Signature>間、次の終了タグを含む)原稿の署名された部分内のすべての改行が* 保存されなければなりません。 Signature要素内の改行やスペースは重要ではなく、署名を変更せずに削除することができます。ここで

例:ここでは

<root id="signedpart"> 
    <data> 
    ... 
    </data> 
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <SignedInfo> 
     <Reference URI="#signedpart"> 
      ... 
     </Reference> 
    </SignedInfo> 
    </Signature> 
</root> 

は、あなたの可能なオプションは以下のとおりです。

  1. は、それ自身でスペースや改行を削除します独自のC14Nアルゴリズムを定義します。他の側もこの非標準のC14Nアルゴリズムを使用しなければならないので、私はこれをお勧めしません。

    <root id="signedpart"><data>...</data><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
        <SignedInfo> 
         <Reference URI="#signedpart"> 
          ... 
         </Reference> 
        </SignedInfo> 
        </Signature></root> 
    

  2. 削除ラインは、それに署名(および潜在的に後で署名にスペースを削除)これはあなたに以下の署名XMLを与える例で

を前にXML からスペースを破ります

と署名後のスペースを削除した後

<root id="signedpart"><data>...</data><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><Reference URI="#signedpart">...</Reference></SignedInfo></Signature></root> 
+0

オプション1 canonicalizers ansトランスフォームはあらかじめ定義されており、変更することはできないため、私はそうすることはできません。 –

+0

オプション2.後で署名からスペースを削除すると、署名が避けられなくなります。唯一の方法は、改行せずに署名をまっすぐに生成することだと私は思う。 –

+0

私はそれを私の自己(apache xmlsec 1.4.4)でテストし、改行とスペースを削除する**の間には、**タグのタグはそれを変更しない。 – lweller

1

私は(恥ずかしい)解決策を見つけました。

ApacheのAPIをjavax.xml.crypto APIに置き換えることは、予想される解決策ではありません。ここで

が変更されたコードです:

// the element where to insert the signature 
Element element = ...; 
X509Certificate cert = ...; 
PrivateKey privateKey = ...; 
// Create a DOM XMLSignatureFactory that will be used to 
// generate the enveloped signature. 
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

// Create a Reference to the enveloped document (in this case, 
// you are signing the whole document, so a URI of "" signifies 
// that, and also specify the SHA1 digest algorithm and 
// the ENVELOPED Transform. 
List<Transform> transformList = new ArrayList<Transform>(); 
TransformParameterSpec tps = null; 
Transform envelopedTransform; 
try { 
    envelopedTransform = fac.newTransform(Transform.ENVELOPED, 
      tps); 
    Transform c14NTransform = fac.newTransform(
      "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", tps); 

    transformList.add(envelopedTransform); 
    transformList.add(c14NTransform); 
} catch (NoSuchAlgorithmException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} catch (InvalidAlgorithmParameterException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} 

// Create the KeyInfo containing the X509Data. 
KeyInfoFactory kif = fac.getKeyInfoFactory(); 
List<Serializable> x509Content = new ArrayList<Serializable>(); 
x509Content.add(cert); 
javax.xml.crypto.dsig.keyinfo.X509Data xd = kif.newX509Data(x509Content); 
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 

// Obtem elemento do documento a ser assinado, será criado uma 
// REFERENCE para o mesmo 
Element el = (Element) element.getElementsByTagName(subTag).item(0); 
String id = el.getAttribute("Id"); 

// Create a DOM XMLSignatureFactory that will be used to 
// generate the enveloped signature. 

Reference ref; 
javax.xml.crypto.dsig.SignedInfo si; 
try { 
    ref = fac.newReference("#" + id, fac.newDigestMethod(
      DigestMethod.SHA1, null), transformList, null, null); 

    // Create the SignedInfo. 
    si = fac.newSignedInfo(fac.newCanonicalizationMethod(
      CanonicalizationMethod.INCLUSIVE, 
      (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
      Collections.singletonList(ref)); 
} catch (NoSuchAlgorithmException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} catch (InvalidAlgorithmParameterException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} 

// Create the XMLSignature, but don't sign it yet. 
javax.xml.crypto.dsig.XMLSignature signature = fac.newXMLSignature(si, ki); 

// Marshal, generate, and sign the enveloped signature. 
// Create a DOMSignContext and specify the RSA PrivateKey and 
// location of the resulting XMLSignature's parent element. 
DOMSignContext dsc = new DOMSignContext(privateKey, element); 
signature.sign(dsc); 

このAPIは、すべてのタグの間には空白で署名を生成します。

このコードは既に成熟しているので、まだapacheのAPIのソリューションを見たいと思っています。署名の実装全体を変更するほどのリスクはありません。

0

私達はちょうど「ignoreLineBreaks」パラメータに「真」の値を設定する必要があり、 原因は、」デフォルト値はfalseで、これは改行に

を追加するために、署名APIにできますここでは、その後

Field f = XMLUtils.class.getDeclaredField("ignoreLineBreaks"); 
f.setAccessible(true); 
f.set(null, Boolean.TRUE); 

を改行を回避または除去するためのコードがあり、私たちは、新しい値が次のコード行で真であることを確認することができます

System.err.println(XMLUtils.ignoreLineBreaks()); 

私は同じ問題を抱えていましたが、これは私の役に立つものでした。

0

あなたは試すことができます:

System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true"); 
関連する問題