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

Transform nodes in a Signature Policy #271

Open
DouweKoopmans opened this issue Mar 6, 2023 · 6 comments
Open

Transform nodes in a Signature Policy #271

DouweKoopmans opened this issue Mar 6, 2023 · 6 comments

Comments

@DouweKoopmans
Copy link

I'm using Xades4j v2.2.0 and want to create a signature based on a signature policy which contains transform nodes.
The policy contains an expected signature policy at the end of the xml-file which needs to be removed with a filter2 subtract action. additionally the entire file needs to be Canonicalized. Both these transformations are defined in the signature policy file.

These transform actions need to be executed before the policy digest is calculated. It seems like these transformations aren't automatically preformed in the current version. Is there a way to execute these transformations through xades4j?

@luisgoncalves
Copy link
Owner

The policy document itself contains those transformations, right?

My understanding - hence the way xades4j is implemented - is that the SignaturePolicyIdentifier qualifying property contains the hash of the policy document itself (i.e. the whole resource), not the hash/digest according to the processing rules defined by spec/syntax to which the policy obeys. Processing the transforms and digest defined by the policy itself is out of the scope of xades4j, as the library doesn't include support for processing signature policies.

The XAdES spec allows for transforms to be applied over the policy document (this kind of confirms the reasoning above):

The optional ds:Transforms element can contain the transformations performed on the signature policy document
before computing its hash.

This isn't supported by xades4j as I think the use case is rather limited.

More recent versions of the XAdES spec (namely EN 319 132-1) also seem to indicate that the reasoning above is correct. When describing SignaturePolicyStore, that spec says:

Being an unsigned qualifying property, it is not protected by the digital signature. If the
SignaturePolicyIdentifier qualifying property is incorporated into the signature and contains the
SigPolicyHash element with the digest value of the signature policy document

Notice how it mentions the "policy document" again.

Do you have any other indication in a different direction?

So, to sum-up: processing of the policy itself is not handled by xades4j. The verifier has access to SignaturePolicyIdentifierProperty (via the verification result), which identifies the policy and allows for further processing.

@DouweKoopmans
Copy link
Author

Thanks for the response.
The policy I need to add to my signatures is the Dutch SBR siganture policy v2.0. If you look at the end of the policy you'll see it specifies what it expects the digest of the document to be.

When I currently feed Xades4J this policy with the code below the resulting digest is different from the one specified in the policy. I think this is because the transform actions aren't being executed.

new SignaturePolicyIdentifierProperty(new ObjectIdentifier("urn:sbr:signature-policy:xml:2.0", IdentifierType.OIDAsURN), new ByteArrayInputStream(in.readAllBytes()));

What would be the best way I can assure Xades4J produces signatures with the same SigPolicyHash as the one specified in the policy?

@luisgoncalves
Copy link
Owner

luisgoncalves commented Mar 8, 2023

What would be the best way I can assure Xades4J produces signatures with the same SigPolicyHash as the one specified in the policy?

xades4j already produces the correct hash, as I tried to explain in my previous reply. There's no way to change this behavior via configuration.

I don't know if that policy file obeys to some standard that also defines processing rules, but, trying to explain again, my understanding is the following:

sbrsp:SignPolicyDigest

The digest value in sbrsp:SignPolicyDigest in the policy document is calculated by:

  • Take the XML of the policy - i.e. the DOM nodeset.
  • Apply the transforms defined in ds:Transforms
  • Apply the digest algorithm defined in sbrsp:SignPolicyDigestAlg

As expected, in this case there's a transform to remove SignPolicyDigest, because otherwise, setting its value would change the final digest, if calculated again.

SignaturePolicyIdentifier

The digest value within the SignaturePolicyIdentifier qualifying property (SignaturePolicyIdentifier/SignaturePolicyId/SigPolicyHash/DigestValue) in the signature produced by xades4j is calculated by:

  • Take the bytes of the policy file
  • Apply transforms defined in SignaturePolicyIdentifier/SignaturePolicyId/ds:Transforms, if any. Note that xades4j doesn't allow you to specify these transforms, but that's reasonable.
  • Apply the digest algorithm defined in SignaturePolicyIdentifier/SignaturePolicyId/SigPolicyHash/DigestMethod

In this case we just look at the policy file/resource as a whole, for integrity. It just happens that the policy format also defines a digest, but it probably didn't have to.

From the XAdES spec, section 7.2.3:

