The Concealed HTTP Authentication Scheme
Extracted elements (29)
Authentication checks can introduce timing side-channels: an attacker can compare response timing for known-nonexistent resources versus potentially authenticated resources. Servers should slightly delay responses to some nonexistent resources to mask authentication verification time, but must avoid making the delay itself reveal that this mechanism is in use.
Existing signature-based HTTP authentication schemes (e.g., HOBA) require the server to send a fresh nonce/challenge to the client, which reveals that authentication is expected. The Concealed scheme instead derives freshness from a TLS keying material exporter, allowing the server to never issue a challenge and thus remain non-probeable.
The 'a' parameter (public key included in the Authorization header) avoids key confusion issues identified in the 'Seems Legit' paper, where an attacker could trick a server into accepting a signature computed for a different key. The 'v' parameter similarly guards against signature schemes where certain keys can produce signatures valid for multiple inputs.
The static prefix (64 x 0x20 + context string + zero separator) prepended before signing mirrors the TLS 1.3 CertificateVerify construction. Its purpose is to mitigate issues that could arise if authentication keys were accidentally reused across protocols, even though such reuse is explicitly forbidden.
The Concealed authentication scheme is only defined for HTTP over TLS, including HTTP/2 over TLS and HTTP/3 (where QUIC uses TLS for key exchange). It is not defined for cleartext HTTP.
Byte-sequence authentication parameter values MUST NOT include any characters other than ASCII letters, digits, dash, and underscore (base64url without padding). The integer parameter value MUST NOT include any characters other than digits and MUST NOT start with a zero unless the full value is '0'.
Clients MUST NOT use the Concealed HTTP authentication scheme on connections that do not use TLS >= 1.3, or TLS 1.2 without the extended master secret extension (RFC 7627). If a server receives such a request, it MUST treat the authentication as not present.
For RSASSA-PSS algorithms, BER encodings of the public key that are not also DER MUST be rejected.
HTTP servers that parse the Concealed-Auth-Export header field MUST ignore it unless they have already established that they trust the sender. Frontends that send Concealed-Auth-Export MUST ensure they do not forward any Concealed-Auth-Export header field received from the client.
If any of the backend's five validation checks fail (parameter parsing, key ID lookup, public key match, verification field match, or cryptographic signature), the backend MUST treat the request as if the Authorization (or Proxy-Authorization) header field was missing.
If the realm authentication parameter is not present, the Realm field in the key exporter context SHALL be empty. A client not configured to use a specific realm SHALL use an empty realm and SHALL NOT send the realm authentication parameter.
Length fields in the key exporter context are encoded using the variable-length integer encoding from Section 16 of RFC 9000 (QUIC) and MUST be encoded in the minimum number of bytes necessary.
Servers wishing to make resources non-probeable MUST respond to authentication failures with the exact same response they would use for nonexistent resources (e.g., 404 Not Found instead of 401 Unauthorized).
The frontend MUST validate that all required authentication parameters are present and parseable. If any parameter is missing or fails to parse, the frontend MUST ignore the entire Authorization (or Proxy-Authorization) header field.
When a client uses the Concealed scheme, it SHALL compute the authentication proof using a TLS keying material exporter with label 'EXPORTER-HTTP-Concealed-Authentication', context as defined in Section 3.1, and output length of 48 bytes.
Five REQUIRED authentication parameters are defined: 'k' (key ID byte sequence identifying the client key), 'a' (public key byte sequence to prevent key confusion), 'p' (proof/signature byte sequence), 's' (signature scheme integer 0-65535 from IANA TLS SignatureScheme registry), and 'v' (verification byte sequence from the last 16 bytes of the key exporter output).
Public key encoding depends on the algorithm: RSASSA-PSS uses DER-encoded RSAPublicKey (BER-only encodings MUST be rejected); ECDSA uses UncompressedPointRepresentation from TLS Section 4.2.8.2; EdDSA uses the byte-string encoding from RFC 8032.
The 'Concealed-Auth-Export' HTTP request header field carries the 48-byte key exporter output from frontend to backend as a Structured Field Byte Sequence (RFC 9651 Section 3.3.5), encoded in the non-URL-safe base64 variant, when the frontend and backend are separate servers.
The 'Concealed' HTTP authentication scheme uses asymmetric cryptography. Clients possess a key ID and a public/private key pair; servers maintain a mapping of authorized key IDs to public keys. The client signs data derived from a TLS key exporter and sends the result unprompted in the Authorization (or Proxy-Authorization) header field.
The signature is computed over: 64 repetitions of octet 0x20, the UTF-8 context string 'HTTP Concealed Authentication', a single 0x00 separator byte, and the 32-byte Signature Input from the key exporter output. This construction mirrors TLS 1.3 CertificateVerify to prevent cross-protocol key misuse.
IANA registered 'Concealed-Auth-Export' as a permanent HTTP field name in the HTTP Field Name Registry (https://www.iana.org/assignments/http-fields), with Structured Type 'Item', referencing RFC 9729.
IANA registered 'Concealed' in the HTTP Authentication Schemes registry (https://www.iana.org/assignments/http-authschemes), referencing RFC 9729.
IANA registered 'EXPORTER-HTTP-Concealed-Authentication' in the TLS Exporter Labels registry (https://www.iana.org/assignments/tls-parameters) with DTLS-OK: N and Recommended: Y, referencing RFC 9729.
Authentication asymmetric keys used for the Concealed HTTP authentication scheme MUST NOT be reused in other protocols. Reusing keys could undermine security guarantees even though the signed data includes a static prefix to mitigate cross-protocol attacks.
Authentication proofs are not bound to individual HTTP requests; proofs on the same connection are identical, enabling replay of the Authorization header across multiplexed security contexts. Client implementations that multiplex different security contexts over a single HTTP connection must ensure those contexts cannot read each other's header fields.
Freshness is provided by the TLS key exporter and thus can be as old as the underlying TLS connection. Servers requiring better freshness can force clients to create new connections, e.g., using the HTTP/3 GOAWAY frame.
Origins can link requests that use the same key, enabling user tracking within a single origin. Requests are not linkable across origins if per-origin keys are used.
The 48-byte key exporter output is split into two fields: Signature Input (first 32 bytes / 256 bits) which is included in the signed data, and Verification (next 16 bytes / 128 bits) which is transmitted to the server via the 'v' parameter to confirm correct exporter output.
The TLS key exporter context encodes: Signature Algorithm (16-bit), Key ID (variable-length integer prefixed), Public Key (variable-length integer prefixed), Scheme (variable-length integer prefixed), Host (variable-length integer prefixed), Port (16-bit network byte order), and Realm (variable-length integer prefixed). Length fields use QUIC variable-length integer encoding and MUST be encoded in the minimum number of bytes.