使用.p12证书签名XML时出现PrivateKeyEntry空指针异常求助
解决XML签名时的NullPointerException问题
错误信息
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.security.KeyStore$PrivateKeyEntry.getCertificate()" because "keyEntry" is null
at xmlCreateSignature/xmlCreateSignature.xmlSignature.main(xmlSignature.java:38)
错误发生在第38行代码:X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
核心原因是keyEntry为null,即从PKCS12证书库中获取私钥条目失败。
原代码
package xmlCreateSignature; import java.io.*; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Collections; import java.util.List; import javax.xml.XMLConstants; import javax.xml.crypto.*; import javax.xml.crypto.dom.*; import javax.xml.crypto.dsig.*; import javax.xml.crypto.dsig.dom.*; import javax.xml.crypto.dsig.keyinfo.*; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.security.cert.X509Certificate; import java.util.Base64; public class xmlSignature { public static void main(String[] args) throws Exception { System.setProperty("com.sun.org.apache.xml.internal.security.ignoreLineBreaks", "true"); // Load the XML document DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(new File("./certDir/request.xml")); // Load the certificate KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("./certDir/4300648_identity.p12"), "DAL00MATIAN".toCharArray()); KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry((String) ks.aliases().nextElement(), new KeyStore.PasswordProtection("DAL00MATIAN".toCharArray())); X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); // Create the XML signature DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement()); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA256, null), Collections.singletonList(ref)); KeyInfoFactory kif = fac.getKeyInfoFactory(); X509Data x509d = kif.newX509Data(Collections.singletonList(cert)); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509d)); XMLSignature signature = fac.newXMLSignature(si, ki); // Sign the XML document signature.sign(dsc); SignedInfo signedInfo = signature.getSignedInfo(); // Get the references from the signed info List<Reference> references = signedInfo.getReferences(); // Process each reference and encode the digestValue to Base64 for (Reference reference : references) { // Get the digestValue as a byte array byte[] digestValue = reference.getDigestValue(); // Encode the digestValue to Base64 String base64DigestValue = Base64.getEncoder().encodeToString(digestValue); // Output the Base64-encoded digestValue System.out.println("Base64-encoded DigestValue: " + base64DigestValue); } // Save the signed XML document TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc), new StreamResult(new File("./certDir/request_response.xml"))); } }
解决方法
1. 修复别名获取逻辑
原代码直接调用ks.aliases().nextElement()获取别名,未验证该别名是否对应有效的私钥条目。修改为遍历并筛选有效密钥别名:
// 替换原有的keyEntry获取代码 KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("./certDir/4300648_identity.p12"), "DAL00MATIAN".toCharArray()); // 遍历别名,找到有效的私钥条目 Enumeration<String> aliases = ks.aliases(); String validAlias = null; while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); // 确认该别名对应私钥条目 if (ks.isKeyEntry(alias)) { validAlias = alias; break; } } if (validAlias == null) { throw new RuntimeException("PKCS12证书库中未找到有效的私钥条目"); } // 获取私钥条目 KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(validAlias, new KeyStore.PasswordProtection("DAL00MATIAN".toCharArray())); // 添加空指针检查 if (keyEntry == null) { throw new RuntimeException("无法获取私钥条目,请验证别名和密码是否正确"); } X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
2. 验证证书文件和密码
- 确认
./certDir/4300648_identity.p12文件路径正确,文件未损坏。 - 确认加载证书库的密码和获取私钥条目的密码一致(当前代码使用同一密码,需确认是否与证书设置匹配)。
3. 完整修正后的代码
package xmlCreateSignature; import java.io.*; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.Collections; import java.util.List; import javax.xml.XMLConstants; import javax.xml.crypto.*; import javax.xml.crypto.dom.*; import javax.xml.crypto.dsig.*; import javax.xml.crypto.dsig.dom.*; import javax.xml.crypto.dsig.keyinfo.*; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.security.cert.X509Certificate; import java.util.Base64; public class xmlSignature { public static void main(String[] args) throws Exception { System.setProperty("com.sun.org.apache.xml.internal.security.ignoreLineBreaks", "true"); // Load the XML document DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(new File("./certDir/request.xml")); // Load the certificate KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(new FileInputStream("./certDir/4300648_identity.p12"), "DAL00MATIAN".toCharArray()); // 遍历别名,找到有效的私钥条目 Enumeration<String> aliases = ks.aliases(); String validAlias = null; while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (ks.isKeyEntry(alias)) { validAlias = alias; break; } } if (validAlias == null) { throw new RuntimeException("PKCS12证书库中未找到有效的私钥条目"); } KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(validAlias, new KeyStore.PasswordProtection("DAL00MATIAN".toCharArray())); if (keyEntry == null) { throw new RuntimeException("无法获取私钥条目,请验证别名和密码是否正确"); } X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); // Create the XML signature DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement()); XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA256, null), Collections.singletonList(ref)); KeyInfoFactory kif = fac.getKeyInfoFactory(); X509Data x509d = kif.newX509Data(Collections.singletonList(cert)); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509d)); XMLSignature signature = fac.newXMLSignature(si, ki); // Sign the XML document signature.sign(dsc); SignedInfo signedInfo = signature.getSignedInfo(); // Get the references from the signed info List<Reference> references = signedInfo.getReferences(); // Process each reference and encode the digestValue to Base64 for (Reference reference : references) { // Get the digestValue as a byte array byte[] digestValue = reference.getDigestValue(); // Encode the digestValue to Base64 String base64DigestValue = Base64.getEncoder().encodeToString(digestValue); // Output the Base64-encoded digestValue System.out.println("Base64-encoded DigestValue: " + base64DigestValue); } // Save the signed XML document TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc), new StreamResult(new File("./certDir/request_response.xml"))); } }
内容的提问来源于stack exchange,提问作者John Malko
相关产品推荐
相关产品推荐

