How to Sign Just a part of XML File - Java XMLSignature - But was well-up error

Viewed 229

I'm just trying to digital sign a part of an XML.

The XML to sign is like this:

<Invoice>
    <DataInvoice Id="data">
        ----
    </DataInvoice>
    <DataSignature>
        <SignatureSeller Id="seller">
        </SignatureSeller>
    </DataInvoice>
</Invoice>

xml after signing

<Invoice>
    <DataInvoice Id="data">
        ----
    </DataInvoice>
    <DataSignature>
        <SignatureSeller Id="seller">
            <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
                <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="data">
                        <Transforms>
                            <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                        </Transforms>
                        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <DigestValue>49uyshWL+fnQ2UetAe2t3BNQqnA=</DigestValue>
                    </Reference>
                </SignedInfo>
                <SignatureValue>
                    VWI03lBKlE/wVT//uHME4qLyUs2PqxOgq0KBYaGYcR6z3QZdnXqOZClu9EVMT2V3RBA7hr+QQy2cCHVsdtb85B2gsNsRdxHPjj9KfLetTFx1lL8nlC6L5SA0x6k9Lh7xNBZTJl275IT4hnSnNe8q+9dWskgE/6We24DKBLMrOLg=
                </SignatureValue>
                <KeyInfo>
                    <X509Data>
                        <X509Certificate>
                            MIIEDzCCAvegAwIBAgIQVAT//rcDP7MW1nIgG4H6OjANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJWTjESMBAGA1UEBwwJSMOgIE7hu5lpMRYwFAYDVQQKEw1WaWV0dGVsIEdyb3VwMRMwEQYDVQQDEwpWaWV0dGVsLUNBMB4XDTIwMDYwODA5NDMyNFoXDTIxMDYwODA5NDMyNFowgYoxITAfBgkqhkiG9w0BCQEWEmh1b25nbnRAbWF0YmFvLmNvbTEeMBwGCgmSJomT8ixkAQEMDk1TVDowMzAyNzEyNTcxMSgwJgYDVQQDDB9Dw5RORyBUWSBD4buUIFBI4bqmTiBN4bquVCBCw4NPMQ4wDAYDVQQHDAVUUEhDTTELMAkGA1UEBhMCVk4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJQ3aZioAdDIU1rQOO5tN7ORCqAWDWkQvP24gqD8LzRhA1Ui27DcOukuTp2bG8zSB3vGUMoFxV8qOpkfpt4/YUFhrMR6fG3k7J4YAKhkI/Ear3m3cEHo/MKxKsMbWHriI2CrKbG7Ih51iafRyt/mLGI66fNfnIwAoSIeXvLXi5YDAgMBAAGjggEuMIIBKjA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnZpZXR0ZWwtY2Eudm4wHQYDVR0OBBYEFHQbrRodIeEnE0sMBLuNyp+lCsvhMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAU/stBFOldp9kyDeSyCFzxXOy2srUwgZIGA1UdHwSBijCBhzCBhKAuoCyGKmh0dHA6Ly9jcmwudmlldHRlbC1jYS52bi9WaWV0dGVsLUNBLXYzLmNybKJSpFAwTjETMBEGA1UEAwwKVmlldHRlbC1DQTEWMBQGA1UECgwNVmlldHRlbCBHcm91cDESMBAGA1UEBwwJSMOgIE7hu5lpMQswCQYDVQQGEwJWTjAOBgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQEFBQADggEBAJInz1BLmnJIfl8juAs+StPAl4a5bd9Gf4B6eksmYOBFLeUzc/B78LcO9B2z3fpOVcqOvsK9rCFMO81+TePa6KZODk4xnP2HjgpuiN+E/qdYucUSMQNNVH2BDa/BraK41H1ySVVuqxvQ5fAvkIfhgBuyt3RVRmBpWkRT1faJ1hh5o9sq3SBqTmqd+W5PmA4hOUHj/Rb4xcQF3hMywWIBnVXZAwJ+GTbF4T/XkFavxb54UObTuebaQ8deB4hIOMvM6SKagFofBVeurS7CELMQtHKBjVRndlzecK0zR6vzKDLBukL6W4K7s9u55A2563Vv5HhZJhQHnftlrmJ59bBUHx0=
                        </X509Certificate>
                    </X509Data>
                </KeyInfo>
                <Object xmlns="http://www.w3.org/2000/09/xmldsig#">
                    <SignatureProperties>
                        <SignatureProperty>
                            <SigningTime>2021-05-27T14:13:48</SigningTime>
                        </SignatureProperty>
                    </SignatureProperties>
                </Object>
            </Signature>
        </SignatureSeller>
    </DataInvoice>
