6.2.6. 提供加密密钥和签名密钥

概述

标准 WS-SecurityPolicy 策略是为了在一些详细信息中指定 安全要求 :例如,安全协议、安全算法、令牌类型、身份验证要求等等。但是,标准策略断言不提供指定相关安全数据的任何机制,如密钥和凭证。WS-SecurityPolicy 期望通过专有机制提供必要的安全数据。在 Apache CXF 中,相关的安全数据通过 Blueprint XML 配置提供。

配置加密密钥和签名密钥

您可以通过在客户端的请求上下文或端点上下文中设置属性来指定应用程序的加密密钥和签名密钥(请参阅 “为 Blueprint 配置添加加密和签名属性”一节)。您可以设置的属性显示在 表 6.1 “加密和签名属性” 中。

表 6.1. 加密和签名属性

属性描述

security.signature.properties

WSS4J 属性文件/对象,包含用于配置签名密钥存储(也用于解密)和 Crypto 对象的 WSS4J 属性属性。

security.signature.username

(可选) 要使用的签名密钥存储中密钥的用户名或别名。若不指定,则使用属性文件中设置的别名。如果也未设置,并且密钥存储仅包含一个密钥,则将使用该密钥。

security.encryption.properties

WSS4J 属性文件/对象,包含用于配置加密密钥存储(也用于验证签名)和 Crypto 对象的 WSS4J 属性属性。

security.encryption.username

(可选) 加密密钥存储中要使用的密钥的用户名或别名。若不指定,则使用属性文件中设置的别名。如果也未设置,并且密钥存储仅包含一个密钥,则将使用该密钥。

上述属性的名称不会被正确选择,因为它们无法准确反映它们的用途。由 security.signature.properties 指定的密钥实际上用于 签名和 解密。由 security.encryption.properties 指定的密钥实际上用于加密 验证签名。

为 Blueprint 配置添加加密和签名属性

在 Apache CXF 应用程序中使用任何 WS-Policy 策略前,您必须将策略功能添加到默认的 CXF 总线中。将 p:policies 元素添加到 CXF 总线,如以下 Blueprint 配置片段所示:

<beans xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:cxf="http://cxf.apache.org/core"
       xmlns:p="http://cxf.apache.org/policy" ... >

    <cxf:bus>
        <cxf:features>
            <p:policies/>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>
    ...
</beans>

以下示例演示了如何在指定服务类型的代理中添加签名和加密属性(该服务名称通过 jaxws:client 元素的 name 属性指定)。这些属性存储在 WSS4J 属性文件中,其中 alice.properties 包含签名密钥的属性,bob.properties 包含加密密钥的属性。

<beans ... >
    <jaxws:client name="{http://InteropBaseAddress/interop}MutualCertificate10SignEncrypt_IPingService"
                  createdFromAPI="true">
        <jaxws:properties>
            <entry key="ws-security.signature.properties" value="etc/alice.properties"/>
            <entry key="ws-security.encryption.properties" value="etc/bob.properties"/>
        </jaxws:properties>
    </jaxws:client>
    ...
</beans>

实际上,虽然属性名称没有明显,但每个密钥都用于客户端的两个不同的目的:

  • alice.properties (即 security.signature.properties指定的密钥)在客户端中使用,如下所示:

    • 用于签名传出消息。
    • 用于解密传入消息。
  • Bob.properties (即 security.encryption.properties)在客户端中使用,如下所示:

    • 用于加密传出消息。
    • 在传入信息中验证签名。

如果您发现这个混淆,请参阅 第 6.2.2 节 “基本签名和加密(cenario)” 以获得更详细的说明。

以下示例演示了如何在 JAX-WS 端点中添加签名和加密属性。属性文件 bob.properties 包含签名密钥和属性文件 alice.properties 的属性,包含加密密钥的属性(这是客户端配置不良)。

<beans ... >
    <jaxws:endpoint
       name="{http://InteropBaseAddress/interop}MutualCertificate10SignEncrypt_IPingService"
       id="MutualCertificate10SignEncrypt"
       address="http://localhost:9002/MutualCertificate10SignEncrypt"
       serviceName="interop:PingService10"
       endpointName="interop:MutualCertificate10SignEncrypt_IPingService"
       implementor="interop.server.MutualCertificate10SignEncrypt">

        <jaxws:properties>
            <entry key="security.signature.properties" value="etc/bob.properties"/>
            <entry key="security.encryption.properties" value="etc/alice.properties"/>
        </jaxws:properties>

    </jaxws:endpoint>
    ...
</beans>

每个密钥都用于服务器端的两个不同目的:

  • Bob.properties (即 security.signature.properties指定的密钥)在服务器端使用,如下所示:

    • 用于签名传出消息。
    • 用于解密传入消息。
  • alice.properties (即 security.encryption.properties)在服务器端使用,如下所示:

    • 用于加密传出消息。
    • 在传入信息中验证签名。

定义 WSS4J 属性文件

