使用较新版本的Bouncy Castle时,接收器无法验证SMIME

时间:2014-08-29 06:14:53

标签: java encryption smime

我正在使用BC加密和签署SMIME消息以与AS2一起使用。我们的代码可以使用绝对古老的充气城堡bcmail-1.4:125。升级到任何更新的东西会导致消息的接收者(不是太古老的Cyclone服务器)无法验证消息。 (例如 maven中最早的v 也会导致这种情况。这些是没有API更改的版本(例如1.38)。

由于我们使用JDK 1.7(和1.8),我一直在尝试将其更新为更新版本的BC,java-mail等。我已将所有充气城堡升级为bcmail-jdk15on:1.51和{ {1}}以及java邮件,并按照bcprov-jdk15on:1.51包中的示例进行操作。但是,我仍然从Cyclone说bcmail收到错误。

我相当肯定错误在于我如何签名。当我禁用签名并仅使用加密时,它会正确处理。此外,我可以正确地从远程服务器接收签名的响应并验证签名,这是我如何获取错误消息(来自MimeMultiPart上的内容处置)。

  • 证书由openssl / self signed / etc创建,存储在pkcs12文件中
  • 无限强度政策已到位
  • integrity-check-failedsenderKey
  • BCRSAPrivateCrtKey
    • senderCert

失败:当前代码为此,使用org.bouncycastle.jcajce.provider.asymmetric.x509.X509CertificateObject&等等

bcmail-jdk15on:1.51

之前正在使用的代码看起来像这样并使用SMIMESignedGenerator gen = new SMIMESignedGenerator(); gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder() .setProvider("BC") .build("SHA1withRSA", senderKey, senderCert)); // gen.addCertificates(new JcaCertStore(list(senderCert))); old v. doesn't add certs MimeMultipart smime = gen.generate(part); // MimeBodyPart passed in to function MimeBodyPart tmpBody = new MimeBodyPart(); tmpBody.setContent(signedData); tmpBody.setHeader("Content-Type", signedData.getContentType() 。在解密时,升级到1.3x也会导致另一端失败(无论我运行的是哪个jdk,1.6 - 1.8)

bcmail-1.4:1.25

常用设置代码

MimeBodyPart body = new MimeBodyPart();
body.setDataHandler(new DataHandler(new ByteArrayDataSource(bytes[], contentType, null);));
SMIMESignedGenerator sGen = new SMIMESignedGenerator();
// SHA1 resolves to "1.3.14.3.2.26", FWIW
sGen.addSigner(senderKey, senderCert, getBouncyCastleAlgorithmId("SHA1"));
MimeMultipart signedData = sGen.generate(part, "BC");
// this is then encrypted & streamed, no issues there

我觉得它与我如何添加(或操纵)byte[] data = Files.readAllBytes(filePath); MimeBodyPart part = new MimeBodyPart(); ByteArrayDataSource dataSource = new ByteArrayDataSource(data, "application/EDIFACT", null); part.setDataHandler(new DataHandler(dataSource)); part.setHeader("Content-Transfer-Encoding", "8bit"); part.setHeader("Content-Type", "application/EDIFACT"); 有关,这是本地应用程序的X509。

更新

我通过删除证书使新代码更符合旧代码:

  • 它不再包含已签名邮件中的证书。旧版没有
  • 整个mime多部分内容现在完全与之前相同的长度(1095字节)
  • 格式(标题等)现在完全相同
  • 签名部分现在几乎相同。但是,有一部分似乎根据时间(???)而变化,并且每次都会改变。我无法通过openssl验证此消息,不知道为什么。

这是样本输出,FWIW。 senderCert中的文字是唯一可以改变的部分。

[]

1 个答案:

答案 0 :(得分:2)

经过大量的调试和转储文件等等,我证明了它与摘要计算有关。在签名正文部分中的特定位置是内容MIC(摘要的base64)。不知何故,这个价值与另一方的价值不符......

有了这个,还有更多的时间与谷歌,我终于出现了more information on sourceforge确认这一点。有用,因为它提到我的特定版本的BC。引用:

  

问题是BC> = 1.27将“规范化”所有消息   不与content-transfer-encoding二进制文件一起发送。

     

这是什么意思?

     

在S / MIME rfc中,它表示所有消息都应转换为   在计算MIC之前的“规范”形式。 “规范”的形式   文本消息是EOL由CR,LF表示。 rfc是   沉默于其他内容类型的规范形式是什么。许多   S / MIME实现(例如openssl,1.27之后的Bouncy Castle)   错误地假设所有消息的规范形式除外   那些使用content-transfer-encoding二进制文件发送的是每个LF   应该在CR之前。

     

因此,如果使用的BC 1.25发送包含裸LF字符的消息   如果消息收到,则MIC验证将失败   使用BC> = 1.27或openssl smime或许多其他S / MIME的应用程序   的实施方式。

     

应修复OpenAS2以使用content-transfer-encoding二进制文件。

只有在 MIME正文部分 上设置编码时,这才会起作用我通过执行JCA路由验证了相同的结果(在服务器上失败了)手动,轻量级路由,以及CMS路由。

通过这些信息,我对发送者做了一个简单的改变....

MimeBodyPart part = //.. make mime body part from file
part.setHeader("Content-Transfer-Encoding", "binary");

关于这一点的有趣之处在于,改变与SMIMESignedGenerator()有关的任何内容似乎都没有效果:

gen = SMIMESignedGenerator("binary");  // nothing, even though the docs say to set this

对于任何感兴趣的人,我的最终签名功能如下所示:

SMIMESignedGenerator gen = new SMIMESignedGenerator();
SignerInfoGenerator sigGen = new JcaSimpleSignerInfoGeneratorBuilder()
        .setProvider(BC)
        .build("SHA1withRSA", senderKey, senderCert);
gen.addSignerInfoGenerator(sigGen);
MimeMultipart smime = gen.generate(part);
MimeBodyPart tmpBody = new MimeBodyPart();
tmpBody.setContent(smime);
tmpBody.setHeader("Content-Type", smime.getContentType());
return tmpBody;

原始文件只有一行:

this is a test

签名的输入是:

Content-Type: application/EDIFACT
Content-Transfer-Encoding: binary

this is a test

调试信息:

data bytes:
436F6E74656E742D547970653A206170706C69636174696F6E2F454449464143540D0
A436F6E74656E742D5472616E736665722D456E636F64696E673A2062696E6172790D
0A0D0A74686973206973206120746573740A

digest mic: {
   "algorithmId":   "1.3.14.3.2.26"
   "digest bytes":  "CEC2C6614A481DFDF45C801FD6F2A51BC53D3FDF"
   "digest base64": "zsLGYUpIHf30XIAf1vKlG8U9P98="
}

这不会附加签名,或添加任何功能,并使用v1 x509证书。我现在可能会改变这些东西,因为这一切都在重新开始。

我真的希望所有这一切都更加透明......虽然我明白为什么,BC内部是间接的间接。内部仍然比旧版本更好。我不能说我没有找到很多例子,但是BC测试用例看起来并不是最好的(例如我找不到一个经过验证的预期的摘要值SMIME'ing。也许我错过了它)