XML Signature规范是将数字签名和XML组合而成的产物,不要以为XML Signature仅仅是将数字签名技术应用于XML文件。
XML Signature包括以下的功能:
1.XML Signature可以对任何能够以URI形式(uniform resource identifier)定位的资源做签名。既包括与签名同在一个XML文件中的元素,也包括其他XML文件中的元素,甚至可以是非XML形式的资源(比如一个图形文件),只要能被URI定位到的资源都可以应用XML Signature. 这也代表了XML签名的对象可以是动态的变化。
2.XML Signature可以对XML文件中的任一元素做签名,也可以对整个文件做签名。
3.XML Signature 既可以用非对称密钥做签名(Digital Signature),也可以用对称密钥做签名(HMAC)。
XML Signature的结构如下:
<Signature>
<SignedInfo>
<CanonicalizationMethod>
<SignatureMethod>
(<Reference (URI=)? >
(Transforms)?
(DigestMethod)
(DigestValue)
</Reference>)+
</SignedInfo>
<SignatureValue>
(KeyInfo)?
(Object)*
</Signature>
(x)? 代表x出现0-1次 (x)+ 代表x出现1-n次 (x)* 代表x出现0-n次
下面对Signature中出现的各个元素做简要介绍:
SignedInfo表示最终要被签名的对象,签名主要包括两个过程先对要签名的对象做摘要,然后加密摘要(DSA不是加密摘要而是将摘要和密钥混合,效果类似)。XML Signature签名的对象并不仅仅是你引用的对象,而是包含了一些其他元素,比如CanonicalizationMethod, SignatureMethod元素,它是对整个SignedInfo元素做的签名。
CanonicalizationMethod代表了将XML元素标准化的方法,在XML的签名中与通常的签名有一个不同的地方在于XML元素的特殊性,比如同样一份XML文件在Windows下的表示方法和Linux下就会有所不同,因为同样一个换行符号在不同的操作系统代表的字符是不同的,但你不可能因为这个就认为这份XML文件被修改了;一个XML元素的两个属性的位置调换了,也不代表这份XML文件的完整性被破坏,所以在XML元素被签名前需要做一个标准化的处理。该元素就是指定其处理方法。
SignatureMethod指定了用于签名的方法,其中包括了摘要所用的方法以及是使用非对称密钥还是对称密钥加密(或混合)。
Reference表示真正想要签名的对象,通过URI定位到要签名的对象(一个xml元素或其他),如果没有指定URI就表示要签名的整个XML文件。
Transforms表示了在签名前可能对被签名对象所要做的转换,比如当待签名的对象是一个二进制资源时,为了避免该对象中可能出现非法的XML格式,就需要用Base-64将其转换一下。这里还可以使用一些其他的转化方法如XPATH和XSLT。
DigestMethod指定了对引用对象做摘要的方法,一般使用SHA1。
DigestValue这里面存放做完摘要后的结果,这样当后面对做SignedInfo签名的时候就间接的对引用对象做了签名,从而保证其完整性。
SignatureValue这里存放的是对SignedInfo元素标准化(CanonicalizationMethod)后签名(SignatureMethod)的结果。
KeyInfo是一个可选项,它用于消息接受方查找验证签名时所需的密钥,比如用某个特定的名称标识(Identity)来表示密钥,这样信息的接受方就可以根据这个标识来查找验证签名时所需要的密钥。如果消息交换双方之前已经约定好了签名的密钥就可以省略该元素。
Object用于定义一些扩展信息,也是可选项。
其中根据被签名对象(Reference中URI所指向的对象)和Signature元素所处的位置关系,将XML Signature做了一个分类。
如果被签名对象是Signature的子元素那么这个签名属于Enveloping Signatures类型。如果Signature是被签名对象的子元素,那么该签名属于Enveloped Signatures类型。如果以上两种都不是则属于Detached Signatures类型。
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<Reference URI="#111" />
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>...</KeyInfo>
<Object>
<SignedItem id="111">Stuff to be signed</SignedItem>
</Object>
</Signature>
Enveloping Signatures
<PurchaseOrder id="po1">
<SKU>125356</SKU>
<Quantity>17</Quantity>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<Reference URI="#po1" />
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>...</KeyInfo>
</Signature>
</PurchaseOrder>
Enveloped Signatures
<PurchaseOrderDocument>
<PurchaseOrder id="po1">
<SKU>12366</SKU>
<Quantity>17</SKU>
</PurchaseOrder>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<Reference URI="#po1" />
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>...</KeyInfo>
</Signature>
</PurchaseOrderDocument>
Detached Signatures 1
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<Reference URI="http://www.foo.com/picture.jpg" />
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>...</KeyInfo>
</Signature>
Detached Signatures 2
在了解了XML Signature的结构的基础上,再来看看XML Signature的处理过程,其中包括了Signature的创建以及验证过程。
在创建Signature的时候分为两个步骤:
1. 引用(Reference)的创建
1.1 利用URI定位到引用的资源,并获得其数据。
1.2 利用Transforms元素中指定的方法对引用的资源做转换。
1.3 利用DigestMethod元素中指定的方法对转换后的资源做摘要,获得的结果用于创建DigestValue元素。
1.4 将以上元素组合成Reference元素。
<Reference URI="http://www.foo.com/securePage.html">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>60NvZvtdTB+7UnlLp/H24p7h4bs=</DigestValue>
</Reference>
2. 签名(Signature)的创建
2.1 创建SignedInfo元素,并指定CanonicalizationMethod 和SignatureMethod的方法,然后将之前创建的Reference元素包含进来。
2.2 根据指定的CanonicalizationMethod将刚创建的SignedInfo元素标准化。
2.3 根据指定的SignatureMethod对标准化后的SignedInfo元素做签名,所得到的结果用于创建SignatureValue元素。
2.4 将SignedInfo,SignatureValue以及可选的KeyInfo和Object元素组合成Signature元素。
经过以上步骤,Signature创建完毕。最后介绍消息的接受方如何对Signature进行验证,从而确认消息的完整性。
Signature 的验证过程和创建过程一样也分为两个步骤,只有当Reference, Signature都通过验证才能保证消息的完整性。首先在验证前利用CanonicalizationMethod元素中指定的方法将整个 Signature元素标准化,然后开始验证各个部分:
1. 引用(Reference)的验证
1.1 利用URI定位到引用的资源,并获得其数据。
1.2 利用Transforms元素中指定的方法对引用的资源做转换。
1.3 利用DigestMethod元素中指定的方法对转换后的资源做摘要。
1.4 将上一步的结果与DigestValue中的内容做比较,如果完全一致,则通过验证。
2. 签名(Signature)的验证
2.1 获得用于验证的密钥。(可能事先已经约定好,也可能通过KeyInfo中的信息取得)
2.2 对经过标准化的SignedInfo元素做摘要。
2.3 利用在第一步中获得的密钥解密SignatureValue元素中的内容,将其与上一步创建的摘要做比较,如果完全一致,则通过验证。如果使用了数字签名(非对称密钥),那么消息还将具有抗否认性。
当以上的两个验证都通过时,可以得到以下的结论:
1. 消息在传送以及保存的过程中都没有被别人算改。
2. 消息的发送方与签名方一致(身份鉴别)。 因为密钥只有消息的发送方和消息的接受方知道。
3. 如果使用了数字签名(非对称密钥加密摘要), 那么还可以防止消息的发送方否认它曾经发送过此消息。