Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XmlDsigEnvelopedSignatureTransform shouldn't remove all found Signatures #49

Open
halmos opened this issue Oct 17, 2020 · 3 comments
Open
Assignees

Comments

@halmos
Copy link

halmos commented Oct 17, 2020

Hello,

We are using xmldsig for epub signatures.xml signature generation. In the epub spec, the signatures file may contain multiple Signature elements. It may also contain a reference to the signatures.xml file itself which requires an enveloped signature to avoid recursion. See https://www.w3.org/publishing/epub32/epub-ocf.html#sec-container-metainf-signatures.xml

My understanding according to https://www.w3.org/TR/xmldsig-core1/#sec-EnvelopedSignature is that the envelope should only apply to the direct ancestor signature to which the enveloped transform has been applied (please correct me if I am misunderstanding). In other words, sibling Signature nodes should be left intact.

However, the XmlDsigEnvelopedSignatureTransform method removes all first-level ancestor Signature elements from the XML being transformed.

It's not clear to me how one would decern which Signature is the ancestor of the transform in this example, but I think the simplest approach would be to allow the passing of an ID to XmlDsigEnvelopedSignatureTransform.GetOutput() in order to scope the transform to a particular Signature.

e.g.

 public GetOutput(id): any {
        if (!this.innerXml) {
            throw new XmlError(XE.PARAM_REQUIRED, "innerXml");
        }

        let child = this.innerXml.firstChild;
        const signatures: Element[] = [];
        while (child) {
            if (isElement(child)
                && child.localName === XmlSignature.ElementNames.Signature
                && child.namespaceURI === XmlSignature.NamespaceURI) {
                if(id === undefined || id === child.id) {
                   signatures.push(child);
               }
            }
            child = child.nextSibling;
        }
        for (const signature of signatures) {
            signature.parentNode?.removeChild(signature);
        }
        return this.innerXml;
    }

This may be related to issue #37

And thank you!

@microshine
Copy link
Collaborator

@halmos Do you have any XML signed file (as an example)? And point which signature it must to verify. I'd debug that case and fix it

@halmos
Copy link
Author

halmos commented Oct 18, 2020

Hi @microshine - thanks. An official signatures.xml test fixture from idpf doesn't seem to be available, unfortunately. I'll search around some more for a validated example, but if nothing turns up, I will generate a test fixture for you myself.

@halmos
Copy link
Author

halmos commented Oct 18, 2020

@microshine - In the meantime, I've provided an unsigned example below so you can have a more clear idea of the issue.

In the case of a signatures.xml signature in which the signatures.xml file itself (or any signature which contains a reference to the file in which the signature is contained) must be hashed and added to a signature manifest, an enveloped transform must be applied during the generation of the signature digest of the parent XML to omit the signature containing the self-reference.

for example:

<signatures xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
    <Signature Id="othersig" 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#dsa-sha1"/>
            <Reference URI="#Manifest0">
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>j6lwx3rvEPO0vKtMup4NbeVu8nk=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>…</SignatureValue>
        <KeyInfo>
            <KeyValue>
                <DSAKeyValue>
                    <P>…</P><Q>…</Q><G>…</G><Y>…</Y> 
                </DSAKeyValue>
            </KeyValue>
        </KeyInfo>
        <Object>
            <Manifest Id="Manifest0">
                <Reference URI="EPUB/images/cover.jpeg">                    
                    <Transforms>                                                
                        <Transform
                            Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                        
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue></DigestValue>
                </Reference>
            </Manifest>
        </Object>
    </Signature> 
    <Signature Id="sig" 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#dsa-sha1"/>
            <Reference URI="#Manifest1">
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue>j6lwx3rvEPO0vKtMup4NbeVu8nk=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>…</SignatureValue>
        <KeyInfo>
            <KeyValue>
                <DSAKeyValue>
                    <P>…</P><Q>…</Q><G>…</G><Y>…</Y> 
                </DSAKeyValue>
            </KeyValue>
        </KeyInfo>
        <Object>
            <Manifest Id="Manifest1">
                <Reference URI="META-INF/container.xml">                    
                    <Transforms>                                                
                        <Transform
                            Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                        
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue></DigestValue>
                </Reference>
                <Reference URI="META-INF/signatures.xml">
                    <Transforms>                                                
                        <Transform
                            Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                        
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue></DigestValue>
                </Reference>
            </Manifest>
        </Object>
    </Signature> 
</signatures>

Where the #sig Signature contains an Object > Manifest ><Reference URI="META-INF/signatures.xml"> - a reference to its own parent XML, then in order to produce the <DigestValue> for that reference the enveloped transform must be applied to the parent XML so as to commit the reference's parent signature.
In other words the enveloped transformed XML used to generate the Object > Manifest > <DigestValue> should look like:

<signatures xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
    <Signature Id="othersig" 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#dsa-sha1"/>
            <Reference URI="#Manifest0">
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <DigestValue></DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>…</SignatureValue>
        <KeyInfo>
            <KeyValue>
                <DSAKeyValue>
                    <P>…</P><Q>…</Q><G>…</G><Y>…</Y> 
                </DSAKeyValue>
            </KeyValue>
        </KeyInfo>
        <Object>
            <Manifest Id="Manifest0">
                <Reference URI="EPUB/images/cover.jpeg">                    
                    <Transforms>                                                
                        <Transform
                            Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>                        
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue></DigestValue>
                </Reference>
            </Manifest>
        </Object>
    </Signature> 
</signatures>

Here the validation would need to happen at the DigestValue in the object manifest, however I think it would be a similar approach when creating a Signature without an Object Manifest... (using an Object Manifest is the more common epub approach to the Signature model).

In any case, I just wanted to clarify the issue. I will still try to get you a proper signatures.xml test fixture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants