XKMS 使安全性易于管理
级别:入门
XML 密钥管理规范(XML Key Management Specification,XKMS)为访问和集成公钥基础设施(Public Key Infrastructure,PKI)拟出了一种容易的机制。在本文中,Manish Verma 解释了 XKMS 背后的目标,之后还为使用 XKMS 服务来注册和检索与公钥和/或私钥相关的信息提供了逐步操作指南。
随着越来越多的个人和企业依赖于 Internet 来交换机密信息和敏感信息,安全性已经成为一个热门问题。其中有两个与安全性相关的话题得到了极大的重视:
易于管理:使得安全性基础设施的使用及其与应用程序的集成比较容易,以便于广泛采纳。
可移植的信任:在与某个实体建立了信任关系之后,要有一种标准机制来将那种信任转移至另一个协作的实体。单点登录(Single SignOn)就是可移植的信任的一个典型实例。当某个用户经过了一个特定网站的认证之后,就有一种标准机制将那种信息传递给其他需要该用户认证信息的协作站点。这样那些站点就可以透明地共享关于某个实体的信息,而不必一次又一次地请求那个实体的同样的信息。要使单点登录生效,这些实体必须认识彼此的凭证(credential)。
XML 密钥管理规范(XML Key Management Specification,XKMS)使得安全性基础设施易于管理,而安全性断言标记语言(Security Assertion Markup Language,SAML)则使信任可以移植。SAML 为在相互协作的各个不同实体之间传输关于实体认证的断言提供了一种机制,这样就不必迫使这些实体失去对信息的所有权。
本文将讨论 XKMS 在管理安全性基础设施的过程中所扮演的角色,并为使用 XKMS 提供一个逐步操作指南。
可管理性问题
XML 加密和数字签名依赖于公共密钥基础设施(Public Key Infrastructure,PKI)来帮助加密(encrypt)、解密(decrypt)、签名(sign)和验证(verify)各种文档。对于一个要使用 XML 加密和/或数字签名的应用程序来说,它必须使用或者集成一个 PKI 解决方案。有很多 PKI 解决方案可供使用,例如 X.509 (使用最广泛)、Pretty Good Privacy (PGP)、Simple Public Key Infrastructure (SPKI) 和 Public Key Infrastructure X.509 (PKIX)。问题是,到底该使用或集成哪种解决方案呢?
不幸的是,答案并不像选择某种可用的 PKI 并与之集成那么简单。真正的问题是,一个应用程序要想与其他应用程序对话,它必须知道多少 PKI 以及这些 PKI 的语法和语义,而其他应用程序又可能使用其他可用的 PKI 解决方案来发送经过编码或签名的文档,或者期望收到这样的文档。例如,如果组织 A 使用 X.509 PKI 解决方案,它要发送加密的文档给组织 B,而组织 B 使用的是 SPKI PKI 解决方案,那么,组织 B 就不能解密和使用由组织 A 发送的文档。要使 A 和 B 协同工作,它们当中必须有一方能够理解另一方的 PKI 解决方案。如果将这种场景再扩展一下,假设牵涉到多方,那么显然所有方都必须知道彼此的 PKI 解决方案,这样就使应用程序的复杂性增加了很多倍。
在本文的其余部分,我将演示 XKMS 如何为这个问题提供答案。
XML 密钥管理规范(XKMS)
XKMS 将管理客户机应用程序的 PKI 的复杂性抽象到了一个受信任的第三方,从而使 PKI 易于管理。这个受信任的第三方在提供一个到客户机应用程序的 PKI 接口的同时驻留了 XKMS 服务。
XKMS 的目标
XKMS 的主要目标是:
在应用程序与 PKI 解决方案之间创建一个抽象层。这样就允许应用程序根据需要插入不同的 PKI 解决方案,而不需要对应用程序本身作任何修改。
提供一种基于 XML 的简单协议,以便通过 XKMS 服务处理密钥信息,使应用程序不必理解复杂的 PKI 语法和语义。
将复杂性从客户机应用程序转移到基础设施层,从而允许应用程序更简单、更小巧。这样一来,即使是占用内存很少(small footprint)的设备也可以利用 PKI。
实现 XKMS,使其平台无关、供应商无关和传输协议无关。
XKMS 概述
XKMS 是以 Web 服务的形式实现的,它允许客户机应用程序访问 PKI 功能,从而减少客户机应用程序的复杂性。客户机应用程序不需要关心底层 PKI 的语法,底层 PKI 可以是以下的任何一种:
X.509 (最广泛使用)
Pretty Good Privacy (PGP)
Simple Public Key Infrastructure (SPKI)
Public Key Infrastructure X.509 (PKIX)
XKMS 规范由两个规范组成,其中一个规范与公钥的注册有关 —— XML 密钥注册服务规范(XML Key Registration Service Specification,XKRSS),另一个规范关心的是基于密钥信息的信息检索 —— XML 密钥信息服务规范(XML Key Information Service Specification,XKISS)。
另一种规范,也就是 X-Bulk,是由万维网联盟(Worldwide Web Consortium,W3C)发布的。该规范用于解决批量注册密钥对这一问题。我将在讨论了 XKRSS 之后解释 X-Bulk。
XML 密钥注册服务规范(XKRSS)
XKMS 的这一部分为将密钥对注册到服务提供程序提供机制。可以有两种方式来将密钥注册到一个 XKMS 服务:
客户机生成一个密钥对,并将公钥和其他信息一起提供给服务提供程序,以便注册。
XKMS 服务为客户机生成一个密钥对,将密钥对的公钥注册到它自己,然后将密钥对的私钥发送给客户机,供其使用。客户机还可以告诉 XKMS 服务,让 XKMS 服务也保留私钥。在客户机丢失了私钥的情况下,私钥就与 XKMS 服务保持一致。
XKRSS 服务规范定义了四种操作:
注册(Register):通过密钥绑定将信息与一个密钥对绑定。在注册期间,要么是客户机提供公钥以及其他证明其拥有相应私钥的某些证据,要么是服务提供程序为客户机生成密钥对。服务提供程序在注册公钥(还可能同时包括私钥)之前,可以向客户机请求更多的信息。
重新发行(Reissue):重新绑定之前已经注册的密钥。可以使用该操作生成底层 PKI 中的新凭证。虽然 XKMS 使用的密钥绑定信息没有寿命,但是底层 PKI 颁发的凭证偶尔也会有这么一段时间,过了这段时间之后就要周期性地更新。
撤销(Revoke):该操作允许客户机销毁一个密钥所绑定到的数据对象。例如,当调用这个操作时,绑定到一个 XKMS 密钥的 X.509 凭证将被销毁。
恢复(Recover):该操作允许客户机恢复私钥。要使该操作有意义,私钥必须已经注册到了服务提供程序。要想服务提供程序拥有私钥,那么就应该在服务器上而不是在客户机上生成密钥对。
恢复操作在密钥对的私钥被用来加密数据的情况下添加很多值。如果丢失了私钥,则加密的数据也会丢失。当出现这种情况时,让私钥在服务器上生成并让服务提供程序保留该私钥是明智的。这样就可恢复私钥。
如果丢失的私钥只是用于数字签名文档,那么就可以生成一个新的密钥,而不会影响对已经签名的文档的有效性。因此,由客户机来生成那种用途的密钥是很安全的,而且完全可以不将私钥注册到 XKMS 服务。
实现了 XKRSS 服务规范的 XKMS 服务可以选择提供一些、所有或者不提供这些操作。XKRSS 服务规范并不强制要求 XKMS 服务实现上述任何一种操作。
密钥对的批量注册(X-Bulk)
X-Bulk 处理在一条请求消息内同时注册多个密钥对,这与 XKRSS 不同,后者只处理一次注册一个密钥对的情况。X-Bulk 规范定义了一个批量元素,这种元素可以有多个注册请求或者多个服务器响应,所有这些请求或响应都遵从 XKMS 消息格式。与 XKRSS 一样,X-Bulk 服务支持所有四种操作 —— 注册(Register)、重新发行(Reissue)、撤销(Revoke)和恢复(Recover)。X-Bulk 可以处理客户机和服务器生成的密钥对的批量注册。
XML 密钥信息服务规范(XKISS)
XKMS 的这一部分为允许客户机应用程序认证经过加密/签名的数据提供机制。
客户机通过将相应的密钥信息传递给服务提供程序来认证经过加密或签名的数据。而服务提供程序则以 "true" 或 "false" 响应。"true" 表明,用于签名的私钥所对应的公钥的确属于那个宣称对该文档进行了签名的实体。
XKISS 服务规范定义了下面两种操作:
定位(Locate):定位操作解析可能与 XML 加密或 XML 签名有关的 元素,但是没有证明 元素中数据绑定的有效性。
确认(Validate):定位操作能做的一切该操作都能做,而且还可以做更多的事情。定位服务根据 元素发现一个密钥,但是不保证密钥绑定信息是否值得信任。而确认操作不仅可以搜索 元素所对应的公钥,而且还保证它返回的密钥绑定信息是值得信任的。
XKMS 过程
在这一节中,我将带您一步一步地经历注册和检索密钥的过程。
基于 XKRSS 的注册过程允许注册客户机生成的密钥,也允许注册服务器生成的密钥。在注册客户机生成的密钥时,客户机首先生成密钥,然后通过发送公钥和提供私钥作为所有权的证据来请求 XKMS 服务注册密钥对的公钥。在注册服务器生成的密钥时,XKMS 服务同时生成私钥和公钥,然后将私钥发送给客户机。
清单 1 演示了如何注册客户机生成的密钥。为了使用该清单中的代码,必须与某个具有演示或测试 XKMS 服务运行的 XKMS 服务提供程序联系。从该服务提供程序获取您在将密钥注册到它们的演示或测试 XKMS 服务时所需的信息。我使用 Verisign 作为 XKMS 提供程序,并且使用共享密钥(shared secret)和密钥名,它们是提供给我用于注册密钥的。
清单 1. XKMS 密钥注册
String sharedSecret = "passcode";
String passPhrase = "passPhrase";
KeyPair rsakey = getKeyPair();
String keyName =
"http://xkms.verisign.com/keyname?jurisdiction=d7ea68c518b2602ca4bbca895826a7dd&"+
"mail_email=mverma2@xkms.org&corp_company=Nano";
XKMSKeyData data = new XKMSKeyData(rsakey, new XKMSKeyName(keyName));
XKMSAuthInfo authInfo = new XKMSAuthInfo(passPhrase, sharedSecret);
XKMSRegister register = new XKMSRegister(data, authInfo);
XKMSRegisterResponse resp = null;
String serviceurl = "http://interop-xkms.verisign.com/xkms/Acceptor.nano";
URL url = new URL(serviceurl);
XmlTransportSOAP transport = new XmlTransportSOAP(url);
resp = register.send(transport);
System.out.println("Response status is " + resp.getStatus());
if (resp.getStatus()) {
System.out.println("The key name is " + resp.getKeyName());
System.out.println("The public key is " + resp.getPublicKey());
}
步骤 1: 从要注册密钥对的服务提供程序那里获得密码(共享密钥)。服务提供程序还可以提供与密码一起使用的密钥名。
步骤 2: 使用 getKeyPair() 在客户机上生成密钥对。getKeyPair() 的代码是您可以利用本文下载的源代码的一部分(请参阅 参考资料)。
步骤 3: 指定 XKMS 密钥注册所需的密钥数据。创建 XKMSKeyData 对象。提供密钥对和密钥名作为输入。在密钥对中,公钥是已注册的,私钥用于作为所有权的证明。XKMSKeyData 中使用的密钥名必须遵从由提供程序指定的特定格式。
步骤 4: 指定 XKMS 密钥注册所需的注册授权数据。有两种方式可以用来提供授权信息:
共享密钥:注册请求伴随着共享密钥,共享密钥由带外(out-of-band)客户机的注册中心给出。
注册中心(registration authority,RA)认证:使用 RA 的 X.509 证书和 RA 的私钥。在清单 1 中,我演示了共享密钥认证机制的使用。
步骤 5: 通过提供 XKMS 密钥数据和授权信息,创建 XKMSRegister 对象的一个实例。
步骤 6: 创建一个 XmlTransportSOAP 对象。提供运行注册服务时所在的 URL 作为输入。
步骤 7: 使用 send 方法发送请求给 XKMSRegister 对象,将 XmlTransportSoap 实例传递给这个方法。
send 方法首先注册密钥,然后返回一个 XKMSRegisterResponse 对象。可以通过查询这个对象来获得密钥名和其他密钥信息。通过查询 XKMSRegisterResponse 对象而得到的密钥名不同于您在步骤 3 中创建 XKMSKeyData 对象时提供的密钥名。以后您将使用这个密钥名来定位密钥。
接下来,我将演示如何定位一个已经注册到服务提供程序的密钥。(用于定位密钥的清单 2 中所演示的机制使用了这个密钥名。在清单 2 的后面我将更详细地加以解释。)
清单 2. 定位密钥
// The key name that you got from the XKMSRegisterResponse
// Object
String keyNameToLocate =
"http://xkms.verisign.com/key?company=VeriSign&department=XKMS Test&"+
"CN=MANISH VERMA6&issuer_serial=73efeeea87e159e6d7fc790ef01c6fe7";
// An array of response strings to indicate what key
// information is requested
String[] xkmsResponse =
{XKMSLocate.KeyName,XKMSLocate.KeyValue,XKMSLocate.X509Cert,XKMSLocate.X509Chain };
XKMSLocateResponse locateResponse = null;
XKMSLocate xkmsLocate = new XKMSLocate(keyName,xkmsResponse);
String serviceurl = "http://interop-xkms.verisign.com/xkms/Acceptor.nano";
URL url = null;
url = new URL(serviceurl);
XmlTransportSOAP transport = new XmlTransportSOAP(url);
locateResponse = xkmsLocate.sendRequest(transport);
List keyInfoList = locateResponse.getXKMSKeyInfos();
Iterator itr = keyInfoList.iterator();
XKMSKeyInfo xkmsKeyInfo = null;
while (itr.hasNext()){
xkmsKeyInfo = (XKMSKeyInfo)itr.next();
}
步骤 1: 为了定位一个密钥,您可以使用以下任何信息进行查询:
密钥名(这应该是先前在一个 XKMSRegisterResponse 对象中返回的密钥名)。注册时与 XKMSKeyData 一起使用的那个密钥名这里不能使用。
公钥值。
X.509 证书。
在清单 2 中,我使用密钥名来查询密钥。
步骤 2: 指定一个响应字符串数组,这些字符串的值都是我们感兴趣的。
步骤 3: 用密钥名和响应字符串数组创建 XKMSLocate 对象。
步骤 4: 创建一个 XmlTransportSOAP 对象。提供运行注册服务时所在的 URL 作为输入。
步骤 5: 使用 sendRequest 方法发送请求给 XKMSLocate 对象,将 XmlTransportSoap 实例传递给该方法。
步骤 6: 获取 XKMSLocateResponse 对象。从这个对象中,您可以获得一个 XKMSKeyInfo 对象列表。迭代这些对象,以获得与响应字符串对应的信息。
XKMS 服务本身的安全性
您还没完全了解 XKMS。您还应该了解一些事情,然后才可以把文档和应用程序的安全性托付给 XKMS 服务。在这一节中我大致谈到的问题与所有基于 Web 的服务有关,但是应该确保 XKMS 可靠和可用,这一点很重要。
防止重复攻击(replay attack):确保 XKMS 服务为某请求发送的回复不被未经授权的第三方捕获到。这个捕获到的响应可以被第三方作为对其他请求的响应再次发送,并假装它就是 XKMS 服务本身。您可以通过各种标准方式来处理这种情况,例如给响应加时间戳。
防止服务的抵赖攻击(denial of service attack):使用 XKMS 来获取密钥信息比较有用,前提是 XKMS 在需要的时候可用,并且这一过程能在合理的时间内完成。实现服务时,必须使其能够承受服务的抵赖攻击,从而保持高度可用。
验证一个良好的、健壮的密钥恢复策略:确保 XKMS 服务提供程序具有一个良好的、健壮的密钥恢复策略,因为这直接影响着签名文档的否认和加密文档的可靠性。
结束语
通常,好的技术之所以不能坚持到底,是因为它们使用起来过于笨重。在这种情况下,只有一小撮忠实的开发人员会继续使用这种技术,而一般的 IT 部门不再采纳这种技术。PKI 问世已经有多年了,但是它还没有走进一般的 IT 部门。现在,XKMS 为使用 PKI 和将 PKI 与应用程序集成提供了一种容易的机制。在本文中,我解释了在各种 PKI 解决方案上使用一个 XKMS 抽象层的目的,并演示了使用 XKMS 服务来注册和定位密钥是多么的容易。在我的下一篇文章中,我将重点解释如何通过 SAML 使这种信任可移植。
|