# Security and cryptography

This document covers how the BDI components sign things, verify things, manage their keys, and what we worry about when we wear our security hat. It's the place to start if you're auditing the implementation, or if you're trying to figure out whether a particular threat is in scope.

If you've found something that needs to be fixed, jump to the bottom for how to report it privately.

# The BDI JWS profile

Cryptographic interoperability between heterogeneous operators only works if everyone agrees on a narrow set of choices. We've kept the allowed surface deliberately small — every option is one less thing for a verifier to get wrong.

Every compact JWS produced or consumed by these components must satisfy:

Token lifetimes are intentionally short. The shorter the lifetime, the smaller the window for any kind of replay or revocation race.

Token type Max lifetime
BVAD 10 minutes
BVOD 60 minutes
OAuth access token 15 minutes
Member descriptor 24 hours
Trustlist 5 minutes (CDN + invalidation)
Webhook detached sig 5 minutes (replay)

All of these constants live in @transportial/contracts, so the wire profile is single-source: one PR changes them everywhere or nowhere.

# Key management

Each service carries three sets of keys at any moment:

Rotation is a scheduled job (in the reference, a cron BullMQ job; in development, called manually). When the active key rotates, the event asr.keys.rotated is published so downstream consumers refresh their trustlists immediately rather than waiting for the next poll.

# Signer adapters

The reference JwsSigner is backed by HMAC-SHA-256 via WebCrypto. It's a real implementation of the RawSigner port — production deployments just plug in a different one:

All adapters implement the same two methods, which is why swapping them is a one-line composition-root change:

interface RawSigner {
  sign(payload: Uint8Array): Promise<Uint8Array>;
  verify(payload: Uint8Array, signature: Uint8Array): Promise<boolean>;
}

# Certificate authority (ACME)

For production, @transportial/crypto-ca provides an RFC 8555 server skeleton with:

Operators plug in the actual CA via the CertificateAuthority port: a bundled step-ca adapter, a PKCS#11 / HSM adapter, or their own.

# Threat model — the short version

Here's what we worry about, and how the design responds to each one.

Threat Mitigation
Stolen connector private key Cert revocation → trustlist update → BVAD fails next issuance; short BVAD lifetime bounds the window
Replayed BVAD jti + 30s clock skew; BVAD-only, never used on the data plane
Replayed webhook Bdi-Event-Id seen-cache (7-day TTL) in CON
Malicious subscription endpoint Callback-URL whitelist via ASR registration
Compromised ASR DB Tokens carry hashes, not PII; trustlist is signed
Wrong-issuer impersonation BVAD iss pinned to the association root JWK in CON

This list isn't exhaustive — it's the set of failure modes the dual-token boundary was designed for. If you have a threat in mind that isn't covered here, please raise an issue. We'd rather discuss it openly than discover it the hard way.

# Reporting a security issue

If you discover a security issue, please don't open a public GitHub issue. Email [email protected] with:

We'll acknowledge within 3 business days and aim to disclose and fix within 30 days. Responsible disclosure is much appreciated and we'll credit you (or stay anonymous, your call) in the release notes.