2012-07-15 294 views
0

我想使用cxf和sprint加密传出的SOAP头。正如我configutaion的春天有个结果,我最终使用outInterceptor为我的客户:证书KeyUsage和密码加密模式

'

<bean id="encryptOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"> 

    <constructor-arg> 
    <map> 
     <entry key="action" value="UsernameToken Timestamp Encrypt" /> 
     <entry key="passwordCallbackRef" value-ref="passwordCallback" /> 
     <entry key="user" value="mykey" /> 
     <entry key="encryptionPropFile" value="keystore.properties" /> 

    </map> 
    </constructor-arg> 
    </bean> 

`

,并为这样的结果是最终调用

`org.apache.ws.security.message.WSSecEncryptedKey.prepareInternal()` 

方法,我通过调试器到其源:

try { 
     **cipher.init(Cipher.ENCRYPT_MODE, remoteCert);** 
    } catch (InvalidKeyException e) { 
     throw new WSSecurityException(
      WSSecurityException.FAILED_ENCRYPTION, null, null, e 
     ); 
    } 

并在那一点上抛出:“无效的密钥用法”异常。

我最后写一个测试Java类,在那里我阅读手动证书,然后试图用Cipher.ENCRYPT_MODE参数初始化密码, 和我最终得到相同exception.here特定片段:

 InputStream inStream = new FileInputStream("our_cert.cer"); 
     CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
     X509Certificate cert =(X509Certificate)cf.generateCertificate(inStream); 
     inStream.close(); 

     // Read the public key from certificate file 
     RSAPublicKey pubkey = (RSAPublicKey) cert.getPublicKey(); 
     cipher.init(Cipher. ENCRYPT_MODE, certif); // it breaks at this point 

我换成最后一行与

cipher.init(Cipher. PRIVATE_KEY, certif); 

,并通过罚款。

我不认为这是正确的密钥用法,但我认为ENCRYPT_MODE也应该工作。

通过观察证书密钥使用部分我注意到它定义为关键用法:

ObjectId: 2.5.29.15 Criticality=true 
KeyUsage [ 
    DigitalSignature 
    Key_Encipherment 
] 

并且有它没有其他的关键部分。

从它的行为似乎的方式,Cipher.init(..)只为的DigitalSignature(即密码。PRIVATE_KEY),但不是Key_Encipherment工程(即密码。ENCRYPT_MODE)。

所以我的问题是,有可能是KeyUsage没有正确定义该证书。 我不是专家密码学,但有些留言板我读认为,如果执行keyUsage是至关重要的,它可能需要使用 DATA_ENCIPHERMENT,以及...

感谢您对您的帮助!

回答

1

通过source code的嗅探,有两种情况会引发该异常,其中一种是从未发生的错误,另一种是检查以查看相关证书是否支持有问题的操作。

if (critSet != null && !critSet.isEmpty() 
    && critSet.contains(KEY_USAGE_EXTENSION_OID)) { 
    boolean[] keyUsageInfo = cert.getKeyUsage(); 
    // keyUsageInfo[2] is for keyEncipherment; 
    // keyUsageInfo[3] is for dataEncipherment. 
    if ((keyUsageInfo != null) && 
     (((opmode == Cipher.ENCRYPT_MODE) && 
     (keyUsageInfo.length > 3) && 
     (keyUsageInfo[3] == false)) || 
     ((opmode == Cipher.WRAP_MODE) && 
     (keyUsageInfo.length > 2) && 
     (keyUsageInfo[2] == false)))) { 
     throw new InvalidKeyException("Wrong key usage"); 
    } 
} 

这表明您使用的是无效的加密证书。也许你试图使用公钥证书进行加密?

它看起来像代码不检查opmode总是无效像PRIVATE_KEY,只是那些有时无效像ENCRYPT_MODE,这可能是为什么你的测试代码很好。

+0

是,通过调试Cipher.init()我没有看到,第一个条件得到满足,即: '(!keyUsageInfo = NULL)&& (((OPMODE == Cipher.ENCRYPT_MODE)&& (keyUsageInfo.length > 3)&& (keyUsageInfo [3] == FALSE)' 的KeyUsage证书中应该支持加密,因为它具有本节: '的ObjectId:2.5.29.15临界=真 的KeyUsage [ 的DigitalSignature Key_Encipherment ]' 还是我误读了? 非常感谢! – user1526437 2012-07-17 02:34:43

+0

我相信你正在寻找“数据加密”而不是“密钥加密”。我想这将是Cipher.WRAP_MODE。 – tbroberg 2012-07-17 07:59:40

1

最近跑进去了。只要正确创建了公钥证书,就可以使用公钥证书进行加密。该证书应该具有密钥使用对象ID(ObjectId:2.5.29.15 Criticality = true),设置为'b0'(10110000),基本上启用数据加密位。否则,您将遇到错误密钥使用错误。任何CA颁发的证书都将使密钥使用严重性变为真实。自签名证书(如在开发/沙箱环境中)不会将该重要性设置为true,因此这些将起作用,当然您会设置为信任它们。 我尝试使用服务器的公钥证书,并正在努力解决此错误。然后我们的IT部门拿回了适用于Data Encipherment的正确公钥证书,并开始为我工作。