13.1 Challenge and response
A SIP server must know who sends a request before it accepts a registration or connects a call. SIP does not send the password to prove this. It uses digest authentication, the same method as HTTP.
The idea is simple:
- The server sends a challengechallenge. A 401 or 407 response that asks the UAC for credentials.: a random value called a noncenonce. A one-time value from the server. It stops an attacker from reusing an old response..
- The client mixes the nonce with the password and makes a hash.
- The client sends only the hash, called the digest responsedigest response. The final hash that proves the UAC knows the password..
- The server makes the same hash with its copy of the password. If the two hashes are equal, the client knows the password.
An attacker who captures the request sees the hash, but cannot get the password back from it. The nonce changes, so an old hash does not work again.
13.2 Two challenges: 401 and 407
SIP has two challenge responses. They work the same way, but they use different headers. A trace with the wrong pair is a common source of failures.
| 401 Unauthorized | 407 Proxy Authentication Required | |
|---|---|---|
| Who sends it | A registrar or a UAS | A proxy |
| Challenge header | WWW-Authenticate |
Proxy-Authenticate |
| Credentials header | Authorization |
Proxy-Authorization |
| Typical request | REGISTER | INVITE, and other requests through a proxy |
| RFC 3261 section | §22.2 | §22.3 |
“If no credentials (in the Authorization header field) are provided in the request, the UAS can challenge the originator to provide credentials by rejecting the request with a 401 (Unauthorized) status code.”Read the section ↗
“The proxy MUST populate the 407 (Proxy Authentication Required) message with a Proxy-Authenticate header field value applicable to the proxy for the requested resource.”Read the section ↗
13.3 The parameters
A challenge and its credentials carry these parameters. The calculator in 13.6 uses all of them.
| Parameter | In | Meaning |
|---|---|---|
realm |
challenge, credentials | The protection domain. It tells the UAC which username and password to use. |
nonce |
challenge, credentials | A one-time value from the server. The UAC copies it back. |
qop |
challenge, credentials | Quality of protection. Use auth. When the challenge has qop, the credentials must have it too. |
algorithm |
challenge, credentials | MD5 (default), or SHA-256 and SHA-512-256 from RFC 8760. |
opaque |
challenge, credentials | Optional server data. The UAC copies it back unchanged. |
stale |
challenge | true means the nonce is old but the password was correct. The UAC retries without asking the user. |
username |
credentials | The authentication username. It is not always the user part of From. |
uri |
credentials | The digest URI: the Request-URI of the request. It must be in quotation marks. |
response |
credentials | The digest response: the final hash. |
nc, cnonce |
credentials | The nonce count and a client nonce. Both are needed when qop is present. |
“However, servers MUST always send a "qop" parameter in WWW-Authenticate and Proxy-Authenticate header field values. If a client receives a "qop" parameter in a challenge header field, it MUST send the "qop" parameter in any resulting authorization header field.”Read the section ↗
13.4 The REGISTER challenge
Alice turns on her phone. The phone sends REGISTER to the Registrar for atlanta.example. Step through the flow, then select a line in the inspector to see what it means. The inspector also marks every line that changed since the previous message of the same kind.
Call flow · REGISTER with 401
REGISTER with a 401 challenge
- SIP
Alice asks the Registrar to bind the AOR to a Contact. The request has no credentials.
All steps as text
- Alice → Registrar: REGISTER. Alice asks the Registrar to bind the AOR to a Contact. The request has no credentials.
- Registrar → Alice: 401 Unauthorized. The Registrar rejects the request with 401. WWW-Authenticate carries the realm and a fresh nonce.
- Alice → Registrar: REGISTER (credentials). Alice sends REGISTER again with an Authorization header. CSeq is now 2 and the branch is new.
- Registrar → Alice: 200 OK. The Registrar calculates the same response value and stores the binding. The 200 OK lists the active Contact.
Look at F3 and compare it with F1:
- CSeq goes from
1 REGISTERto2 REGISTER. The retry is a new request. - The Via branch is new. The retry is a new transaction.
- Call-ID and the From tag do not change. The Registrar can link the two requests.
- The Authorization header is new. It is the only proof of identity.
“When a UAC resubmits a request with its credentials after receiving a 401 (Unauthorized) or 407 (Proxy Authentication Required) response, it MUST increment the CSeq header field value as it would normally when sending an updated request.”Read the section ↗
13.5 The INVITE challenge, step by step
Now Alice calls Bob. Proxy A, the outbound proxy for atlanta.example, wants to know who Alice is before it connects the call. This flow follows RFC 3665 §3.2, with two corrections that RFC 3261 requires (see the note after the flow).
Scroll through the story. The ladder follows the text.
F1 · INVITE
Alice sends an INVITE for sip:bob@biloxi.example. A pre-loaded Route header sends it to Proxy A first. It has no credentials yet.
F2 · 407
Proxy A rejects the INVITE with 407 Proxy Authentication Required. The Proxy-Authenticate header carries the realm atlanta.example, a fresh nonce, and qop="auth".
A 407 is a final response. It ends the INVITE transaction on the Proxy A side, but only after an ACK arrives.
F3 · ACK
Alice sends ACK for the 407. This ACK belongs to the first INVITE transaction, so it reuses the INVITE branch and the CSeq number 1. Only the method changes to ACK.
F4 · INVITE + credentials
Alice sends a new INVITE with Proxy-Authorization. Three things change: CSeq is now 2, the branch is new, and the credentials are added. Call-ID and the From tag stay the same.
F5 · 100 Trying
Proxy A checks the digest response and accepts it. The 100 Trying tells Alice to stop retransmitting the INVITE. A 100 Trying never travels further than one hop.
F6 · forward
Proxy A forwards the INVITE to Proxy B. It adds its own Via and a Record-Route, decrements Max-Forwards, removes its own Route entry, and consumes the Proxy-Authorization for its realm.
F8 · Proxy B → Bob
Proxy B finds Bob’s Contact in its location service and forwards the INVITE there. The Request-URI is now Bob’s Contact address. Now there are three Via headers, one for each hop.
F9 · 180 Ringing
Bob’s phone rings. The 180 Ringing adds a To tag, which creates an early dialog. Each proxy removes its own Via on the way back.
F12 · 200 OK
Bob answers. The 200 OK carries Bob’s SDP answer and confirms the dialog. Both Record-Route headers travel back to Alice.
F15 · ACK for 2xx
Alice sends ACK for the 200 OK. This ACK is a new transaction with a new branch. It follows the route set, and it copies the Proxy-Authorization from the INVITE.
F18 · media
The call is up. RTP audio flows directly between Alice and Bob. Proxy A and Proxy B see only the signaling.
18Audio flows directly between Alice and Bob. The media does not pass through the proxies.
Explore every message
The same flow, with the full inspector. Use ← and → on your keyboard, or select any arrow.
Call flow · INVITE with 407 through two proxies
INVITE with a 407 challenge through two proxies
- SIP
- RTP media
Alice sends an INVITE to Proxy A, the outbound proxy. It has no credentials.
All steps as text
- Alice → Proxy A: INVITE. Alice sends an INVITE to Proxy A, the outbound proxy. It has no credentials.
- Proxy A → Alice: 407 Proxy Auth Required. Proxy A rejects the INVITE with 407. Proxy-Authenticate carries the realm and a nonce.
- Alice → Proxy A: ACK. Alice sends ACK for the 407. The ACK reuses the INVITE branch, so it completes the first transaction.
- Alice → Proxy A: INVITE (credentials). Alice sends a new INVITE with Proxy-Authorization. CSeq is now 2 and the branch is new.
- Proxy A → Alice: 100 Trying. Proxy A accepts the credentials. The 100 Trying stops the INVITE retransmissions from Alice.
- Proxy A → Proxy B: INVITE. Proxy A consumes the credentials for its realm. It adds Via and Record-Route, then forwards the INVITE.
- Proxy B → Proxy A: 100 Trying. Proxy B answers with 100 Trying. A 100 Trying travels one hop only.
- Proxy B → Bob: INVITE. Proxy B finds Bob's Contact in its location service. It adds Via and Record-Route.
- Bob → Proxy B: 180 Ringing. Bob's phone rings. The 180 adds a To tag, which creates an early dialog.
- Proxy B → Proxy A: 180 Ringing. Proxy B removes its own Via and forwards the 180.
- Proxy A → Alice: 180 Ringing. Proxy A removes its own Via and forwards the 180. Alice plays ringback.
- Bob → Proxy B: 200 OK. Bob answers. The 200 OK carries the SDP answer and confirms the dialog.
- Proxy B → Proxy A: 200 OK. Proxy B removes its own Via and forwards the 200 OK.
- Proxy A → Alice: 200 OK. Alice receives the 200 OK. Alice reverses the Record-Route list to build the route set.
- Alice → Proxy A: ACK (new branch). Alice sends ACK for the 200 OK. This ACK is a new transaction, and it copies the INVITE credentials.
- Proxy A → Proxy B: ACK. Proxy A removes its own Route entry and the credentials. It forwards the ACK to Proxy B.
- Proxy B → Bob: ACK. Proxy B removes its own Route entry. It forwards the ACK to Bob's Contact.
- Alice → Bob: RTP audio. Audio flows directly between Alice and Bob. The media does not pass through the proxies.
“UACs creating an ACK message will duplicate all of the Authorization and Proxy-Authorization header field values that appeared in the INVITE to which the ACK corresponds. Servers MUST NOT attempt to challenge an ACK.”Read the section ↗
13.6 The calculation
The digest response is three hashes. For MD5 with qop=auth:
HA1 = MD5( username : realm : password )
HA2 = MD5( method : digest-uri )
response = MD5( HA1 : nonce : nc : cnonce : qop : HA2 )
The calculator starts with the values from F4 of the INVITE flow. Change any value and watch the response change. Point at a field to see where it is used.
HA1 = MD5( username : realm : password )
alice:atlanta.example:••••••••••••
→ …
A server can store HA1 instead of the password.
HA2 = MD5( method : digest URI )
INVITE:sip:bob@biloxi.example
→ …
response = MD5( HA1 : nonce : nc : cnonce : qop : HA2 )
…:f84f1cec41e6cbe5aea9c8e88d359:00000001:6a4b1c2d:auth:…
→ …
The header Alice sends
Proxy-Authorization: Digest username="alice", realm="atlanta.example", nonce="f84f1cec41e6cbe5aea9c8e88d359", uri="sip:bob@biloxi.example", response="…", algorithm=MD5, qop=auth, nc=00000001, cnonce="6a4b1c2d"
Things to try:
- Change the method to
ACK. The response changes. An ACK copies the INVITE credentials unchanged, so its response was calculated withINVITE, notACK. RFC 3261 tells the server to accept it anyway. - Change one letter of the password. Every hash after HA1 changes completely.
- Switch the algorithm to SHA-256. The response is longer: 64 hexadecimal digits.
13.7 Nonces, nonce count, and stale
- The server chooses a new nonce for each challenge. Many servers put a timestamp in it, so they can reject old nonces.
- The client can reuse a nonce for more requests. Each time, it increments nc (
00000001,00000002, …). A server that remembers the last nc can detect a replayed request. - When a nonce is too old, the server sends a new challenge with
stale=true. This means “the password was correct, the nonce was not”. The client retries at once and does not ask the user for the password again.
13.8 Algorithms: MD5, SHA-256, SHA-512-256
RFC 3261 uses MD5 only. RFC 8760 adds SHA-256 and SHA-512-256 for SIP. A server can offer more than one algorithm by sending more than one challenge header for the same realm. It puts them in order of preference.
“The UAS MUST add these header fields to the response in the order in which it would prefer to see them used, starting with the most preferred algorithm at the top.”Read the section ↗
“When the UAC receives a response with multiple WWW-Authenticate/Proxy-Authenticate header fields with the same realm, it SHOULD use the topmost header field that it supports unless a local policy dictates otherwise.”Read the section ↗
Many devices still support only MD5. If a server offers only SHA-256 and the phone supports only MD5, the phone cannot answer the challenge, and registration fails.
13.9 More than one challenge
A request can pass through more than one proxy that wants credentials. Proxy A can accept Alice’s credentials, and then Proxy B can challenge too. Proxy A forwards that 407 to Alice. Alice retries with two Proxy-Authorization headers, one for each realm. Each proxy uses only the credentials with its own realm.
“When multiple proxies are used in a chain, a Proxy-Authorization header field value MUST NOT be consumed by any proxy whose realm does not match the "realm" parameter specified in that value.”Read the section ↗
“Proxies MUST NOT add values to the Proxy-Authorization header field.”Read the section ↗
Common mistakes
No ACK for the 407
The UAC sends the new INVITE but never ACKs the 407. The 407 is a final response to an INVITE, so it needs an ACK, like any other final response. Over UDP, Proxy A retransmits the 407 until Timer H gives up after 32 seconds.
Broken
Broken: no ACK for the 407
- SIP
- ⚠Problem
Alice sends an INVITE. It has no credentials.
All steps as text
- Alice → Proxy A: INVITE. Alice sends an INVITE. It has no credentials.
- Proxy A → Alice: 407 Proxy Auth Required. Proxy A rejects the INVITE with 407 and a challenge.
- Alice → Proxy A: INVITE (credentials). Alice sends the new INVITE at once. The first transaction never receives an ACK. Problem: No ACK for the 407. The INVITE server transaction stays in the Completed state.
- Proxy A → Alice: 100 Trying. Proxy A accepts the credentials and continues with the call.
- Proxy A → Alice: 407 (retransmission). Timer G fires, so Proxy A sends the same 407 again. Problem: Proxy A retransmits the 407 because no ACK arrived.
- Proxy A → Alice: 407 (retransmission). Proxy A keeps retransmitting. Timer H stops the transaction after 64×T1, which is 32 seconds. Problem: Wasted retransmissions, and the proxy reports a transaction failure.
Fix: ACK every final response to an INVITE, including 401, 407, 486, and 487.
ACK for the 407 with a new branch
The UAC sends the ACK, but with a new branch value. The proxy matches requests to transactions by the branch, so it cannot match this ACK to the INVITE. It keeps retransmitting the 407.
Broken
Broken: ACK for the 407 with a new branch
- SIP
- ⚠Problem
Alice sends an INVITE. It has no credentials.
All steps as text
- Alice → Proxy A: INVITE. Alice sends an INVITE. It has no credentials.
- Proxy A → Alice: 407 Proxy Auth Required. Proxy A rejects the INVITE with 407 and a challenge.
- Alice → Proxy A: ACK (new branch). Alice sends ACK with a new branch value. Problem: The branch does not match the INVITE. Proxy A cannot match this ACK to the transaction.
- Alice → Proxy A: INVITE (credentials). Alice sends a new INVITE with Proxy-Authorization. CSeq is 2 and the branch is new.
- Proxy A → Alice: 100 Trying. Proxy A accepts the credentials and continues with the call.
- Proxy A → Alice: 407 (retransmission). Timer G fires, so Proxy A sends the same 407 again. Problem: Proxy A retransmits the 407 because it has no matching ACK.
- Alice → Proxy A: ACK (new branch). Alice ACKs the retransmitted 407 with the same wrong branch. The loop continues until Timer H fires. Problem: Proxy A never matches these ACKs, so Timer H ends the transaction with a failure.
Fix: An ACK for a non-2xx response uses the branch and CSeq number of the INVITE. Only an ACK for a 2xx gets a new branch.
“The ACK MUST contain a single Via header field, and this MUST be equal to the top Via header field of the original request. The CSeq header field in the ACK MUST contain the same value for the sequence number as was present in the original request, but the method parameter MUST be equal to "ACK".”Read the section ↗
The retry keeps the same CSeq
The UAC adds credentials but sends CSeq 1 again. This breaks a MUST in RFC 3261 §22.2. What happens next depends on the server: some accept the request, some reject it. A failure that depends on the server is hard to find.
Fix: A retry with credentials is a new request. Increment CSeq by one, and keep Call-ID and the From tag.
The wrong username or realm
Many SIP trunks use an authentication username that is not the user part of the From URI. A phone that uses the From user as the digest username calculates the wrong HA1. The server answers every retry with a new 401 or 407: an authentication loop.
Fix: Configure the authentication username and the realm separately. In a trace, compare the username and realm in the credentials with the values the provider gave you.
The digest URI is not the Request-URI
HA2 uses the uri parameter. Some clients put the To URI or the AOR in uri, but send the request to another Request-URI. Many servers check that the two match, and RFC 3261 allows that check.
“Therefore, in SIP, a server MAY check that the Request-URI in the Authorization header field value corresponds to a user for whom the server is willing to accept forwarded or direct requests, but it is not necessarily a failure if the two fields are not equivalent.”Read the section ↗
Fix: Put the Request-URI, exactly as sent, in uri, and use the same value in HA2.
Challenging ACK or CANCEL
A server sends 401 or 407 to an ACK or a CANCEL. ACK has no response, and a CANCEL cannot be sent again, so the UAC cannot answer the challenge. The call cannot end cleanly.
“Although the CANCEL method does take a response (a 2xx), servers MUST NOT attempt to challenge CANCEL requests since these requests cannot be resubmitted.”Read the section ↗
Fix: Never challenge ACK or CANCEL. Accept an ACK with the credentials of its INVITE, and accept a CANCEL from the hop that sent the INVITE.
Summary
- Digest authentication proves that the UAC knows the password. The password is never sent.
- 401 +
WWW-Authenticate/Authorizationcomes from a registrar or UAS. 407 +Proxy-Authenticate/Proxy-Authorizationcomes from a proxy. - After a challenge, the UAC sends a new request: CSeq + 1, a new branch, the same Call-ID and From tag, and the credentials.
- Every final response to an INVITE needs an ACK. The ACK for a 401 or 407 reuses the INVITE branch.
- response = H(HA1 : nonce : nc : cnonce : qop : HA2), with HA1 = H(username : realm : password) and HA2 = H(method : uri).