1 签名类型
- 包封式:签名封装在被签名数据中,一起发往接收端
- 分离式:签名和被签名数据分离发送的
2 XML的数字签名格式
<Signature> <SignedInfo> <CanonicalizationMethod/> 规范化方法,用于去除空格和其他格式 <SignatureMethod/> (<Reference (URI)?> (<Transforms/>)? <DigestMethod/> <DigestValue/> </Reference>)+ </SignedInfo> <SignatureValue/> (<KeyInfo/>)? (<Object ID?/>)* </Signature> |
3 式例--包封式签名示例
需要被签名的XML文档如下:
<license> <test>hello world</test> </license> |
签名后的XML:
<license> <test>hello world</test> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <!--[s01]--> <ds:SignedInfo> <!--[s02]--> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2006/12/xml-c14n11" /> <!--[s03]--> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> <!-- [s04]--> <ds:Reference URI="" Id=""> <!--[s05]--> <ds:Transforms> <!--[s06]--> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <!--[s07]--> <ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" /> </ds:Transforms> <!--[s08]--> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> <!--[s09]--> <ds:DigestValue> <!--[s10] --> d+F/TTTxoF2Fk/knoTwHLqC7gqa+ETnTn84sNwx4c0Y= </ds:DigestValue> </ds:Reference> <!--[s11]--> </ds:SignedInfo> <!--[s12]--> <ds:SignatureValue>KdSti.....6OA==</ds:SignatureValue> <!--[s13]--> <ds:KeyInfo> <!--[s14]--> <ds:KeyValue> <!--[s15a]--> <ds:RSAKeyValue> <!--[a15b]--> <ds:Modulus>nM95A0J.....+GQ==</ds:Modulus> <!--[a15c]--> <ds:Exponent>AQAB</ds:Exponent> <!--[a15d]--> </ds:RSAKeyValue> <!--[a15e]--> </ds:KeyValue> <!--[a15f]--> </ds:KeyInfo> <!--[a16]--> </ds:Signature> <!--[a17]--> </license> |
SignedInfo
[s02-12]该元素的子元素包含有关所签名的内容以及签名方式的所有信息。签名算法实际上应用于该元素及其所有子元素以生成签名。
CanonicalizationMethod
[s03]该元素指定了用于SignedInfo元素以便将XML规范化的规范化(C14N)算法。(常常也是transform算法的一部分)
SignatureMethod
[s04]该元素指定了该签名的签名算法。这里的签名算法是带有RSA的SHA-256。
Reference
- [s05-11]这些元素指定了将要签名的数据,并指定哈希运算之前应当如何对该数据进行处理。URI属性(它表示统一资源标识符)标识要签名的数据,而Transforms元素(稍后描述)指定在进行哈希运算之前如何处理数据。在该示例中,我们将使用特殊的URI——空字符串,它表明签名与被签名在同一个包中(包封式)。Id属性用来标记xml包中需要局部签名的数据Id.
- XML签名标准对Reference数据使用间接签名机制。该标准不是对Reference中的所有数据进行统一的哈希运算然后加密哈希值,而是使用由Reference的DigestMethod元素所指定的算法对每个Reference的数据进行哈希运算,然后将哈希值存储到Reference的DigestValue元素中。接下来,对SignedInfo元素和它的所有子元素(包括Reference元素)进行哈希运算;哈希值被加密以生成签名。因此,您实际上是对Reference元素中所引用数据的哈希的哈希进行签名,但是该方案仍然可以保护数据的完整性。
- [s05]Reference的这个可选 URI 属性标识要签名的数据对象。 在一个 Signature 中,至多可以对一个Reference省略该属性。(为了确保明确地匹配引用和对象, 要强加这个限制。)
- [s06-08]该标识与transforms一起是签名者提供的描述, 其内容有关它们如何获得已编摘形式的已签名数据对象(即,已编摘的内容)。验证者还可能以另一种方法获得已编摘的内容,只要摘要验证这种方法。
Transforms
[s06-08]每个Reference元素都可以具有零个或更多个为它指定的转换。这些转换按照它们在XML中列出的顺序应用于该Reference的数据。转换使您可以在对Reference的数据进行哈希运算之前对该数据进行筛选或修改。在该示例中,我们将使用包封式签名转换,该转换选择了包含文档中除Signature元素以外的所有XML(排除Signature元素)。我们必须从将被签名的数据中移除Signature元素,否则,当我们存储签名值时,可能会修改我们尝试签名的数据。
DigestMethod
[s09-10]DigestMethod 是在应用 Transforms(如果已经指定它)之后对数据应用以产生 DigestValue 的算法。DigestValue 存储产生的哈希值。
SignatureValue
[s13]该元素包含通过签名SignedInfo元素及其所有子元素而计算得到的签名值。
KeyInfo
[s14-16]KeyInfo表示用于验证签名的密钥(公钥)。标识机制可以包括证书、密钥名称和密钥协议算法。KeyInfo是可选的有两个原因:首先,签名者可能不希望向所有文档处理方披露任何密钥信息。其次,该信息在应用程序上下文中可能是已知的,并且不需要明确表示。 由于KeyInfo在SignedInfo之外,所以如果签名者希望将密钥信息与签名绑定,那么Reference可以容易地将KeyInfo作为签名的一部分标识并将其包括在内(在Reference增加被签名数据源)。
3.1 签名过程
- 首先,对于签名中的每个Reference元素:
- 按照转换在Transforms元素下面出现的顺序,将Transform元素中指定的每个转换算法应用于Reference的数据。
- 使用Reference的DigestMethod元素所指定的哈希算法对经过转换的数据进行哈希运算。
- 在Reference的DigestValue元素中存储产生的哈希值。
- 然后,使用在签名的CanonicalizationMethod元素中指定的算法规范化SignedInfo元素及其子元素。
- 最后,使用在签名的SignatureMethod元素中指定的算法对SignedInfo元素及其子元素进行签名。签名值被存储在SignatureValue元素中。
3.2 验证过程
签名验证是刚刚描述的过程的逆过程。
- 首先,必须使用CanonicalizationMethod元素中指定的C14N算法规范化SignedInfo元素及其子元素。
- 然后,必须针对SignedInfo元素及其子元素验证SignatureValue元素中存储的签名值。
- 最后,对于签名中的每个Reference元素:
- 按照转换在Transforms元素下面出现的顺序,将Reference的Transform元素中指定的每个转换算法应用于Reference的数据。
- 使用Reference的DigestMethod元素所指定的哈希算法对Reference的经过转换的数据进行哈希运算。
- 将计算得到的哈希值与DigestValue元素中存储的值进行比较。
个人理解
从上面有关xml签名的规范看(被签名数据-[transform/Canonicalization/Digest]->DigestValue-[Canonicalization/Signature]->SignatureValue),确实可以做到万无一失保证数据不被篡改,但是每一条报文都这样是否消耗太多资源
参考: