Skip to main content

SIP digest verification model

When a SIP device registers with Devotel Orbit, the digest handshake is verified at more than one layer. Reading any single layer in isolation is misleading — an operator who finds the local registration-cap check can misread its fail-open branch as a security hole. This page lays out the roles each verification layer plays, which digest envelopes the local check can and cannot recompute, and why falling open on the un-recomputable envelopes is the correct design. The credential the handshake authenticates is covered end to end in SIP credential lifecycle.

The three roles of SIP authentication

SIP registration authentication in Orbit plays three distinct roles, each at a different layer:
  1. Edge verification — prove the password before the binding forms. When a device sends REGISTER, the Jambonz softswitch challenges with a nonce and re-computes the digest response against the stored HA1 (the RFC 2617 A1 hash over username:realm:password, kept in an MD5 and a SHA-256 variant). A bad response gets a 401/403 and no binding ever forms. A stolen username alone cannot register.
  2. Optional local re-check — keep bogus User-Agents out of the cap. A credential with a registration cap re-verifies the digest locally before the slot is counted, so an attacker who knows only the username cannot fill the cap with junk endpoints and lock out your real devices. This check is accounting, not an auth gate — and this page documents exactly when it abstains.
  3. Softswitch as authority — the last word on registration. The softswitch re-verifies the digest downstream regardless of anything Orbit’s local layer concluded. The local layer can only ever decide whether a cap slot is counted; it can never admit a registration the softswitch would reject, and it never overrides a rejection.

The digest algorithm envelope

The local re-check recomputes the expected response from the same stored HA1 it hands the softswitch, using the algorithm the device announced:
  • MD5 or SHA-256 with qop=auth (or RFC 2069 no-qop) — fully recomputable. The expected response is rebuilt over (HA1, nonce, nc, cnonce, qop, HA2) and compared in constant time. A mismatch means the digest is wrong and the slot is not counted.
  • *-sess variants (MD5-sess, SHA-256-sess) — the sess HA1 folds the nonce and client nonce into the A1 hash itself. Orbit stores the base HA1 only, so the sess variant cannot be reconstructed locally. The check abstains and the slot is not counted.
  • qop=auth-int — needs a hash of the SIP message body, which the local hook does not receive. The check abstains and the slot is not counted.
  • Missing digest fields (nonce, URI, response) or an unrecognized algorithm — nothing to recompute against. Abstain and do not count the slot.
Every abstention has the same outcome: the registration proceeds to the softswitch for the real verification, and the cap simply does not reserve a slot for that attempt.

Why fail-open is correct

The fail-open posture follows directly from the split of roles above. The local check exists to keep the cap a fair accounting of verified registrations — it is a guardrail, not a gate. If it failed closed on digests it cannot recompute, any device legitimately negotiating a *-sess algorithm or auth-int quality-of-protection would be turned away from a cap it should pass, and nothing the softswitch decided afterwards could un-block it. Failing open cannot admit an attacker. A bogus digest on a sess algorithm skips the slot accounting and reaches the softswitch, which re-verifies against the stored HA1 and rejects it with a 401/403 — the same outcome the edge challenge produces for any bad digest. The worst case of an abstention is a registration whose slot was not counted, while the binding still has to survive the authoritative verification. The worst case of failing closed would be turning away your own phones.

Which envelopes must fall open

The platform’s outbound and registration boundary is anchored by a single rule — inbound termination stays at the edge, and the softswitch remains the authority on what registers. That rule fixes precisely which digest envelopes the local check is allowed to abstain on rather than misjudge:
  • *-sess algorithms — abstain; the session-HA1 variant is provably un-recomputable from the stored base HA1.
  • qop values other than auth (today auth-int) — abstain; the entity-body hash is not available at the hook.
  • Missing nonce, URI, or response fields — abstain; there is no well-formed digest to compare.
Envelopes outside that list — MD5 or SHA-256 with qop=auth, or RFC 2069 with no qop — must verify exactly, with the comparison in constant time. When you review or extend the digest handling, keep the abstention list complete: an envelope added to the digest path without falling into one of these classes is the defect case, and a *-sess or auth-int attempt blocked by the local check is the regression this page exists to prevent.

Where the handshake terminates

Every REGISTER — recomputable or abstained — still terminates on the Devotel wholesale softswitch, which re-verifies the digest against the stored HA1 before any binding is accepted. The local envelope rules above only shape how the registration cap accounts for attempts; they never reroute, bypass, or override that termination. The edge handshake and the error statuses it surfaces (403 / 402 / 480) are described in Jambonz softswitch model.