</Invoice>

This is the code I'm using to try to sign it, but I need to sign only the part of XML and put the result inside this Id

public String xmlSign(String xml, String idData, String signBy) throws
        NoSuchAlgorithmException, InvalidAlgorithmParameterException, InterruptedException,
        UnrecoverableKeyException, KeyStoreException, SAXException, IOException, ParserConfigurationException,
        XPathExpressionException, MarshalException, XMLSignatureException
    {
        PublicKey publicKey = null;
        PrivateKey privateKey = null;
   
        if (!(cert instanceof Certificate)) {
            Map<String, Certificate> aliases = store.getAliases();
            for (Map.Entry<String, Certificate> item : aliases.entrySet()) {
                Certificate tmpCert = item.getValue();
                publicKey = tmpCert.getCertificate().getPublicKey();
                privateKey = (PrivateKey) store.getKeyStore().getKey(tmpCert.getAlias(), null);

                if (publicKey instanceof PublicKey && privateKey instanceof PrivateKey) {
                    cert = tmpCert;
                    break;
                }
            }
            
        } else {
            publicKey = cert.getCertificate().getPublicKey();
            privateKey = (PrivateKey) store.getKeyStore().getKey(cert.getAlias(), null);
        }
        
        if (publicKey == null || privateKey == null) {
            return null;
        }

        // Load factory
        XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();   
        
        // Load xml document
        Document document = this.importXML(this.ignoreLineBreak(xml));
        
        XMLObject xmlObject = factory.newXMLObject(Collections.singletonList(new DOMStructure(createTimestamp(document))), null, null, null);
        
        XPathExpression exprAssertion =  xpath.compile(String.format("//*[@Id='%s']", idData));
        Element assertionNode = (Element) exprAssertion.evaluate(document, XPathConstants.NODE);        
        assertionNode.setIdAttribute("Id", true);

    
        // Retreive Subject Node because the signature will be inserted before.
        XPathExpression exprAssertionSubject = xpath.compile(String.format("//*[@Id='%s']", "seller"));
        Node insertionNode = (Node) exprAssertionSubject.evaluate(document, XPathConstants.NODE);        

        DOMSignContext signContext = new DOMSignContext(privateKey, assertionNode, insertionNode);
        
        // Create transform
        List<Transform> transformList = new ArrayList<Transform>();
        Transform exc14nTranform = ((XMLSignatureFactory) factory).newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", (TransformParameterSpec) null);
        Transform envTransform = ((XMLSignatureFactory) factory).newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
        transformList.add(exc14nTranform);
        transformList.add(envTransform);
        
        // Create reference
        DigestMethod digestMethod = factory.newDigestMethod(DigestMethod.SHA1, null);
        Reference reference = factory.newReference("#" + idData, digestMethod, transformList, null, (signBy != null ? "#" + signBy : null));
    
        // Create key info
        KeyInfoFactory kif = ((XMLSignatureFactory) factory).getKeyInfoFactory();
        List<X509Certificate> x509Content = new ArrayList<X509Certificate>();
        x509Content.add(cert.getCertificate());
        X509Data xd = kif.newX509Data(x509Content);
        KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(xd));
        
        // Create signature info
        SignedInfo signInfo = ((XMLSignatureFactory) factory).newSignedInfo(
            ((XMLSignatureFactory) factory).newCanonicalizationMethod(
                    CanonicalizationMethod.INCLUSIVE,
                    (C14NMethodParameterSpec) null
                ),
            ((XMLSignatureFactory) factory).newSignatureMethod(
                    SignatureMethod.RSA_SHA1,
                    null
                ),
            Collections.singletonList(reference)
        );
        
        
        XMLSignature signature = factory.newXMLSignature(signInfo, keyInfo, Collections.singletonList(xmlObject), null, null);
        
        signature.sign(signContext);
        
        return this.ignoreLineBreak(
            this.exportXML(new DOMSource(document))
        );
    }

It can't work and shows error:

NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist. com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(Unknown Source)

Any help will be very appreciated. Regards

0 Answers
Related