【问题标题】:Java NPE while validating my own XML signature验证我自己的 XML 签名时的 Java NPE
【发布时间】:2017-03-01 11:02:31
【问题描述】:

我有一个签名的 XML 请求,由于签名无效而被第 3 方拒绝。因此,我编写了自己的签名验证代码,看看有什么问题。但是,在验证我刚刚创建的 XML 签名时,我得到了 NPE。这是 XML 的样子(我删除了不相关的部分):

<?xml version="1.0" encoding="UTF-8"?>
<envelope xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="some_third_party.xsd">
    <header>...</header>
    <body>...</body>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="MySignature">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <Reference URI="">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>AaV+ejxBF8GjJvIZA9Bonw81Z1Y=</DigestValue>
            </Reference>
            <Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#SignatureProperties">
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>qcofYVnQ/n7sxKJPT5rG0+UYbjg=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>XXX</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>XXX</X509Certificate>
            </X509Data>
        </KeyInfo>
        <Object Id="SignatureProperties">
            <SignatureProperties xmlns="">
                <SignatureProperty Id="TimeStamp" Target="#MySignature">
                    <TimeStamp>
                        <Date>2017-03-01</Date>
                        <Time>09:06:36.779+01:00</Time>
                    </TimeStamp>
                </SignatureProperty>
            </SignatureProperties>
        </Object>
    </Signature>
</envelope>

当我尝试验证这个签名时,我在注释行上得到了 NPE(所以它实际上发生在解组签名时,在实际验证之前):

// Omitted: extract the X509 Certificate from the document
DOMValidateContext valContext = new DOMValidateContext(cert.getPublicKey(), signature);
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
XMLSignature xmlSignature;
try {
    // Null pointer exception here!
    xmlSignature = factory.unmarshalXMLSignature(valContext);
} catch (MarshalException e) {
    // Handle exception
}

为了完整起见,以下是我创建签名的方式:

try {
    XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");

    Reference ref = xmlSignatureFactory.newReference("",
            xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
            Collections.singletonList(xmlSignatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
            null,
            null);

    Reference signatureRef = xmlSignatureFactory.newReference("#SignatureProperties",
            xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null),
            null,
            "http://www.w3.org/2000/09/xmldsig#SignatureProperties",
            null);

    SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(xmlSignatureFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
            xmlSignatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
            Arrays.asList(ref, signatureRef));

    XMLObject xmlObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(new DOMStructure(timestamp)),
            "SignatureProperties", null, null);

    KeyInfoFactory keyInfoFactory = xmlSignatureFactory.getKeyInfoFactory();
    List<Object> x509Content = new ArrayList<>();
    x509Content.add(certificate);
    X509Data xd = keyInfoFactory.newX509Data(x509Content);
    KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(xd));

    XMLSignature xmlSignature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo,
            Collections.singletonList(xmlObject), SIGNATURE_ID, null);
    DOMSignContext signContext = new DOMSignContext(privateKey, document.getDocumentElement());
    xmlSignature.sign(signContext);
} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
    // Handle exception
}

知道我在这里做错了什么吗?

编辑:添加堆栈跟踪以显示 NPE 的确切抛出位置:

java.lang.NullPointerException: null
    at org.jcp.xml.dsig.internal.dom.DOMXMLObject.<init>(DOMXMLObject.java:120)
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.<init>(DOMXMLSignature.java:171)
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshal(DOMXMLSignatureFactory.java:193)
    at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshalXMLSignature(DOMXMLSignatureFactory.java:150)

编辑 2:我还应该提到 SignedValue 和 X509Certificate 内容在创建签名后都有空格,这对我来说看起来很奇怪。例如

<X509Certificate>MIIG8DCCBdigAwIBAgIUJZSmBORuGuXyx48f04sNGHT+RhwwDQYJKoZIhvcNAQELBQAwWzELMAkG
    A1UEBhMCQ0gxEzARBgNVBAoTClBvc3QgQ0ggQUcxDTALBgNVBAsTBFBST0QxKDAmBgNVBAMTH1BL
    SSBTd2lzc1Bvc3QgTWFjaGluZSBBRVAgQ0EgRzMwHhcNMTcwMTI2MTIzMTQ0WhcNMjAwMTI2MTIz
    MTQ0WjCBsTELMAkGA1UEBhMCQ0gxCzAJBgNVBAgTAkZSMSAwHgYDVQQKExdEaWUgU2Nod2VpemVy
    ...

【问题讨论】:

  • 你有堆栈跟踪吗?
  • 是的,我现在添加了堆栈跟踪。
  • 你确定signature 不为空吗?
  • @RC。整个 元素对我来说看起来不错,除了 内容中都有空格(请参阅我的第二次编辑)。我希望这些值打印在一行中,没有任何空格。我不确定为什么会发生这种情况,这可能是问题所在。
  • 我不说你的xml我说的是signature in new DOMValidateContext(cert.getPublicKey(), signature);

标签: java xml xml-signature


【解决方案1】:

经过一些调试,我发现了问题所在。 DOMXMLObject 尝试获取 SignatureProperties 节点的本地名称,该名称返回 null。我稍微修改了创建该元素的方式,现在它工作正常。

我正在添加那段代码,以防以后对其他人有用:

private Element createTimestamp(Document doc) {
    // Use createElementNS instead of createElement, otherwise you will get the aforementioned NPE
    Element signatureProperties = doc.createElementNS("", "SignatureProperties");
    Element signatureProperty = signatureProperties.getOwnerDocument().createElementNS("","SignatureProperty");
    signatureProperty.setAttribute("Target", "#" + SIGNATURE_ID);
    signatureProperty.setAttribute("Id", "TimeStamp");
    Element timeStamp = signatureProperty.getOwnerDocument().createElementNS("", "TimeStamp");

    ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());
    Element date = timeStamp.getOwnerDocument().createElementNS("", "Date");
    date.setTextContent(now.toLocalDate().toString());
    Element time = timeStamp.getOwnerDocument().createElementNS("", "Time");
    time.setTextContent(now.toLocalTime().toString() + now.getOffset().toString());

    timeStamp.appendChild(date);
    timeStamp.appendChild(time);
    signatureProperty.appendChild(timeStamp);
    signatureProperties.appendChild(signatureProperty);
    return signatureProperties;
}

然后在这一行中使用此方法的结果:

XMLObject xmlObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(new DOMStructure(createTimestamp(doc))),
                "SignatureProperties", null, null);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 2022-08-18
    相关资源
    最近更新 更多