Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms
updated by
Extracted elements (30)
SCRAM intentionally omits security layer negotiation (confidentiality/integrity). It is designed to be used with an external security layer such as TLS or SSH, with optional channel binding to that layer, rather than providing its own.
The Hi() function is essentially PBKDF2 with HMAC as the PRF and dkLen equal to the HMAC output length. The iteration count 'i' is deliberately configurable and recommended to increase over time to raise the cost of offline attacks as hardware improves.
The server stores only StoredKey = H(ClientKey) and ServerKey rather than the plaintext password or SaltedPassword. This means the stored authentication information is not sufficient by itself to impersonate the client, and a server compromise does not directly yield impersonation capability.
SCRAM conforms to the GS2 bridge (RFC 5801) between SASL and GSS-API, defining both a SASL mechanism and a GSS-API mechanism. When used as a GSS-API mechanism, the GS2 header and channel binding data are excluded from the first message, and the RFC 2743 Section 3.1 initial context token header is prepended instead.
Before sending the username to the server, the client SHOULD prepare it using the SASLprep profile of stringprep treating it as a query string; if preparation fails or yields an empty string, the client SHOULD abort the exchange.
Both the username and the password MUST be encoded in UTF-8. Implementations MUST either implement SASLprep or disallow use of non-US-ASCII Unicode codepoints.
For interoperability, all SCRAM clients and servers MUST implement the SCRAM-SHA-1 authentication mechanism using the SHA-1 hash function as defined in RFC 3174.
For SCRAM-SHA-1/SCRAM-SHA-1-PLUS, servers SHOULD announce a hash iteration-count of at least 4096.
If the channel binding flag is 'y' and the server supports channel binding, the server MUST fail authentication, as this indicates a potential downgrade attack.
If the channel binding flag was 'p' and the server does not support the indicated channel binding type, the server MUST fail authentication.
If the ServerSignature computed by the client does not match the value sent by the server, the client MUST consider the authentication exchange unsuccessful and may need to drop the connection.
Mandatory extensions sent by one peer but not understood by the other MUST cause authentication failure; unknown optional extensions MUST be ignored upon receipt.
Servers MUST implement the 'tls-unique' channel binding type if they implement any channel binding; clients SHOULD implement 'tls-unique' as well.
The characters ',' and '=' in usernames are sent as '=2C' and '=3D' respectively. If the server receives a username containing '=' not followed by '2C' or '3D', the server MUST fail the authentication.
The client MUST verify that the initial part of the nonce used in subsequent messages is the same as the nonce it initially specified; the server MUST verify that the nonce sent by the client in the second message matches the one sent by the server in its first message.
The presence of the 'm' attribute (reserved for mandatory extensions) in a client or server message MUST cause authentication failure when parsed by the other end.
The server MUST always validate the client's 'c=' field by constructing the expected value and checking that it matches.
Upon receipt of the username, the server MUST either prepare it using SASLprep or be prepared to do SASLprep-aware comparisons and lookups; regardless, the server MUST use the username as received (unprepared) in hash calculations.
SCRAM mechanism names take the form 'SCRAM-<HASH>' and optionally 'SCRAM-<HASH>-PLUS' for channel-binding variants. SASL mechanism names are limited to 20 octets, allowing hash names up to 9 octets long.
The gs2-cbind-flag signals channel binding intent: 'n' = client does not support channel binding; 'y' = client supports it but believes server does not; 'p=<type>' = client requires channel binding of the named type. The flag must be the first element of the client-first-message.
The SCRAM algorithm derives: SaltedPassword = Hi(Normalize(password), salt, i); ClientKey = HMAC(SaltedPassword, "Client Key"); StoredKey = H(ClientKey); ClientProof = ClientKey XOR HMAC(StoredKey, AuthMessage); ServerKey = HMAC(SaltedPassword, "Server Key"); ServerSignature = HMAC(ServerKey, AuthMessage). The server stores only StoredKey and ServerKey.
IANA registered the SCRAM-* family of SASL mechanisms, SCRAM-SHA-1, and SCRAM-SHA-1-PLUS in the SASL Mechanism registry. New SCRAM-SASL mechanisms MUST be explicitly registered via IETF Review. A GSS-API OID for SCRAM-SHA-1 (1.3.6.1.5.5.14) was also assigned.
A hostile server can perform a computational denial-of-service attack on clients by advertising a very large iteration count value.
If authentication information is stolen from the database, an attacker who also eavesdrops on or impersonates a server can impersonate the user to all servers using the same hash function, password, iteration count, and salt. Using randomly generated salts is therefore critical.
SCRAM's channel binding 'y' flag mechanism detects downgrade attacks on mechanism negotiation (e.g., an attacker stripping the '-PLUS' suffix from advertised mechanisms), causing authentication to fail rather than silently proceeding over an unbound channel.
Without a strong security layer (e.g., TLS with confidentiality), a passive eavesdropper can gather sufficient information to mount an offline dictionary or brute-force attack to recover the user's password. The iteration count and external encryption layer are the primary mitigations.
The client-final-message consists of: 'c=' (base64-encoded GS2 header + optional channel binding data), 'r=' (complete nonce), optional extensions, and 'p=' (base64-encoded ClientProof).
The client-first-message consists of a GS2 header (gs2-cbind-flag ',' optional-authzid ',') followed by an optional reserved-mext, the 'n=' username attribute, and the 'r=' client nonce (printable ASCII excluding ','). Example: 'n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL'.
The server-final-message is either a 'v=' (base64-encoded ServerSignature) on success or an 'e=' (server-error-value) on failure, optionally followed by extensions. The server-final-message is OPTIONAL on authentication failure.
The server-first-message contains: optional reserved-mext, 'r=' (client nonce + server nonce), 's=' (base64-encoded salt), and 'i=' (positive iteration count). Example: 'r=fyko+...,s=QSXCR+Q6sek8bf92,i=4096'.