Skip to content

macOS beta.99 updater fails Sigstore verification in Electron: unspecified ECDSA hash algorithms #426

Description

@pplebel

Problem

On macOS 26.6.2 / Apple Silicon, Settings → Updates → Check now fails in the official mdbase Connect 0.1.0-beta.99 desktop app:

Could not verify updates: No release had valid signed update metadata. Rejected update metadata for v0.1.0-beta.99: The cached and freshly bootstrapped Sigstore trust metadata both failed verification.

The underlying error is UnsignedMetadataError: root was signed by 0/3 keys.

The desktop, bundled CLI, and managed daemon all report beta.99; the daemon is healthy. This persists after restarting the app and service and is distinct from the old-daemon problem in #425. The installed app passed macOS signature verification and Gatekeeper's notarized Developer ID assessment.

Reproduction and isolation

  1. Obtain beta.99's public mdbase-connect-channel-v1.json and corresponding .sigstore.json asset.
  2. Extract the unchanged self-contained dist/main/release-source.js from the official app's app.asar to a temporary directory, naming it release-source.cjs.
  3. Invoke its exported verifier with a temporary trust cache:
const fs = require("node:fs");
const { verifyArtifactBundle } = require("./release-source.cjs");

verifyArtifactBundle({
  bundleBytes: fs.readFileSync("./mdbase-connect-channel-v1.json.sigstore.json"),
  artifactBytes: fs.readFileSync("./mdbase-connect-channel-v1.json"),
  tag: "v0.1.0-beta.99",
  trustCacheDirectory: "./isolated-trust"
}).then(() => console.log("PASS"))
  .catch(error => {
    console.dir(error, { depth: 8 });
    process.exitCode = 1;
  });

Run the same script with:

  • Standalone Node 22.23.1: full verification passes.
  • ELECTRON_RUN_AS_NODE=1 "/Applications/mdbase connect.app/Contents/MacOS/mdbase-connect" verify.cjs: verification fails.

The shipped Electron reports 43.1.1, Node 24.18.0, architecture arm64, and process.versions.openssl === "0.0.0".

A fresh Node verification successfully advances the pinned TUF root from version 14 to version 15. Electron still fails when given that verified root-15 cache, as well as with a fresh bootstrap. Therefore an expired/corrupt cache alone does not explain this failure.

Isolated repair candidate

The runtime difference is triggered by unspecified signature hash algorithms in two bundled dependency helpers:

  • @tufjs/models/dist/utils/verify.js: root metadata verification calls crypto.verify(undefined, ...).
  • @sigstore/core's crypto helper: transparency-log verification can also reach crypto.verify without an algorithm.

Explicit SHA-256 for the EC keys in this release's signatures makes complete verification succeed in the shipped Electron runtime. Fixing only the first helper advances verification but then fails with TLOG_INCLUSION_PROMISE_ERROR; both paths need coverage.

Diagnostic changes against the extracted bundle:

 // @tufjs/models verification helper; key is an options object
-return crypto_1.default.verify(void 0, canonicalData, key, Buffer.from(signature, "hex"));
+return crypto_1.default.verify(key.key.asymmetricKeyType === "ec" ? "sha256" : undefined, canonicalData, key, Buffer.from(signature, "hex"));

 // @sigstore/core verification helper; key is a KeyObject
-return crypto_1.default.verify(algorithm, data, key, signature);
+return crypto_1.default.verify(algorithm ?? (key.asymmetricKeyType === "ec" ? "sha256" : undefined), data, key, signature);

This is a diagnostic candidate, not a production-ready patch for every EC scheme. A production implementation should choose algorithms from the supported signature/key schemes, preserve EdDSA semantics and explicit algorithms, and rebuild from source. The tests below cover the actual beta.99 release signatures, not all supported key types.

Validation under the shipped Electron runtime

With both temporary changes and the existing signer identity, issuer, transparency-log threshold, and CT-log threshold checks intact:

Case Result
Official beta.99 payload and bundle Accepted
Altered payload Rejected: SIGNATURE_ERROR
Wrong release identity (beta.98) Rejected: UNTRUSTED_SIGNER_ERROR
Altered transparency-log signature Rejected: TLOG_INCLUSION_PROMISE_ERROR
Repeat with cached trust Accepted

No installed application bundle was patched or re-signed, no signature checks were disabled, and no personal collection contents or credentials were used. A publisher-signed release with a source-level fix and an Electron-runtime regression test would resolve this without asking users to weaken application integrity.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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