我正在使用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上的内容处置)。
integrity-check-failed
是senderKey
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。
更新
我通过删除证书使新代码更符合旧代码:
这是样本输出,FWIW。 senderCert
中的文字是唯一可以改变的部分。
[]
答案 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。也许我错过了它)