Apache CXF 使用 WSS4J 属性文件加载加密和签名所需的公钥和私钥。表 6.2 “WSS4J 密钥存储属性” 描述您可以在这些文件中设置的属性。

表 6.2. WSS4J 密钥存储属性

属性描述

org.apache.ws.security. crypto.provider

指定 Crypto 接口的实现(请参阅 “WSS4J Crypto 接口”一节)。通常,您可以指定 Crypto 的默认 WSS4J 实施,即org.apache.ws.security.components.crypto.Merlin

此表中的其余属性特定于 Crypto接口的 Merlin 实施

org.apache.ws.security. crypto.merlin.keystore.provider

(可选) 要使用的 JSSE 密钥存储提供程序的名称。默认密钥存储提供程序是 Bouncy Castle。您可以通过将此属性设置为 SunJSSE,将提供程序切换到 Sun 的 JSSE 密钥存储提供程序。

org.apache.ws.security. crypto.merlin.keystore.type

Bouncy Castle 密钥存储提供程序支持以下密钥存储: JKSPKCS12。此外,Boocy Castle 支持以下专有密钥存储类型:BKS 和 UBER。

org.apache.ws.security. crypto.merlin.keystore.file

指定要加载的密钥存储文件的位置,其位置相对于 Classpath。

org.apache.ws.security. crypto.merlin.keystore.alias

(可选) 如果密钥存储类型为 JKS (Java 密钥存储),您可以通过指定其别名从密钥存储中选择特定的密钥。如果密钥存储仅包含一个密钥,则不需要指定别名。

org.apache.ws.security. crypto.merlin.keystore.password

此属性指定的密码用于两个目的: 解锁密钥存储(密钥存储密码)并解密存储在密钥存储中的私钥(私钥密码)。因此,密钥存储密码必须与私钥密码相同。

例如,etc/alice.properties 文件包含用于加载 PKCS#12 文件 certs/alice.pfx 的属性设置,如下所示:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin

org.apache.ws.security.crypto.merlin.keystore.type=PKCS12
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.file=certs/alice.pfx

etc/bob.properties 文件包含用于加载 PKCS#12 文件 certs/bob.pfx 的属性设置,如下所示:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin

org.apache.ws.security.crypto.merlin.keystore.password=password

# for some reason, bouncycastle has issues with bob.pfx
org.apache.ws.security.crypto.merlin.keystore.provider=SunJSSE
org.apache.ws.security.crypto.merlin.keystore.type=PKCS12
org.apache.ws.security.crypto.merlin.keystore.file=certs/bob.pfx

编程加密密钥和签名密钥

加载加密密钥和签名密钥的替代方法是使用 表 6.3 “指定 Crypto 对象的属性” 中显示的属性来指定加载相关键的 Crypto 对象。这要求您自己提供 WSS4J Crypto 接口的实施,即 org.apache.ws.security.components.crypto.Crypto

表 6.3. 指定 Crypto 对象的属性

属性描述

security.signature.crypto

指定负责加载用于签名和解密消息的密钥的 Crypto 对象实例。

security.encryption.crypto

指定 Crypto 对象的实例,它负责加载用于加密消息和验证签名的密钥。

WSS4J Crypto 接口

例 6.7 “WSS4J Crypto 接口” 显示您可以实现的 Crypto 接口的定义(如果您想要按编程提供加密密钥和签名密钥)。如需更多信息,请参阅 WSS4J 主页

例 6.7. WSS4J Crypto 接口

// Java
package org.apache.ws.security.components.crypto;

import org.apache.ws.security.WSSecurityException;

import java.io.InputStream;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public interface Crypto {
    X509Certificate loadCertificate(InputStream in)
    throws WSSecurityException;

    X509Certificate[] getX509Certificates(byte[] data, boolean reverse)
    throws WSSecurityException;

    byte[] getCertificateData(boolean reverse, X509Certificate[] certs)
    throws WSSecurityException;

    public PrivateKey getPrivateKey(String alias, String password)
    throws Exception;

    public X509Certificate[] getCertificates(String alias)
    throws WSSecurityException;

    public String getAliasForX509Cert(Certificate cert)
    throws WSSecurityException;

    public String getAliasForX509Cert(String issuer)
    throws WSSecurityException;

    public String getAliasForX509Cert(String issuer, BigInteger serialNumber)
    throws WSSecurityException;

    public String getAliasForX509Cert(byte[] skiBytes)
    throws WSSecurityException;

    public String getDefaultX509Alias();

    public byte[] getSKIBytesFromCert(X509Certificate cert)
    throws WSSecurityException;

    public String getAliasForX509CertThumb(byte[] thumb)
    throws WSSecurityException;

    public KeyStore getKeyStore();

    public CertificateFactory getCertificateFactory()
    throws WSSecurityException;

    public boolean validateCertPath(X509Certificate[] certs)
    throws WSSecurityException;

    public String[] getAliasesForDN(String subjectDN)
    throws WSSecurityException;
}