You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:37:03