我正在签署 xml 文档的一部分,但生成的签名和证书中包含不需要的空格。例如,这是签名:
<SignatureValue>QcjPfiZcmqE8aMNH5AKVk+oFBYQ4LynV3a5YlJIxuf0y22QQ0NA2BTkRriI85dd/6Qcezf5xFguJ
V+Mlk44c0uZD7TE+NlsFz3q1vtHHPi/9ygc2kJgQeSzxiCR2AHCONN3UN89RjidIqnN1qtKrBhc+
GNeEGhjqgV7DHvzK7tHVkC6c1EevsOV5bH2Gu0X5JsGwOtSHWe6eyOXue0TW7XWrqOLmOusWYhRR
ONJFoa49LQ4WV/RP498rp2TJ0bNE36PMWD6sMh52ERTj6NhngIl2cGjbbwzYteDN/ujo5bHmosmC
dVKBmgaw2YAICJy4BROyK7AmZI5BxKoZ6CY1Tw==</SignatureValue>
这是证书的一部分:
<X509Certificate>MIIFtTCCBJ2gAwIBAgIQBsK927DS8wePBQjvzVX9BjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMR0w
GwYDVQQDExRSYXBpZFNTTCBSU0EgQ0EgMjAxODAeFw0xOTA2MDcwMDAwMDBaFw0yMDA2MDYxMjAw
注意两者都有“$#13;”附加?
这是执行签名的代码:
private void buildSignatureBlock5(String privateKeyPath, String publicKeyPath) {
// Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
// Create a Reference to the enveloped document (in this case,
// you are signing just the element with Id="Body", so a URI of "#Body" signifies
// that, and also specify the SHA1 digest algorithm and the ENVELOPED Transform.
Reference ref = null;
try {
ref = fac.newReference
("#Body", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform
(Transform.ENVELOPED, (TransformParameterSpec) null)),
null, null);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Create the SignedInfo.
SignedInfo si = null;
try {
si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Load the KeyStore and get the signing key and certificate.
KeyStore ks = null;
try {
ks = KeyStore.getInstance("JKS");
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ks.load(new FileInputStream(storage_path +"/keys/myproject.jks"), "changeit".toCharArray());
} catch (NoSuchAlgorithmException | CertificateException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
KeyStore.PrivateKeyEntry keyEntry = null;
try {
keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry
("1", new KeyStore.PasswordProtection("changeit".toCharArray()));
} catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
String issuerName = cert.getIssuerX500Principal().getName();
BigInteger serialNumber = cert.getSerialNumber();
X509IssuerSerial issuer = kif.newX509IssuerSerial(issuerName, serialNumber);
x509Content.add(issuer);
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// Create a DOMSignContext and specify the RSA PrivateKey and location of the resulting XMLSignature's parent element.
Element envHeaderSig = (Element) document.getElementsByTagName("SOAP-SEC:Signature").item(0);
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), envHeaderSig);
// Create the XMLSignature, but don't sign it yet.
XMLSignature signature = fac.newXMLSignature(si, ki);
try {
signature.sign(dsc); //ResourceResolverException: Cannot resolve element with ID Body
} catch (MarshalException | XMLSignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
我已经尝试过这里建议的解决方案:
How to produce XML signature with no whitespaces and line-breaks in Java?
但是没有任何效果。有任何想法吗?
我有一个由 PHP 创建的示例签名 block ,我知道它可以工作,但没有空格。我试图让我的 java 输出看起来就像它一样。
最佳答案
我找不到一种“正确的方式”来做到这一点,因此编写了一个 hack 来在生成后对其进行修改。这是:
//hack to remove unwanted CR at the end of each line in SignatureValue and X509Certificate
private void removeWhitespaceFromSignature() {
Element sig = (Element) document.getElementsByTagName("SignatureValue").item(0);
String sigValue = sig.getTextContent().replaceAll("\r\n", "");
sig.setTextContent(sigValue);
Element cert = (Element) document.getElementsByTagName("X509Certificate").item(0);
String certValue = cert.getTextContent().replaceAll("\r\n", "");
cert.setTextContent(certValue);
}
不得不诉诸于此似乎很荒谬,但几个小时的搜索没有产生其他替代方案。
关于java - 如何防止在java xml签名和证书中添加空格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59218272/