An explicit signature policy has a globally unique reference, which, in this way, is bound
to an electronic signature by the signer as part of the signature calculation. In these cases, for a given explicit
signature policy there shall be one definitive form that has a unique binary encoded value

Another argument is that it wouldn't make sense for a library producing signature to also have to know how to process any signature format. Also, read the arguments in my previous reply.


To sum up: my understanding is that the two mechanisms are different and xades4j is doing the correct thing. If you have any evidence that indicates something different, please share. Otherwise, I'm closing this issue.

@luisgoncalves
Copy link
Owner

With all this, I didn't ask: why did you want xades4j to calculated the digest in SignaturePolicyIdentifier as you described? Is it because the verifier of your signatures expects that? Is the verifier correct?

@DouweKoopmans
Copy link
Author

In this EU guideline (section 5.2.9.) it clearly describes how Transform elements inside a signature policy should be processed before computing the hash that will be placed in the SignaturePolicyIdentifier.
I have not used the Xades Verifier but based on my findings I think the Xades4j signature generator does not support this use-case.

It's up to you if you want to add this support. I have already solved my problem by using the DSS-xades library from the EU to perform the transform actions and giving the resulting policy document to xades4j.

For anyone who has a similar problem, with the following code DSS-Xades will canonicalise your document and perform a filter2 xpath tranform, removing the "SignPolicyDigest" from the policy document:

List<DSSTransform> policyTransforms = new ArrayList<>();
DSSTransform canonicalization = new CanonicalizationTransform(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
policyTransforms.add(canonicalization);
DSSTransform subtractDigestFilter = new XPath2FilterTransform("/*/*[local-name()='SignPolicyDigest']", "subtract");
policyTransforms.add(subtractDigestFilter);
        
return DSSXMLUtils.applyTransforms(signaturePolicy, policyTransforms);

@luisgoncalves
Copy link
Owner

luisgoncalves commented Mar 10, 2023

Thanks for sharing more details.

An important note is that xades4j is based on ETSI TS 101 903 1.4.1. The link you shared is for the more recent XAdES spec.

That said, we still have different interpretations. I believe that - even on the newer EN 319 132-1 V1.2.1 spec - the ds:Transforms in SignaturePolicyIdentifier/SignaturePolicyId are not the same nor related to the ds:Transforms inside a particular policy document which uses a specific policy format.

Note that signature policies don't need to be XML-based. TS 119 172-1 defines both PDF and XML formats for policies.

You asked:

What would be the best way I can assure Xades4J produces signatures with the same SigPolicyHash as the one specified in the policy?

Even assuming the policy is XML, my understanding is that the digest value in SignaturePolicyIdentifier/SignaturePolicyId/SigPolicyHash in the signature does not need to be the same as in sbrsp:SignPolicyDigest in the policy file. sbrsp:SignPolicyDigest is specific to the policy format (XML in this case).

If this wasn't the case, how would signatures be handled (produced and verified) in cases where ds:Transforms are used on both the SignaturePolicyIdentifier property and within the policy document? Would those need to match?! I don't think those digests can be the same. The only way I could think of for the digest from the policy document to be used also for SignaturePolicyIdentifier in the signature would be if the SignaturePolicyIdentifier included a way to explicitly say that.

Note how the section on the spec that you linked even defines a (kind of hacky) transform to indicate that the digest should be calculated accordingly to some other specification:

NOTE 2: This transform can be used when the technical specification defines a mechanism for computing the hash
value of the signature policy document that is not easily implementable using widely used XML
technologies (e.g. XPath), as can occur, for instance, when the signature policy document is
DER-encoded ASN.1.

Given all the above, it's clear to me that SignaturePolicyIdentifier operates over the raw policy document. So, regarding your statement above:

In this EU guideline (section 5.2.9.) it clearly describes how Transform elements inside a signature policy should be processed before computing the hash that will be placed in the SignaturePolicyIdentifier.

I must ask: how did you conclude that?


On the side of trying to understand what's the correct thing to do, I still didn't understand why you needed to have the same digest values. Are you verifying the signatures produced by xades4j in another platform that has this rule? If that's the case, the verifier may be wrong.

Note that by transforming the policy document before providing the byte stream to xades4j, you may actually break other verifiers that do things as xades4j.

It may be worth mentioning that a few years ago xades4j participated in interoperability tests organized by ETSI. I don't recall all the test cases, but I'm pretty sure this wasn't an issue.

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