Certificate generation

Minting Samsung certs, on the box

A Samsung TV only sideloads an app whose distributor signature enrolls that TV's DUID. That certificate used to mean a hand-run trip through Tizen Studio's Certificate Manager. Now Screenwhere gets it straight from Samsung's CA — you just sign in once.

OPERATOR CLOUD RELAY SITE BOX (RPI) SAMSUNG Browser · web app "Vygenerovat certifikát" /app/cert-token in-memory · 1-use token-helper.py localhost:4794 /app/app-cert-generate super-only · audited appcertgen.mjs keys · CSR · .p12 Samsung CA svdca…/apis/v3 encrypted cert store appsign.mjs 1 2 3 4 5 0 store
0the helper opens the Samsung sign-in 1the web app collects the token 2the helper deposits it under a one-time code 3the operator clicks Generate 4the relay forwards it to the box 5the box posts a CSR to Samsung's CA

The numbered steps carry the sequence. What they cannot show is why it is safe to hand a Samsung account token to a server at all — and that is the part worth reading.

The token lives for one exchange. The helper deposits it under a one-time code that the web app is already polling for, the relay keeps it in memory, and collecting it spends it — there is no copy on disk at either end, and nothing to leak later. The private keys are made on the box and never leave it; what travels to Samsung is a signing request, which is useless to anyone who intercepts it. And the certificate that comes back needs no new plumbing: it lands in the same encrypted store the signing and install flows have always read from, so from that moment they simply work. The only step that genuinely needs a human is the sign-in itself — which is why the helper runs on the operator's own machine, on localhost, and not anywhere near the cloud.

Why it exists

A Tizen TV checks one thing before it installs a .wgt: is this TV's DUID listed in the distributor certificate that signed it? That certificate comes from Samsung's online CA. Certificate Manager isn't doing anything special to get it — it just POSTs a signing request to a Samsung endpoint, and the DUIDs ride inside the request the client builds. So if we build the request (with the TV's DUIDs) and post it ourselves, the CA returns the same certificate. The only step that truly needs a person is a one-time Samsung account sign-in.

The pieces, and how they cooperate

token-helper.py

Runs on the operator's machine. Opens the Samsung sign-in and catches the token on localhost:4794 — the only redirect Samsung will accept — then hands it to the relay. The one unavoidable human touch.

/app/cert-token

A code-gated, single-use, in-memory handoff. The helper deposits the token under a 128-bit code the web app minted; the app polls to pick it up. Nothing is persisted.

Web panel

The Instalace tab's "Vygenerovat certifikát": shows the helper command, waits for the token, lets you pick a privilege level and the TV DUIDs (auto-read over sdb), then calls Generate.

/app/app-cert-generate

Super-only, audited relay route. Validates the request and forwards it to the set's box over the agent WebSocket, correlated by request id — exactly like the existing sign/install calls.

appcertgen.mjs

The generator. RSA keys, a CSR with the DUIDs in subjectAltName, a multipart POST to Samsung's CA, then a .p12 assembled with the matching Samsung VD CA chain.

Encrypted store

Generated certs land in the same AES-256-GCM store an uploaded cert would, keyed by the box-only APP_CERT_KEY. The sign + install flows use them unchanged.

Privilege levels

A distributor certificate is issued at a level, and can only sign apps whose privileges fit within it — Public (the default), Partner (Samsung partner privileges like productinfo), or Platform. We learned this on the TV: re-signing a partner-level app with a Public cert fails to install (118012); the Partner cert installs and launches. So the panel lets you pick the level, and each maps to its matching CA chain in the assembled .p12.

Where the secrets live

  • The Samsung token is in memory only — relay Map, single-use, 15-minute TTL; used in-flight on the box, then discarded. Never written to disk or any log.
  • Private keys are generated on the box and stored encrypted at rest; they never leave it. The relay only forwards.
  • Generation is super-only and audited (app.cert.generate records the privilege, DUID count, and CNs — never the token).
  • Fail-closed: without APP_CERT_KEY the plane is disabled rather than storing keys in the clear.

Undocumented endpoint. We call the same Samsung CA endpoint Tizen Studio uses (svdca.samsungqbe.com), extracted from the shipping plugin and proven live. The community does this routinely, but it's a grey area — it's the operator's own account issuing their own dev certs, and the host is configurable so a move is a config change, not a code change.

The full technical reference — every field, the reverse-engineering log, and the tests — is in docs/CERT-GENERATION.md and docs/TIZEN-INSTALL-PLAN.md. See also the architecture.