证书密钥使用和密码加密模式



我正在尝试使用cxf和sprint加密传出的SOAP标头。由于我与spring的配置,我最终为我的客户使用outInterceptor:

'

 <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参数初始化Cipher,最后我得到了同样的例外。下面是具体的片段:

        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(即Cipher.PRIVATE_KEY),而不适用于
KEY_Encipher(例如
Cipher.ENCRYPT_MODE

因此,我的问题是,是否有可能没有为该证书正确定义KeyUsage。我不是密码学专家,但我读到的一些留言板建议,如果keyUsage是关键的,它可能需要使用数据加密以及…

谢谢你的帮助!

仔细阅读源代码,有两个条件会引发该异常,其中一个是永远不会发生的错误,另一个是检查有问题的证书是否支持有问题的操作。

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");
    }
}

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

代码似乎没有检查像PRIVATE_KEY这样总是无效的opmode,只是检查像ENCRYPT_MODE这样有时无效的opmode,这可能就是为什么它对测试代码很好的原因。

最近遇到了这个问题。只要创建正确,就可以使用公钥证书进行加密。证书应具有密钥使用对象ID(ObjectId:2.5.29.15 Criticality=true),设置为"b0"(10110000),基本上启用了数据加密位。否则,您将遇到错误的密钥使用错误。任何CA颁发的证书都会将密钥使用关键性设置为true。自签名证书(如在dev/shadbox环境中)不会将关键性设置为true,因此这些证书可以工作,当然前提是您设置为信任它们。我尝试使用服务器上的公钥证书,但遇到了这个错误。然后,我们的IT部门获得了适用于数据加密的正确公钥证书,它开始为我工作。

最新更新