Documentation
¶
Overview ¶
Ported from org.apache.xml.security.signature.XMLSignatureInput (Apache Santuario xmlsec 3.0.6).
Package xmldsig implements the XML-DSig reference-processing core that upstream DSS obtains from Apache Santuario (xmlsec 3.0.6): URI resolution, the transform pipeline, canonicalization of the result, digest computation, ds:Manifest validation, and verification of ds:SignatureValue over the canonicalized ds:SignedInfo.
Provenance ¶
Per PORTING.md, machinery that upstream gets from a third party has no Java class to mirror one-to-one and therefore lives under internal/. This package replaces exactly the part of org.apache.xml.security that dss-xades imports - the 25 import sites under dss-xades/src/main, enumerated in the table below - and nothing else. It is layered on internal/xmldom, internal/xmlc14n and internal/xpath10, and on model/enumerations for the DSSDocument and DigestAlgorithm types that its detached-content resolver and its digests are expressed in.
The Go names below are the entry points; the Java column is the Santuario member each one replaces, and every exported identifier repeats its own mapping in its doc comment.
Go Apache Santuario 3.0.6 ------------------------------------------------------------------------------------ Data signature.XMLSignatureInput Data.Bytes XMLSignatureInput#getBytes NodeFilter signature.NodeFilter (re-exported from xmlc14n) Transform transforms.TransformSpi Registry / DefaultRegistry transforms.Transform's algorithm registry Registry.Perform transforms.Transform#performTransform PerformTransforms transforms.Transforms#performTransforms URIResolver utils.resolver.ResourceResolverSpi ResolverContext utils.resolver.ResourceResolverContext Resolve utils.resolver.ResourceResolver#resolve ResolverFragment utils.resolver.implementations.ResolverFragment EnforcedResolverFragment dss-xades EnforcedResolverFragment ResolverXPointer utils.resolver.implementations.ResolverXPointer DetachedSignatureResolver dss-xades DetachedSignatureResolver Reference signature.Reference Reference.ContentsBeforeTransformation Reference#getContentsBeforeTransformation Reference.ContentsAfterTransformation Reference#getContentsAfterTransformation Reference.ReferencedBytes Reference#getReferencedBytes Reference.CalculateDigest Reference#calculateDigest Reference.Verify Reference#verify Manifest signature.Manifest Manifest.VerifyReferences Manifest#verifyReferences SignedInfo signature.SignedInfo SignedInfo.CanonicalizedOctets SignedInfo#getCanonicalizedOctetStream XMLSignature signature.XMLSignature XMLSignature.CheckSignatureValue XMLSignature#checkSignatureValue IsDescendantOrSelf, NodeSetOf utils.XMLUtils#isDescendantOrSelf, #getSet
Two deliberate structural deviations ¶
No streaming. Santuario threads an OutputStream through the last transform of a chain so that the digest can be computed without materializing the transform output (Reference#calculateDigest passes a DigesterOutputStream; Transforms#performTransforms hands it to the last Transform only). Every transform that accepts the stream writes to it exactly the octets it would otherwise have returned - TransformC14N and TransformBase64Decode are the only two that look at it, and both branches are the same bytes - and a chain whose last transform ignores it ends in XMLSignatureInput#updateOutputStream, which canonicalizes with Canonicalizer20010315OmitComments, the same canonicalizer getBytes uses. So the streamed and the buffered paths are byte-identical, and this package implements only the buffered one - which is also the path DSS itself reads through Reference#getReferencedBytes and getContentsAfterTransformation().getBytes(). Reference.CalculateDigest digests ReferencedBytes.
Signature verification is not routed through spi.ContentVerifier. XML-DSig encodes an ECDSA signature as the raw IEEE P1363 pair r||s, not as the DER SEQUENCE crypto/x509 expects (Santuario converts in SignatureECDSA), and XMLSignature#checkSignatureValue must distinguish "the signature does not verify" (false) from "this algorithm or key cannot be used" (an exception), which spi.ContentVerifier collapses into one error. verifySignature therefore mirrors Santuario's SignatureBaseRSA/SignatureECDSA/SignatureEDDSA engineVerify directly on crypto/rsa, crypto/ecdsa and crypto/ed25519.
What is out of scope, and where it went instead ¶
Building a signature (Santuario's Transform/Transforms/Reference construction side) belongs to the XAdES port: this package reads a signature that exists. dss-xades's CounterSignatureResolver is likewise not here - it serializes a node with DomUtils.serializeNode and queries it with XPathUtils, both of which live in DSS packages that internal/ may not import - but URIResolver is an interface precisely so the XAdES port can register it. The XSLT transform is refused, exactly as Santuario refuses it under secure validation and as DSS never enables it.
Ported from org.apache.xml.security.signature.Manifest and VerifiedReference (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.signature.Reference (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.utils.resolver.ResourceResolver, ResourceResolverSpi, ResourceResolverContext and the two same-document implementations ResolverFragment and ResolverXPointer (Apache Santuario xmlsec 3.0.6), plus eu.europa.esig.dss.xades.EnforcedResolverFragment (DSS 6.5.RC1).
Ported from eu.europa.esig.dss.xades.validation.DetachedSignatureResolver, DSSDocumentXMLSignatureInput and DigestDocumentXMLSignatureInput (DSS 6.5.RC1).
Ported from org.apache.xml.security.algorithms.SignatureAlgorithm and its implementations SignatureBaseRSA, SignatureBaseRSAPSS, SignatureECDSA, SignatureDSA and SignatureEDDSA (Apache Santuario xmlsec 3.0.6), plus the JCEMapper entries DSS installs.
Ported from org.apache.xml.security.signature.XMLSignature (Apache Santuario xmlsec 3.0.6), as eu.europa.esig.dss.xades.validation.XAdESSignature and XAdESSignatureIntegrityValidator drive it.
Ported from org.apache.xml.security.signature.SignedInfo (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.transforms.Transform, TransformSpi and Transforms (Apache Santuario xmlsec 3.0.6), together with the algorithm registry that org.apache.xml.security.Init populates and DSSXMLUtils re-declares.
Ported from org.apache.xml.security.transforms.implementations.TransformBase64Decode (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.transforms.implementations.TransformC14N, TransformC14NWithComments, TransformC14N11, TransformC14N11_WithComments, TransformC14NExclusive and TransformC14NExclusiveWithComments (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.transforms.implementations.TransformEnvelopedSignature and its EnvelopedNodeFilter (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.transforms.implementations.TransformXPath and its XPathNodeFilter (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.transforms.implementations.TransformXPath2Filter and its XPath2NodeFilter, plus org.apache.xml.security.transforms.params.XPath2FilterContainer (Apache Santuario xmlsec 3.0.6).
Ported from org.apache.xml.security.utils.XMLUtils and org.apache.xml.security.utils.Constants (Apache Santuario xmlsec 3.0.6): the handful of DOM helpers the reference pipeline needs.
Index ¶
- Constants
- Variables
- func IsDescendantOrSelf(ctx, descendantOrSelf *xmldom.Node) bool
- func NodeSetOf(root, exclude *xmldom.Node, comments bool) []*xmldom.Node
- type Data
- func NewNodeData(n *xmldom.Node) *Data
- func NewNodeSetData(nodes []*xmldom.Node) *Data
- func NewOctetData(octets []byte) *Data
- func NewPreCalculatedDigestData(base64Digest string) *Data
- func PerformTransforms(in *Data, transforms *xmldom.Node, baseURI string, secureValidation bool, ...) (*Data, error)
- func Resolve(perManifest, global []URIResolver, ctx *ResolverContext) (*Data, error)
- func (d *Data) AddNodeFilter(f xmlc14n.NodeFilter) error
- func (d *Data) Bytes() ([]byte, error)
- func (d *Data) ExcludeComments() bool
- func (d *Data) ExcludeNode() *xmldom.Node
- func (d *Data) Filters() []xmlc14n.NodeFilter
- func (d *Data) IsElement() bool
- func (d *Data) IsNodeSet() bool
- func (d *Data) IsOctetStream() bool
- func (d *Data) IsPreCalculatedDigest() bool
- func (d *Data) MIMEType() string
- func (d *Data) Node() *xmldom.Node
- func (d *Data) NodeSet() []*xmldom.Node
- func (d *Data) Nodes() ([]*xmldom.Node, error)
- func (d *Data) PreCalculatedDigest() string
- func (d *Data) SetExcludeComments(b bool)
- func (d *Data) SetExcludeNode(n *xmldom.Node)
- func (d *Data) SetMIMEType(s string)
- func (d *Data) SetNodeSet(b bool)
- func (d *Data) SetSourceURI(s string)
- func (d *Data) SourceURI() string
- type DetachedSignatureResolver
- type EnforcedResolverFragment
- type Manifest
- func (m *Manifest) AddResourceResolver(r URIResolver)
- func (m *Manifest) Element() *xmldom.Node
- func (m *Manifest) Item(i int) (*Reference, error)
- func (m *Manifest) Length() int
- func (m *Manifest) References() ([]*Reference, error)
- func (m *Manifest) VerificationResults() []VerifiedReference
- func (m *Manifest) VerifyReferences(followManifests bool) (bool, error)
- type ManifestOptions
- type Reference
- func (r *Reference) CalculateDigest() ([]byte, error)
- func (r *Reference) ContentsAfterTransformation() (*Data, error)
- func (r *Reference) ContentsBeforeTransformation() (*Data, error)
- func (r *Reference) DigestAlgorithm() (enumerations.DigestAlgorithm, error)
- func (r *Reference) DigestValue() ([]byte, error)
- func (r *Reference) Element() *xmldom.Node
- func (r *Reference) HasURI() bool
- func (r *Reference) ID() string
- func (r *Reference) ReferencedBytes() ([]byte, error)
- func (r *Reference) TransformsElement() *xmldom.Node
- func (r *Reference) TransformsOutput() *Data
- func (r *Reference) Type() string
- func (r *Reference) TypeIsReferenceToManifest() bool
- func (r *Reference) TypeIsReferenceToObject() bool
- func (r *Reference) URI() string
- func (r *Reference) Verify() (bool, error)
- type Registry
- type ResolverContext
- type ResolverFragment
- type ResolverXPointer
- type SignedInfo
- type Transform
- type URIResolver
- type VerifiedReference
- type XMLSignature
- func (s *XMLSignature) AddResourceResolver(r URIResolver)
- func (s *XMLSignature) CheckSignatureValue(pub crypto.PublicKey) (bool, error)
- func (s *XMLSignature) CheckSignatureValueOnly(pub crypto.PublicKey) (bool, error)
- func (s *XMLSignature) Element() *xmldom.Node
- func (s *XMLSignature) KeyInfoElement() *xmldom.Node
- func (s *XMLSignature) SetFollowNestedManifests(b bool)
- func (s *XMLSignature) SignatureValue() ([]byte, error)
- func (s *XMLSignature) SignedInfo() *SignedInfo
Constants ¶
const ( MaximumTransformCount = 5 MaximumReferenceCount = 30 )
MaximumTransformCount is Reference.MAXIMUM_TRANSFORM_COUNT and MaximumReferenceCount is Manifest.MAXIMUM_REFERENCE_COUNT, the two secure-validation caps. Upstream lets a system property (org.apache.xml.security.maxReferences) raise the second one; that knob is not ported, because a global mutable limit is exactly the sort of ambient state this port avoids - a caller who needs a different cap can count the references itself.
DSS validates with secure validation OFF, so neither cap is enforced by default; they are exported so a caller that wants upstream's hardened behaviour can ask for it through ManifestOptions.
const ( ReferenceTypeObject = NamespaceDSig + "Object" ReferenceTypeManifest = NamespaceDSig + "Manifest" )
Reference type URIs. Port of Reference.OBJECT_URI and Reference.MANIFEST_URI.
const ( TransformC14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" TransformC14NWithComments = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" TransformC14N11 = "http://www.w3.org/2006/12/xml-c14n11" TransformC14N11WithComments = "http://www.w3.org/2006/12/xml-c14n11#WithComments" TransformC14NExcl = "http://www.w3.org/2001/10/xml-exc-c14n#" TransformC14NExclWithComments = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments" TransformBase64Decode = NamespaceDSig + "base64" TransformEnvelopedSignature = NamespaceDSig + "enveloped-signature" TransformXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116" TransformXPath2Filter = NamespaceXPathFilter2 TransformXSLT = "http://www.w3.org/TR/1999/REC-xslt-19991116" // TransformXPointer is declared because DSSXMLUtils.registerDefaultTransforms names it, but // there is no implementation to register: Santuario has an XPointer RESOLVER // (ResolverXPointer, which is what a "#xpointer(...)" reference URI goes through) and no // XPointer TransformSpi at all, so a ds:Transform naming this URI is an unknown transform // in upstream exactly as it is here. TransformXPointer = "http://www.w3.org/TR/2001/WD-xptr-20010108" )
Transform algorithm URIs. Port of the TRANSFORM_* constants of org.apache.xml.security.transforms.Transforms; DSSXMLUtils.registerDefaultTransforms names the same set, minus the canonicalization methods it takes from XMLCanonicalizer.
const ( // NamespaceDSig is Constants.SignatureSpecNS. NamespaceDSig = "http://www.w3.org/2000/09/xmldsig#" // NamespaceExcC14N is InclusiveNamespaces.ExclusiveCanonicalizationNamespace. NamespaceExcC14N = "http://www.w3.org/2001/10/xml-exc-c14n#" // NamespaceXPathFilter2 is XPath2FilterContainer.XPathFilter2NS. NamespaceXPathFilter2 = "http://www.w3.org/2002/06/xmldsig-filter2" )
Namespace URIs. Port of Constants.SignatureSpecNS and the XPath Filter 2.0 namespace of transforms.params.XPath2FilterContainer.
Variables ¶
var ErrDetachedDocumentNotFound = errors.New("xmldsig: unable to find the detached document")
ErrDetachedDocumentNotFound is the ResourceResolverException DetachedSignatureResolver raises when no candidate matches ("Unable to find document '%s' (detached signature)").
var ErrForbiddenTransform = errors.New("xmldsig: forbidden transform algorithm")
ErrForbiddenTransform is Santuario's TransformationException("signature.Transform.ForbiddenTransform"), raised by Transforms#checkSecureValidation for the XSLT transform.
var ErrKeyMismatch = errors.New("xmldsig: the public key does not match the signature algorithm")
ErrKeyMismatch reports a public key whose type does not match the signature method - an RSA key under an ECDSA method, say. Santuario surfaces it as an InvalidKeyException wrapped in XMLSignatureException, i.e. as a failure, never as "invalid signature".
var ErrMalformedSignatureValue = errors.New("xmldsig: malformed ds:SignatureValue")
ErrMalformedSignatureValue reports a ds:SignatureValue that cannot be a signature under the key at all - the wrong length for the RSA modulus. The JCE throws SignatureException for it rather than answering false, and so must this: "this is not a signature" and "this signature is forged" are different findings, and a validator that reports the second for the first has silently decided the document was signed and merely tampered with.
var ErrMissingID = errors.New("xmldsig: no element carries the referenced Id")
ErrMissingID is ResourceResolverException("signature.Verification.MissingID").
var ErrMultipleIDs = errors.New("xmldsig: more than one element carries the referenced Id")
ErrMultipleIDs is ResourceResolverException("signature.Verification.MultipleIDs"), the signature-wrapping guard.
var ErrNoReferences = errors.New("xmldsig: the manifest contains no ds:Reference")
ErrNoReferences is Santuario's XMLSecurityException("empty", "References are empty").
var ErrNoResolver = errors.New("xmldsig: no resolver can dereference the reference URI")
ErrNoResolver is Santuario's ResourceResolverException("utils.resolver.noClass").
var ErrNotAManifest = errors.New("xmldsig: not a ds:Manifest or ds:SignedInfo element")
ErrNotAManifest reports an element that is neither ds:Manifest nor ds:SignedInfo.
var ErrNotAReference = errors.New("xmldsig: not a ds:Reference element")
ErrNotAReference reports an element that is not a ds:Reference.
var ErrNotASignature = errors.New("xmldsig: not a ds:Signature element")
ErrNotASignature reports an element that is not a ds:Signature.
var ErrNotASignedInfo = errors.New("xmldsig: not a ds:SignedInfo element")
ErrNotASignedInfo reports an element that is not a ds:SignedInfo.
var ErrUninitializedData = errors.New("xmldsig: XMLSignatureInput is in no usable state")
ErrUninitializedData is Santuario's "getNodeSet() called but no input data present" and the TransformationException("Unrecognized XMLSignatureInput state") its transforms raise.
var ErrUnknownDigestAlgorithm = errors.New("xmldsig: unknown digest algorithm")
ErrUnknownDigestAlgorithm reports a ds:DigestMethod naming an algorithm this build cannot compute. Santuario raises XMLSignatureException("signature.signatureAlgorithm").
var ErrUnknownTransform = errors.New("xmldsig: unknown transform algorithm")
ErrUnknownTransform is Santuario's InvalidTransformException("signature.Transform.UnknownTransform").
var ErrUnsupportedSignatureAlgorithm = errors.New("xmldsig: unsupported signature algorithm")
ErrUnsupportedSignatureAlgorithm reports a ds:SignatureMethod this build cannot verify. It is the counterpart of Santuario's XMLSignatureException("algorithms.NoSuchAlgorithm"), and it is deliberately distinct from "the signature does not verify".
Functions ¶
func IsDescendantOrSelf ¶
IsDescendantOrSelf reports whether descendantOrSelf is ctx or lies inside it. Port of XMLUtils#isDescendantOrSelf, including its one subtlety: an attribute's parent is the element that owns it, so an attribute of a ds:Signature counts as inside that signature even though it is not among its children.
func NodeSetOf ¶
NodeSetOf collects the nodes of a subtree, in document order, skipping exclude and its subtree. Port of XMLUtils#getSet/getSetRec: an element contributes itself and all of its attributes (namespace declarations included, which is why the exclusive canonicalizer can ask whether a declaration is in the set), a comment contributes itself only when comments are kept, and a DOCTYPE contributes nothing.
Types ¶
type Data ¶
type Data struct {
// contains filtered or unexported fields
}
Data is one value flowing through the reference-processing pipeline: the result of dereferencing a ds:Reference URI, and then the result of each ds:Transform in turn. It is the port of XMLSignatureInput.
Santuario's class is a union with an unusually load-bearing discriminator, because the canonicalizer that ends a transform chain dispatches on it (CanonicalizerBase#engineCanonicalize tests isOctetStream, then isElement, then isNodeSet, in that order) and the three branches canonicalize differently. The fields are kept private and the predicates exported so that the discriminator can only ever be in a state Santuario can produce:
state built by canonicalized as ----------------------------------------------------------------------------------------- octets NewOctetData; base64 and c14n transforms parse, then whole document element NewNodeData; ResolverFragment/XPointer subtree rooted at Node, minus Exclude node set SetNodeSet(true); NewNodeSetData document subset under the filters
Exclude and Filters are what the enveloped-signature transform leaves behind (XMLSignatureInput#setExcludeNode plus a NodeFilter), and Filters is also where the ds:XPath and XPath Filter 2.0 transforms put themselves. ExcludeComments is XMLDSIG 4.4.3.3 step 4, set by the same-document resolvers.
func NewNodeData ¶
NewNodeData wraps a document or element node: the subtree rooted at it, all descendants included. Port of XMLSignatureInput(Node).
func NewNodeSetData ¶
NewNodeSetData wraps an explicit node set. Port of XMLSignatureInput(Set<Node>).
func NewOctetData ¶
NewOctetData wraps an octet stream. Port of XMLSignatureInput(byte[]).
A nil slice becomes an empty one: Java distinguishes "no octets" from "zero octets" through null, and this constructor is only ever reached for the second, so the nil is normalized away here rather than left to trip a digest routine downstream.
func NewPreCalculatedDigestData ¶
NewPreCalculatedDigestData wraps a base64-encoded digest that stands in for content that is never streamed. Port of XMLSignatureInput(String), which DSS reaches through DigestDocumentXMLSignatureInput.
func PerformTransforms ¶
func PerformTransforms(in *Data, transforms *xmldom.Node, baseURI string, secureValidation bool, r *Registry) (*Data, error)
PerformTransforms runs a ds:Transforms element's chain over in, left to right. Port of Transforms#performTransforms.
transforms may be nil, which is a ds:Reference with no ds:Transforms: the input passes through untouched and the digest is taken over Data.Bytes, which is XMLDSIG 4.4.3.2's "if the data is a node-set, apply Canonical XML".
func Resolve ¶
func Resolve(perManifest, global []URIResolver, ctx *ResolverContext) (*Data, error)
Resolve walks perManifest first and then global, returning the first resolver's answer. Port of ResourceResolver#resolve(List<ResourceResolverSpi>, ResourceResolverContext).
func (*Data) AddNodeFilter ¶
func (d *Data) AddNodeFilter(f xmlc14n.NodeFilter) error
AddNodeFilter ports addNodeFilter, including its side effect: a filter cannot be applied to octets, so an octet input is parsed into a document first (Santuario's convertToNodes).
func (*Data) Bytes ¶
Bytes returns the octets this value denotes. Port of XMLSignatureInput#getBytes: octets are returned as they are, and anything else is canonicalized with Canonical XML 1.0 omitting comments - the default the XMLDSIG reference processing model prescribes for a node set that reaches the digest without an explicit canonicalization transform (4.4.3.2), and the hard-wired canonicalizer of both getBytes and updateOutputStream.
func (*Data) ExcludeComments ¶
ExcludeComments ports isExcludeComments.
func (*Data) ExcludeNode ¶
ExcludeNode ports getExcludeNode.
func (*Data) IsElement ¶
IsElement ports isElement: a subtree, not yet turned into a node set.
FIX (integrator, Phase 4d): Santuario's isElement()/isNodeSet() test inputOctetStreamProxy (i.e. whether this value was ever constructed as an octet stream), never the cached bytes getBytes() leaves behind after canonicalizing a subtree - getBytes() caches into `bytes` at XMLSignatureInput.java:279 and upstream still re-canonicalizes the subtree on every call after that. This predicate used to also require !hasOctets, which meant a Data that had already been read once (Bytes() caches its result the same way) reported "no usable state" to the next transform - breaking any identity transform (EnvelopedSignatureTransform, Base64Transform) followed by another one, exactly the chain EnvelopedSignatureTransform's own javadoc prescribes. IsOctetStream's node==nil && nodeSet==nil guard already keeps the three branches disjoint, so dropping the hasOctets term here is safe. See the dss-xades REFS chunk's porter notes for the original diagnosis (55/57 -> 56/57 KAT cases verified against the Java oracle in a scratch harness).
func (*Data) IsNodeSet ¶
IsNodeSet ports isNodeSet. See IsElement's FIX note above; the same hasOctets term was dropped here for the same reason.
func (*Data) IsPreCalculatedDigest ¶
IsPreCalculatedDigest ports isPreCalculatedDigest.
func (*Data) Nodes ¶
Nodes materializes the node set this value denotes. Port of getNodeSet(): the explicit set when there is one, the subtree under Node minus the exclude node otherwise, and the whole parsed document for octets.
Only Manifest.VerifyReferences needs it, to find the ds:Manifest inside a reference's output when following nested manifests; the canonicalizers never call it, because materializing a filtered set would lose the -1 "skip this subtree" answers that make the filters exact.
func (*Data) PreCalculatedDigest ¶
PreCalculatedDigest ports getPreCalculatedDigest.
func (*Data) SetExcludeComments ¶
SetExcludeComments ports setExcludeComments.
func (*Data) SetExcludeNode ¶
SetExcludeNode ports setExcludeNode: the enveloped-signature transform names the ds:Signature element that the subtree canonicalization must skip.
func (*Data) SetNodeSet ¶
SetNodeSet ports setNodeSet: the ds:XPath and XPath Filter 2.0 transforms flip the discriminator so that the canonicalizer takes the document-subset path.
type DetachedSignatureResolver ¶
type DetachedSignatureResolver struct {
Documents []model.DSSDocument
DigestAlgorithm enumerations.DigestAlgorithm
}
DetachedSignatureResolver resolves a ds:Reference whose URI names a detached document, or carries no URI at all, against a list of documents supplied by the caller. Port of DetachedSignatureResolver.
DigestAlgorithm is the fallback used when the reference does not say which digest it uses; upstream registers one resolver per distinct digest algorithm found in the ds:SignedInfo, which is why the field is a single algorithm and not a set.
Candidate selection is deliberately not "match the URI to a file name". Upstream tries, in order:
- exactly one document and exactly one detached reference in the ds:SignedInfo: that document, whatever the URI says;
- the document whose digest equals the ds:DigestValue the reference states, which lets a renamed file still validate;
- the document whose name equals the percent-decoded URI.
Rule 2 before rule 3 is the surprising one and it is load-bearing: DSS prefers the document that actually hashes right, and only falls back to the name.
func (*DetachedSignatureResolver) CanResolve ¶
func (r *DetachedSignatureResolver) CanResolve(ctx *ResolverContext) bool
CanResolve ports engineCanResolveURI: a reference with no URI attribute at all, or one whose URI is a non-blank value that does not start with '#'.
func (*DetachedSignatureResolver) Resolve ¶
func (r *DetachedSignatureResolver) Resolve(ctx *ResolverContext) (*Data, error)
Resolve ports engineResolveURI.
A DigestDocument - a document that carries a digest instead of content - yields a pre-calculated-digest input, which Reference.CalculateDigest returns verbatim without running any transform. That is how DSS validates a reference over content it was never given, and it is also why a DigestDocument silently "passes" a reference that carries transforms: there is nothing to transform. Upstream has the same hole.
type EnforcedResolverFragment ¶
type EnforcedResolverFragment struct{ ResolverFragment }
EnforcedResolverFragment is ResolverFragment with DSS's XPath-injection guard in front. Port of eu.europa.esig.dss.xades.EnforcedResolverFragment.
The guard percent-decodes the URI and refuses it if it contains any of "()='[]:,*/ ". Its purpose is to stop a URI that has been crafted to be read as an XPath expression by some downstream resolver, and its effect on ordinary XAdES is nil: a "#id" fragment can carry none of those characters. A URI it refuses simply falls through to the next resolver, and then to "no resolver can dereference this", which is why DSS registers it BEFORE ResolverXPointer rather than instead of ResolverFragment.
func (EnforcedResolverFragment) CanResolve ¶
func (r EnforcedResolverFragment) CanResolve(ctx *ResolverContext) bool
CanResolve ports EnforcedResolverFragment#engineCanResolveURI.
type Manifest ¶
type Manifest struct {
// contains filtered or unexported fields
}
Manifest is a ds:Manifest, and the shared base of ds:SignedInfo - which is what it is in Santuario too: SignedInfo extends Manifest, and "verify the signature's references" is literally Manifest#verifyReferences on the ds:SignedInfo element.
func NewManifest ¶
func NewManifest(element *xmldom.Node, opts *ManifestOptions) (*Manifest, error)
NewManifest wraps a ds:Manifest element. Port of Manifest(Element, String, boolean).
func (*Manifest) AddResourceResolver ¶
func (m *Manifest) AddResourceResolver(r URIResolver)
AddResourceResolver appends a per-manifest resolver. Port of addResourceResolver, which DSSXMLUtils#initManifestDetachedContent calls once per distinct reference digest algorithm.
func (*Manifest) References ¶
References returns every ds:Reference of this manifest, in document order.
func (*Manifest) VerificationResults ¶
func (m *Manifest) VerificationResults() []VerifiedReference
VerificationResults returns the per-reference outcome of the last VerifyReferences. Port of getVerificationResults().
func (*Manifest) VerifyReferences ¶
VerifyReferences re-digests every reference and reports whether all of them match. Port of verifyReferences(boolean).
It is all-or-nothing in its return value but not in its work: every reference is verified even after one has failed, so VerificationResults tells the caller which ones did. A reference that cannot be dereferenced at all is an error, not a false - that is Santuario's MissingResourceFailureException, and DSS distinguishes the two as "reference data not found" versus "reference data not intact".
followManifests walks into a ds:Manifest a reference of type ...#Manifest points at. DSS leaves it off here and validates manifests through its own ManifestValidator instead, which is why the flag exists but the default caller passes false.
type ManifestOptions ¶
type ManifestOptions struct {
BaseURI string
SecureValidation bool
// Resolvers replaces the global resolver list. Nil selects DefaultResolvers().
Resolvers []URIResolver
// Registry replaces the transform registry. Nil selects DefaultRegistry().
Registry *Registry
}
ManifestOptions carries the knobs that are constructor arguments or setters upstream. The zero value is what DSS uses: secure validation off, the DSS resolver set, the default transform registry.
type Reference ¶
type Reference struct {
// contains filtered or unexported fields
}
Reference is one ds:Reference. Port of org.apache.xml.security.signature.Reference.
It reads the element it was built from every time rather than caching, exactly as the Java does, so a caller that mutates the DOM between calls sees the mutation - which matters, because XAdES extension does mutate the signature between validations.
func NewReference ¶
func NewReference(element *xmldom.Node, baseURI string, manifest *Manifest, secureValidation bool) (*Reference, error)
NewReference wraps a ds:Reference element. Port of Reference(Element, String, Manifest, boolean).
func (*Reference) CalculateDigest ¶
CalculateDigest computes the reference's digest. Port of calculateDigest(boolean).
The pre-calculated shortcut comes first and skips everything else: an input that carries a digest instead of content is returned as it is, without dereferencing, transforming or hashing anything.
func (*Reference) ContentsAfterTransformation ¶
ContentsAfterTransformation runs the transform chain. Port of getContentsAfterTransformation().
func (*Reference) ContentsBeforeTransformation ¶
ContentsBeforeTransformation dereferences the URI. Port of getContentsBeforeTransformation().
func (*Reference) DigestAlgorithm ¶
func (r *Reference) DigestAlgorithm() (enumerations.DigestAlgorithm, error)
DigestAlgorithm returns the ds:DigestMethod algorithm. Port of getMessageDigestAlgorithm().
Santuario additionally refuses MD5 under secure validation; DSS runs with secure validation off, so that guard never fires there and is not reproduced here. A digest algorithm the enumerations do not know is an error either way.
func (*Reference) DigestValue ¶
DigestValue returns the decoded ds:DigestValue. Port of getDigestValue().
func (*Reference) Element ¶
Element returns the ds:Reference element. Port of ElementProxy#getElement.
func (*Reference) HasURI ¶
HasURI reports whether the URI attribute is present at all - not the same as an empty URI, which means "this document".
func (*Reference) ReferencedBytes ¶
ReferencedBytes returns the octets that will be digested. Port of getReferencedBytes().
This is the byte array DSSXMLUtils#getReferenceOriginalContentBytes hands back for a reference that carries an enveloped-signature transform, and the one the XAdES validation report shows as the signed content.
func (*Reference) TransformsElement ¶
TransformsElement returns the ds:Transforms child, or nil. Port of getTransforms(), whose null result is what "this reference has no transforms" means downstream.
func (*Reference) TransformsOutput ¶
TransformsOutput returns the pipeline result of the last CalculateDigest or ContentsAfterTransformation, or nil. Port of getTransformsOutput(), which upstream documents as "only works after a call to verify".
func (*Reference) TypeIsReferenceToManifest ¶
TypeIsReferenceToManifest ports typeIsReferenceToManifest().
func (*Reference) TypeIsReferenceToObject ¶
TypeIsReferenceToObject ports typeIsReferenceToObject().
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps algorithm URIs to implementations. Port of the static registry org.apache.xml.security.transforms.Transform keeps, which Init.init() fills.
func DefaultRegistry ¶
func DefaultRegistry() *Registry
DefaultRegistry returns a registry holding the eleven transforms Transform#registerDefaultAlgorithms registers: the six canonicalization methods, base64, enveloped-signature, ds:XPath, XPath Filter 2.0 and XSLT.
Two entries are not what upstream has, and both are deliberate:
- Santuario's "physical" canonicalization method is NOT a transform. It is registered as a canonicalizer (XMLCanonicalizer offers it, so a ds:CanonicalizationMethod may name it) but never as a TransformSpi, so a ds:Transform naming it is an unknown algorithm. That is reproduced: no entry here.
- XSLT is registered as a transform that always fails. Santuario refuses it only when secure validation is on, and DSS turns secure validation OFF (new XMLSignature(element, "", false)), so upstream would actually run an XSLT stylesheet out of a signature it is validating. Running attacker-supplied XSLT is not a behaviour worth reproducing, and no XAdES profile uses the transform; a reference that carries it fails to validate here instead of being digested over transformed output. Recorded as an accepted divergence.
A fresh registry per call: the transforms themselves are stateless values, but a caller that registers its own algorithm must not perturb anyone else's pipeline, which is exactly the global-mutable-registry hazard upstream lives with.
type ResolverContext ¶
type ResolverContext struct {
Attr *xmldom.Node
URIToResolve string
BaseURI string
SecureValidation bool
}
ResolverContext is what a resolver is asked about. Port of ResourceResolverContext.
Attr is the ds:Reference URI attribute node, or nil when the reference carries no URI at all - a distinction the detached resolver depends on, since "no URI" means "the application knows what is meant" while URI="" means "this document".
type ResolverFragment ¶
type ResolverFragment struct{}
ResolverFragment resolves "" (the whole document) and "#id" (the element with that Id). Port of ResolverFragment.
Both answers exclude comments - result.setExcludeComments(true) - which is XMLDSIG 4.4.3.3 step 4: a same-document reference is a node-set that omits comment nodes unless a #WithComments canonicalization is asked for explicitly.
func (ResolverFragment) CanResolve ¶
func (ResolverFragment) CanResolve(ctx *ResolverContext) bool
CanResolve ports engineCanResolveURI: the empty URI, or a "#" URI that is not an XPointer.
func (ResolverFragment) Resolve ¶
func (ResolverFragment) Resolve(ctx *ResolverContext) (*Data, error)
Resolve ports engineResolveURI.
type ResolverXPointer ¶
type ResolverXPointer struct{}
ResolverXPointer resolves the two XPointer forms XMLDSIG requires support for. Port of ResolverXPointer.
Only two shapes are recognised, and they are recognised by string matching, not by parsing XPointer: exactly "#xpointer(/)" for the whole document, and "#xpointer(id('x'))" or "#xpointer(id(\"x\"))" for one element. Anything else - a bare-name XPointer, a scheme other than the implicit one, whitespace inside the parentheses - is not resolvable here, as upstream.
Unlike ResolverFragment this one does NOT exclude comments: an XPointer node-set keeps them, which is XMLDSIG 4.4.3.3's distinction between a bare-name and an XPointer same-document reference, and it is observable whenever the reference is canonicalized #WithComments.
func (ResolverXPointer) CanResolve ¶
func (ResolverXPointer) CanResolve(ctx *ResolverContext) bool
CanResolve ports engineCanResolveURI.
func (ResolverXPointer) Resolve ¶
func (ResolverXPointer) Resolve(ctx *ResolverContext) (*Data, error)
Resolve ports engineResolveURI.
type SignedInfo ¶
type SignedInfo struct {
*Manifest
// contains filtered or unexported fields
}
SignedInfo is a ds:SignedInfo. Port of SignedInfo, which extends Manifest in Java too: the reference verification is entirely inherited, and only the canonicalization and the signature method are its own.
func NewSignedInfo ¶
func NewSignedInfo(element *xmldom.Node, opts *ManifestOptions) (*SignedInfo, error)
NewSignedInfo wraps a ds:SignedInfo element. Port of SignedInfo(Element, String, boolean).
func (*SignedInfo) CanonicalizationMethodURI ¶
func (si *SignedInfo) CanonicalizationMethodURI() string
CanonicalizationMethodURI returns the ds:CanonicalizationMethod Algorithm. Port of getCanonicalizationMethodURI().
func (*SignedInfo) CanonicalizedOctets ¶
func (si *SignedInfo) CanonicalizedOctets() ([]byte, error)
CanonicalizedOctets returns the octets the ds:SignatureValue is computed over. Port of getCanonicalizedOctetStream().
Note what it is NOT: it is a plain SUBTREE canonicalization of the ds:SignedInfo element, with no reference processing, no node filtering and no comment exclusion - the comment behaviour is entirely the algorithm's, so a ds:CanonicalizationMethod naming a #WithComments variant really does sign the comments inside ds:SignedInfo. The result is cached, as upstream caches c14nizedBytes, because both the verification and DSS's getDataToBeSignedRepresentation ask for it.
func (*SignedInfo) SignatureMethodURI ¶
func (si *SignedInfo) SignatureMethodURI() string
SignatureMethodURI returns the ds:SignatureMethod Algorithm. Port of getSignatureMethodURI().
type Transform ¶
type Transform interface {
Algorithm() string
Perform(in *Data, element *xmldom.Node, baseURI string, secureValidation bool) (*Data, error)
}
Transform is one transform algorithm. Port of org.apache.xml.security.transforms.TransformSpi#enginePerformTransform.
element is the ds:Transform element itself, so a transform can read its own parameters - the ds:XPath child, the ec:InclusiveNamespaces PrefixList - and, crucially, resolve the namespace prefixes its expression uses against the declarations in scope there. baseURI is the reference's base URI. secureValidation is XMLSignatureInput#isSecureValidation, which DSS sets to false so that every signature algorithm stays reachable.
A transform returns a new Data or, for the filtering transforms, the same one with a filter attached; both are what Santuario does.
type URIResolver ¶
type URIResolver interface {
CanResolve(ctx *ResolverContext) bool
Resolve(ctx *ResolverContext) (*Data, error)
}
URIResolver dereferences a ds:Reference URI. Port of ResourceResolverSpi.
The two methods are asked in that order and the first resolver that says it can resolve is the one that must: ResourceResolver#resolve does not fall through to the next resolver when the chosen one fails.
func DefaultResolvers ¶
func DefaultResolvers() []URIResolver
DefaultResolvers returns the same-document resolvers, in the order XAdESSignature.initDefaultResolvers registers them: the XPath-injection-guarded fragment resolver, then the XPointer resolver.
This is deliberately NOT Santuario's registerDefaultResolvers(), which also installs ResolverDirectHTTP and ResolverLocalFilesystem. DSS replaces the default set precisely to drop those two - "Ignore references which point to a file (file://) or external http urls" - so a signature can never make the validator fetch anything.
type VerifiedReference ¶
type VerifiedReference struct {
Valid bool
URI string
// ManifestReferences holds the results of a nested ds:Manifest's own references, and is
// non-empty only when VerifyReferences was asked to follow manifests.
ManifestReferences []VerifiedReference
}
VerifiedReference is one entry of the verification result. Port of org.apache.xml.security.signature.VerifiedReference.
type XMLSignature ¶
type XMLSignature struct {
// contains filtered or unexported fields
}
XMLSignature is a ds:Signature. Port of XMLSignature(Element, String, boolean), the constructor XAdESSignature.getSantuarioSignature calls with secure validation off.
func NewXMLSignature ¶
func NewXMLSignature(element *xmldom.Node, opts *ManifestOptions) (*XMLSignature, error)
NewXMLSignature wraps a ds:Signature element.
The document's ID attributes must already be registered - xmldom's RegisterIDs, which is DSS's XAdESDOMDocument.recursiveIdBrowse - or every "#id" reference will fail to resolve. Upstream has the same precondition and satisfies it in getSantuarioSignature, one line before constructing the XMLSignature.
func (*XMLSignature) AddResourceResolver ¶
func (s *XMLSignature) AddResourceResolver(r URIResolver)
AddResourceResolver appends a resolver to the signature's ds:SignedInfo, which is the manifest whose references are being validated. Port of XMLSignature#addResourceResolver, which delegates to signedInfo.addResourceResolver.
func (*XMLSignature) CheckSignatureValue ¶
func (s *XMLSignature) CheckSignatureValue(pub crypto.PublicKey) (bool, error)
CheckSignatureValue verifies the whole signature against pub: first the cryptographic signature over the canonicalized ds:SignedInfo, then every ds:Reference. Port of checkSignatureValue(Key).
The order is Santuario's and is not an implementation detail: the references are re-digested ONLY if the signature over ds:SignedInfo verified, so a forged signature never causes the validator to dereference the URIs it names.
func (*XMLSignature) CheckSignatureValueOnly ¶
func (s *XMLSignature) CheckSignatureValueOnly(pub crypto.PublicKey) (bool, error)
CheckSignatureValueOnly verifies the cryptographic signature over the canonicalized ds:SignedInfo and nothing else.
It has no Santuario counterpart because Santuario never separates the two halves, but DSS does: XAdESSignature.checkSignatureIntegrity reports "signature intact" and "reference data intact" as two independent flags of SignatureCryptographicVerification, and it can only fill them in separately if the two checks can be run separately. Upstream gets there by calling checkSignatureValue (which does both) and then reading the reference validations back out of its own ReferenceValidation list; splitting the call is the same information without re-deriving it.
func (*XMLSignature) Element ¶
func (s *XMLSignature) Element() *xmldom.Node
Element returns the ds:Signature element.
func (*XMLSignature) KeyInfoElement ¶
func (s *XMLSignature) KeyInfoElement() *xmldom.Node
KeyInfoElement returns the ds:KeyInfo child, or nil.
func (*XMLSignature) SetFollowNestedManifests ¶
func (s *XMLSignature) SetFollowNestedManifests(b bool)
SetFollowNestedManifests ports setFollowNestedManifests: whether CheckSignatureValue also validates the references of a ds:Manifest that a reference points at. Default false, as upstream.
func (*XMLSignature) SignatureValue ¶
func (s *XMLSignature) SignatureValue() ([]byte, error)
SignatureValue returns the decoded ds:SignatureValue. Port of getSignatureValue().
func (*XMLSignature) SignedInfo ¶
func (s *XMLSignature) SignedInfo() *SignedInfo
SignedInfo returns the ds:SignedInfo. Port of getSignedInfo().