Detect whether an .xlsx package carries an ECMA-376 Part 2 digital signature.
Library verdicts: python-xlsx: — xlsxjs: —
| Feature id | xlsx/digital-signature-detection |
|---|---|
| Format | xlsx |
| Category | packaging |
| Spec | ecma-376-5-part-2 § 12 |
| ID / part | Predicate | XPath | python-xlsx | xlsxjs |
|---|---|---|---|---|
origin-sigs-marker-present | exist | — | — | |
signature-xml-part-present | exist | — | — | |
signature-element-present_xmlsignatures/sig1.xml | exist | /ds:Signature | — | — |
No render assertions declared.
scripts/gen_signed_fixtures.py
#!/usr/bin/env python3
"""Generate signed-package detection fixtures for pptx and xlsx.
The OPC-level digital-signature layout is format-agnostic:
- ``_xmlsignatures/origin.sigs`` — zero-byte marker part.
- ``_xmlsignatures/_rels/origin.sigs.rels`` — relationship to ``sig1.xml``.
- ``_xmlsignatures/sig1.xml`` — XMLDSIG ``<Signature>`` root.
This script clones the existing minimal .pptx and .xlsx fixtures and
appends the three signature parts so detection-layer assertions pass.
The embedded ``<SignatureValue>`` is a literal ``"ignored"`` — valid
for detection, NOT cryptographically verifiable. Full XMLDSIG
canonicalisation + signing is out of scope; see
``features/{pptx,xlsx}/digital-signature-detection.json``.
Mirrors ``python-docx/features/steps/test_files/pkg-signed.docx``.
"""
from __future__ import annotations
import shutil
import zipfile
from pathlib import Path
_REPO_ROOT = Path(__file__).resolve().parent.parent
_ORIGIN_SIGS = b""
_SIG_RELS = (
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
b'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
b'<Relationship Id="rIdSig1" '
b'Type="http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature" '
b'Target="sig1.xml"/>'
b"</Relationships>"
)
_SIG1_XML = (
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n'
b'<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">\n'
b" <SignedInfo/>\n"
b" <SignatureValue>ignored</SignatureValue>\n"
b" <KeyInfo>\n"
b" <X509Data>\n"
b" <X509SubjectName>CN=Alice Example</X509SubjectName>\n"
b" </X509Data>\n"
b" </KeyInfo>\n"
b" <Object>\n"
b' <SignatureProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">\n'
b" <SignatureProperty>\n"
b" <xades:SigningTime>2024-04-01T12:34:56Z</xades:SigningTime>\n"
b" </SignatureProperty>\n"
b" </SignatureProperties>\n"
b" </Object>\n"
b"</Signature>"
)
def _clone_and_sign(src: Path, dst: Path) -> None:
dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copy(src, dst)
with zipfile.ZipFile(dst, "a", compression=zipfile.ZIP_DEFLATED) as zf:
zf.writestr("_xmlsignatures/origin.sigs", _ORIGIN_SIGS)
zf.writestr("_xmlsignatures/_rels/origin.sigs.rels", _SIG_RELS)
zf.writestr("_xmlsignatures/sig1.xml", _SIG1_XML)
def main() -> int:
pairs = [
(
_REPO_ROOT / "fixtures" / "pptx" / "package-thumbnail-dropped.pptx",
_REPO_ROOT / "fixtures" / "pptx" / "digital-signature-detection.pptx",
),
(
_REPO_ROOT / "fixtures" / "xlsx" / "package-thumbnail-dropped.xlsx",
_REPO_ROOT / "fixtures" / "xlsx" / "digital-signature-detection.xlsx",
),
]
for src, dst in pairs:
_clone_and_sign(src, dst)
print(dst)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "xlsx/digital-signature-detection",
"title": "Digital signature detection",
"format": "xlsx",
"category": "packaging",
"summary": "Detect whether an .xlsx package carries an ECMA-376 Part 2 digital signature.",
"roles": [
"authoring"
],
"spec": {
"source": "ecma-376-5-part-2",
"clause": "12",
"notes": "Sibling of docx/digital-signature-detection for xlsx. Same OPC-level detection pattern: `_xmlsignatures/origin.sigs` marker + `_xmlsignatures/sig1.xml` XMLDSIG part. The committed fixture embeds a detection-only XMLDSIG stub (literal `<SignatureValue>ignored</SignatureValue>`) — valid for existence assertions, NOT cryptographically verifiable."
},
"fixtures": {
"machine": "xlsx/digital-signature-detection"
},
"generator": {
"python": "scripts/gen_signed_fixtures.py"
},
"assertions": [
{
"id": "origin-sigs-marker-present",
"kind": "zip_contains_path",
"path": "_xmlsignatures/origin.sigs",
"must": "exist"
},
{
"id": "signature-xml-part-present",
"kind": "zip_contains_path",
"path": "_xmlsignatures/sig1.xml",
"must": "exist"
},
{
"id": "signature-element-present",
"part": "_xmlsignatures/sig1.xml",
"namespaces": {
"ds": "http://www.w3.org/2000/09/xmldsig#"
},
"xpath": "/ds:Signature",
"must": "exist"
}
]
}
No rendered reference is available for this case.