Skip to content

Omex manifest signing not reproducible for non-Microsoft add-ins #1009

Description

@zsy619

Summary

Working Omex add-in manifests shipped with Office LTSC 2024 Mac
contain an XAdES-T (XML Digital Signature with Time Stamp) envelope
signed with CN=Microsoft Corporation Third-Party App Distribution
and a timestamp from CN=Microsoft Time-Stamp Service (nShield
HSM-backed). The cert chain is rooted at CN=Microsoft Root Certificate Authority 2010.

This cert is only issued to Microsoft itself as part of the AppSource
submission pipeline. No third party can obtain a cert with the
Third-Party App Distribution subject.
As a result, the
"sign your dev manifest with a code-signing cert" path suggested in
some online guides does not work for dev add-ins on LTSC 2024 Mac.

Environment

  • Office LTSC Standard for Mac 2024, version 16.110.2, build 26062818
  • macOS 15.5
  • Any manifest that needs to be XAdES-signed for the WEF scanner to
    consider it installable

Repro (extract cert from a working Omex manifest)

WEF="/Users/zhushuyan/Library/Containers/com.microsoft.Excel/Data/Library/Application Support/Microsoft/Office/16.0/Wef/{EC993EB3-E226-5544-82339-1F3370D3A9CD}"
# Pick any Omex manifest, e.g. wa200010215_2.0.0.0
M="$WEF/Omex/geLWvPTNy9pxk4xxzFEGHw==/Manifests/wa200010215_2.0.0.0"

# Extract all 5 X509Certificate elements
python3 <<'PY'
import re, base64, subprocess
with open("M") as f: c = f.read()
certs = re.findall(r'<X509Certificate>(.+?)</X509Certificate>', c, re.DOTALL)
for i, b64 in enumerate(certs, 1):
    der = base64.b64decode(re.sub(r'\s+', '', b64))
    with open(f"/tmp/omex-cert-{i}.der", "wb") as f: f.write(der)
    out = subprocess.run(["openssl", "x509", "-inform", "DER", "-noout",
                          "-subject", "-issuer", "-dates",
                          f"/tmp/omex-cert-{i}.der"], capture_output=True, text=True).stdout
    print(f"--- cert #{i} ---")
    print(out)
PY

Expected (per the Office Add-in manifest spec)

The official manifest documentation
(https://learn.microsoft.com/en-us/office/dev/add-ins/develop/xml-manifest-overview)
does not mention XML digital signatures or XAdES at all. The schema
reference is silent on the topic. Per spec, a manifest is a plain
XML document with no signing requirement.

Actual

All 4 Omex manifests on a stock LTSC 2024 Mac install contain an
XAdES-T signature with this cert chain:

# Subject Issuer Validity
1 CN=Microsoft Corporation Third-Party App Distribution CN=Microsoft Windows Code Signing PCA 2024 2026-03-05 → 2027-03-03
2 CN=Microsoft Windows Code Signing PCA 2024 CN=Microsoft Root Certificate Authority 2010 2024-08-08 → 2035-06-23
3 CN=Microsoft Root Certificate Authority 2010 (self-signed root) itself 2010-06-23 → 2035-06-23
4 CN=Microsoft Time-Stamp Service (nShield HSM, ESN:F002-05E0-D947) CN=Microsoft Time-Stamp PCA 2010 2026-02-19 → 2027-05-17
5 CN=Microsoft Time-Stamp PCA 2010 CN=Microsoft Root Certificate Authority 2010 2021-09-30 → 2030-09-30

The signature uses RSA-SHA256, c14n 1.0 canonicalization, enveloped
signature with a counter-signature containing a second X509Data
block (the TSA cert chain).

Why this matters for dev

If the WEF scanner on LTSC 2024 Mac does validate the cert chain
against the Microsoft root, no dev add-in can be installed locally
without going through AppSource
. The "sign your manifest with a
self-signed cert" workaround does not work because:

  • A self-signed cert has no chain to Microsoft Root Certificate Authority 2010
  • The leaf cert subject Third-Party App Distribution is reserved
    for Microsoft's AppSource tooling
  • A real public CA-issued cert (e.g. Sectigo, Let's Encrypt) would
    chain to that CA's root, not to the Microsoft root
  • The timestamp must come from Microsoft Time-Stamp Service, not a
    generic RFC 3161 TSA like freetsa.org

If the WEF scanner does NOT validate the cert chain (i.e. the
signature is a post-install artifact for catalog lifecycle tracking
only), then this is a red herring and the real gate is the one
described in the related "WefProcess rejects manually-registered
dev catalog" issue.

Verification I ran

I signed my dev manifest with a self-signed RSA-2048 cert
(CN=DeepSeek Excel Assistant Dev Signing, O=Local Dev, C=US,
30-day validity) using signxml 5.0.1 with the exact same algorithm
choices as the Omex manifests (RSA_SHA256, SHA256,
CANONICAL_XML_1_0, enveloped). The signed manifest is structurally
identical to an Omex one (1 <ds:Signature>, 1 <ds:X509Certificate>,
matching SignatureMethod and CanonicalizationMethod URIs).

I then backfilled all 5 SQL preconditions + on-disk layout with the
signed manifest in Manifests/<aid>_<ver>, disabled the system
proxy, restarted Excel, and waited 35s.

Result: identical to unsigned baseline. WefProcess did not spawn.
Dev server got 0 requests. Excel diagnostic log contained 0 references
to the addin GUID / catalog / signature / 127.0.0.1:3000.

The signature does not unblock the dev catalog.

Suggested fix

Two paths:

  1. Document the exact signature requirements (cert subject,
    timestamp authority, XAdES profile — BES vs T vs XL) in the
    official manifest docs. The current docs are silent on signing,
    but production tooling clearly does sign. Add a section "How to
    sign a manifest for production deployment".

  2. Provide a "sign with a self-signed cert" mode for dev add-ins
    that produces a signature the WEF scanner accepts. The cleanest
    implementation would be to add a <ds:KeyName> to the KeyInfo
    block containing the literal string "dev-mode" and have the WEF
    scanner skip cert chain validation when it sees this marker.

Related

  • See also: office-addin-debugging 5.x / 6.x doesn't sideload on LTSC 2024 Mac (office-addin-debugging 5.x / 6.x doesn't sideload on LTSC 2024 Mac #1006) — the broader "tooling only writes 2/6
    SQL rows" framing
  • See also: LTSC 2024 Mac WefProcess rejects manually-registered
    dev catalog (issue TBD) — the hidden trust gate that fires before
    the signature check and is the more fundamental blocker

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions