Table of Contents
auth_checks_register
(flags)
auth_checks_no_dlg
(flags)
auth_checks_in_dlg
(flags)
qop
(string)
nonce_count
(boolean)
one_time_nonce
(boolean)
nid_pool_no
(integer)
nc_array_size
(integer)
nc_array_order
(integer)
otn_in_flight_no
(integer)
otn_in_flight_order
(integer)
secret
(string)
nonce_expire
(integer)
nonce_auth_max_drift
(integer)
force_stateless_reply
(boolean)
realm_prefix
(string)
use_domain
(boolean)
algorithm
(string)
add_authinfo_hdr
(boolean)
consume_credentials()
has_credentials(realm)
www_challenge(realm, flags)
proxy_challenge(realm, flags)
auth_challenge(realm, flags)
pv_www_authenticate(realm, passwd, flags [, method])
pv_proxy_authenticate(realm, passwd, flags)
pv_auth_check(realm, passwd, flags, checks)
auth_get_www_authenticate(realm, flags, pvdest)
List of Examples
auth_checks_register
module
parameterpv_www_authenticate
usageTable of Contents
auth_checks_register
(flags)
auth_checks_no_dlg
(flags)
auth_checks_in_dlg
(flags)
qop
(string)
nonce_count
(boolean)
one_time_nonce
(boolean)
nid_pool_no
(integer)
nc_array_size
(integer)
nc_array_order
(integer)
otn_in_flight_no
(integer)
otn_in_flight_order
(integer)
secret
(string)
nonce_expire
(integer)
nonce_auth_max_drift
(integer)
force_stateless_reply
(boolean)
realm_prefix
(string)
use_domain
(boolean)
algorithm
(string)
add_authinfo_hdr
(boolean)
consume_credentials()
has_credentials(realm)
www_challenge(realm, flags)
proxy_challenge(realm, flags)
auth_challenge(realm, flags)
pv_www_authenticate(realm, passwd, flags [, method])
pv_proxy_authenticate(realm, passwd, flags)
pv_auth_check(realm, passwd, flags, checks)
auth_get_www_authenticate(realm, flags, pvdest)
This is a generic module that itself doesn't provide all functions necessary for authentication but provides functions that are needed by all other authentication related modules (so called authentication backends).
We decided to divide the authentication code into several modules because there are now more than one backends (currently database authentication and radius are supported). This allows us to create separate packages so users can install and load only the required functionality. This also allows us to avoid unnecessary dependencies in the binary packages.
These three module parameters control which optional integrity
checks will be performed on the SIP message carrying digest response
during SIP MD5 digest authentication. auth_check_register
controls integrity checks to be performed on REGISTER messages,
auth_checks_no_dlg
controls which optional
integrity checks will be performed on SIP requests that have no To
header field or no To tag (in other words the requests either
establishing or outside dialogs).
auth_checks_in_dlg
controls which
integrity checks will be performed on SIP requests within dialogs,
such as BYE or re-INVITE. The default value for all three parameters
is 0 (old behaviour, no extra checks). The set of integrity checks
that can be performed on REGISTERs is typically different from sets of
integrity checks that can be performed for other SIP request types,
hence we have three independent module parameters.
Without the extra checks the nonce will protect only against expired values. Some reply attacks are still possible in the expire "window". A possible workaround is to always force qop authentication and always check the uri from the authorization header, but this would not work if an upstream proxy rewrites the uri and it will also not work with a lot of UA implementations.
In this case the nonce value will be used only to hold
the expire time (see nonce_expire
) and an MD5
over it and some secret (the MD5 is used to make sure that nobody
tampers with the nonce expire time).
When the extra checks are enabled, the nonce will include an extra MD5 over the selected part/parts of the message (see below) and some other secret. This will be used to check if the selected part of the message is the same when an UA tries to reuse the nonce, thus protecting or severely limiting reply attacks.
The possible flag values for all three parameters are:
1 for checking if the message URI changed (uses the whole URI)
2 for checking the callid
4 for checking the From tag
8 for checking the source IP address (see nonce.h).
As an example setting auth_checks_register
to 3
would check if the callid or the request uri changed from the REGISTER
message for which the original nonce was generated (this would allow nonce reuse only
within the same UA and for the expire time). Note that enabling
the extra checks will limit nonce caching by UAs, requiring extra
challenges and roundtrips, but will provide much better protection.
Do not enable the from tag check (4) for REGISTERs
(auth_checks_register
) and out-of-dialog messages
(auth_checks_no_dlg
) unless you are sure that all
your user agents do not change the from tag when challenged. Some
user agents will also change the callid when the challenged request
is not in-dialog, so avoid enabling the callid check (2) for
messages that are not part of a dialog
(auth_checks_no_dlg
).
In some rare case this will also have to be done for REGISTERs.
When the secret
parameter is set and the extra
checks are enabled, the first half of the secret
will be used for the expire time MD5 and the other half for the extra
checks MD5, so make sure you have a long secret (32 chars or longer are
recommended).
Example 1.1. Setting the auth_checks_register
module
parameter
... # For REGISTER requests we hash the Request-URI, Call-ID, and source IP of the # request into the nonce string. This ensures that the generated credentials # cannot be used with another registrar, user agent with another source IP # address or Call-ID. Note that user agents that change Call-ID with every # REGISTER message will not be able to register if you enable this. modparam("auth", "auth_checks_register", 11) # For dialog-establishing requests (such as the original INVITE, OPTIONS, etc) # we hash the Request-URI and source IP. Hashing Call-ID and From tags takes # some extra precaution, because these checks could render some UA unusable. modparam("auth", "auth_checks_no_dlg", 9) # For mid-dialog requests, such as re-INVITE, we can hash source IP and # Request-URI just like in the previous case. In addition to that we can hash # Call-ID and From tag because these are fixed within a dialog and are # guaranteed not to change. This settings effectively restrict the usage of # generated credentials to a single user agent within a single dialog. modparam("auth", "auth_checks_in_dlg", 15) ...
If set, enable qop for challenges: each challenge
will include a qop parameter. This is the
recommended way, but some older non rfc3261 compliant UAs might get
confused and might not authenticate properly if qop
is enabled.
Enabling qop
together with
nonce_count
will provide extra-security
(protection against replay attacks) while still allowing
credentials caching at the UA side and thus not compromising
performance.
The possible values are: "auth", "auth-int" and "" (unset).
The default value is not-set ("").
See also:
nonce_count
.
If enabled the received nc value is remembered and checked against the older value (for a successful authentication the received nc must be greater then the previously received one, see rfc2617 for more details). This will provide protection against replay attacks while still allowing credentials caching at the UA side.
It depends on qop
being enabled (if
qop
is not enabled, the challenges won't include
qop and so the UA will probably not include the
qop or nc parameters in its
response).
If a response doesn't include qop or
nc (for example obsolete UAs that don't support
them) the response will be checked according to the other enabled
nonce checks, in this order: one_time_nonce and auth_check_*.
If a response includes nc only the normal
nonce_expire
checks and the
nonce_count
checks will be performed, all
the other checks will be ignored.
The nonce_count
checks work by tracking a limited
number of nonces. The maximum number of tracked nonces is set using
the nc_array_size
or
nc_array_order
parameters. If this number is
exceeded, older entries will be overwritten. As long as the maximum
rate of challengeable messages per average response time is lower then
nc_array_size
, the nonce_count
checks should work flawlessly. For optimum performance (maximum reuse
of cache credentials) nc_array_size
divided by
nid_pool_no
should be lower then the message rate
multiplied by the desired nonce_expire
.
The maximum accepted nc value is 255. If nc becomes greater then this, the nonce will be considered stale and the UA will be re-challenged.
Note: nonce_count
should be
enabled only in stateful mode (a transaction should be created prior
to the authentication check to absorb possible retransmissions and all
the replies should be sent statefully, using
t_reply()
).
If nonce_count
and the authentication checks are
used in the stateless mode then all retransmissions will be
challenged.
The default value is 0 (off).
See also:
qop
,
nc_array_size
,
nc_array_order
,
nid_pool_no
,
nonce_expire
.
one_time_nonce
.
Example 1.3. nonce_count example
... modparam("auth", "nonce_count", 1) # enable nonce_count support modparam("auth", "qop", "auth") # enable qop=auth .... route{ ... # go stateful and catch retransmissions if (!t_newtran()) { xlog("L_NOTICE", "Failed to create new transaction\n"); drop; }; if (method=="REGISTER"){ if (!www_authenticate("test", "credentials")){ # reply must be sent with t_reply because the # transaction is already created at this point # (we are in "stateful" mode) if ($? == -2){ t_reply("500", "Internal Server Error"); }else if ($? == -3){ t_reply("400", "Bad Request"); }else{ if ($digest_challenge) append_to_reply("%$digest_challenge"); t_reply("401", "Unauthorized"); } drop; } if (!save_noreply("location")) { t_reply("400", "Invalid REGISTER Request"); drop; } append_to_reply("%$contact"); t_reply("$code", "$reason"); # no %, avps are used directly drop; }else{ if (!proxy_authenticate("my_realm", "credentials")){ if ($? == -2){ t_reply("500", "Internal Server Error"); }else if ($? == -3){ t_reply("400", "Bad Request"); }else{ if ($digest_challenge) append_to_reply("%$digest_challenge"); t_reply("401", "Unauthorized"); } drop; } } ...
If set to 1 nonce reuse is disabled: each nonce is allowed only once,
in the first response to a challenge. All the messages will be
challenged, even retransmissions. Stateful mode should be used, to
catch retransmissions before the authentication checks (using
t_newtran()
before the authentication checks
and sending all the replies with t_reply()
).
one_time_nonce
provides enhanced replay protections
at the cost of invalidating UA side credentials caching, challenging
every message (and thus generating extra messages and extra
round-trips) and requiring stateful mode. In general
qop
and nonce_count
should
be prefered (if possible) with fallback to
auth_checks_*
. Due to the disadvantages listed
above, one_time_nonce
should be used only if the
extra checks provided by auth_checks_register
,
auth_checks_no_dlg
and
auth_checks_in_dlg
are deemed insufficient for a
specific setup.
Compared to nonce_count
,
one_time_nonce
provides the same protection, but at
a higher message cost. The only advantages are that it works with
user agents that do not support qop and
nc and that it uses less memory for the same
supported number of maximum in-flight nonces (by a factor of 8).
one_time_nonce
can be used as fallback from
nonce_count
, when the UA doesn't support
nc (it happens automatically when both of them
are enabled).
Like nonce_count
, one_time_nonce
works by tracking a limited number of nonces. The maximum number of
tracked nonces is set using the otn_in_flight_no
or
otn_in_flight_order
parameters. If this number is
exceeded, older entries will be overwritten. As long as the maximum
rate of challengeable messages per average response time is lower then
otn_in_flight_no
, the
one_time_nonce
checks should work flawlessly.
The default value is 0 (off).
See also:
otn_in_flight_no
,
otn_in_flight_order
,
nid_pool_no
and
nonce_count
.
Example 1.4. one_time_nonce example
... modparam("auth", "one_time_nonce", 1) # Note: stateful mode should be used, see the nonce_count example ...
Controls the number of partitions for the
nonce_count
and one_time_nonce
arrays (it's common to both of them to reduce the nonce size).
Instead of using single arrays for keeping nonce state, these arrays
can be divided into more partitions. Each Kamailio process is assigned to
one of these partitions, allowing for higher concurrency on multi-CPU
machines. Besides increasing performance, increasing
nid_pool_no
has also a negative effect: it could
decrease the maximum supported in-flight nonces in certain conditions.
In the worst case, when only one Kamailio process receives most of the
traffic (e.g. very busy tcp connection between two proxies), the
in-flight nonces could be limited to the array size
(nc_array_size
for nonce_count
or otn_in_flight_no
for
one_time_nonce
) divided by the partitions number
(nid_pool_no
). However for normal traffic, when
the process receiving a message is either random or chosen in
a round-robin fashion the maximum in-flight nonces number will be
very little influenced by nid_pool_no
(the
messages will be close to equally distributed to processes using
different partitions).
nid_pool_no
value should be one of: 1, 2, 4, 8, 16,
32 or 64 (the maximum value is 64 and all values should be of the
form 2^k or else they will be rounded down to 2^k).
The default value is 1.
See also:
nonce_count
,
one_time_nonce
,
nc_array_size
and
otn_in_flight_no
.
Maximum number of in-flight nonces for nonce_count
.
It represents the maximum nonces for which state will be kept. When
this number is exceeded, state for the older nonces will be
discarded to make space for new ones (see
nonce_count
for more details).
The value should be of the form 2^k. If it's not it will be rounded
down to 2^k (for example a value of 1000000 will be rounded down to
2^19=524288). nc_array_order
can be used to
directly specify the power of 2 (e.g.
nc_array_order
set to 20 is equivalent to
nc_array_size
set to 1048576).
The memory used to keep the nonce state will be
nc_array_size
in bytes.
The default value is 1048576 (1M in-flight nonces, using 1Mb memory).
See also:
nonce_count
and
nid_pool_no
.
Equivalent to nc_array_size
, but instead of
directly specifying the size, its value is the power at which 2 should
be raised (log2(nc_array_size
)).
nc_array_size
= 2^nc_array_order
.
For more details see nc_array_size
.
The default value is 20 (1M in-flight nonces, using 1Mb memory).
See also:
nonce_count
,
nc_array_size
and
nid_pool_no
.
Maximum number of in-flight nonces for
one_time_nonce
. It represents the maximum number
of nonces remembered for the one-time-nonce check. When this
number is exceeded, information about older nonces will be discarded
and overwritten with information about the new generated ones (see
one_time_nonce
for more details).
The value should be of the form 2^k. If it's not it will be rounded
down to 2^k (for example a value of 1000000 will be rounded down to
2^19=524288). otn_in_flight_no
can be used to
directly specify the power of 2 (e.g.
otn_in_flight_order
set to 19 is equivalent to
otn_in_fligh_number
set to 524288).
The memory used to keep the nonce information will be the
otn_in_flight_no
divided by 8 (only 1 bit of state
is kept per nonce).
The default value is 1048576 (1M in-flight nonces, using 128Kb memory).
See also:
one_time_nonce
and
nid_pool_no
.
Example 1.8. otn_in_flight_no example
... modparam("auth", "otn_in_flight_no", 8388608) # 8 Mb (1Mb memory) ...
Equivalent to otn_in_flight_no
, but instead of
directly specifying the size, its value is the power at which 2 should
be raised (log2(otn_in_flight_no
)).
otn_in_flight_no
=
2^otn_in_flight_order
.
For more details see otn_in_flight_order
.
The default value is 20 (1M in-flight nonces, using 128Kb memory).
See also:
one_time_nonce
,
otn_in_flight_no
and
nid_pool_no
.
Example 1.9. otn_in_flight_order example
... modparam("auth", "otn_in_flight_order", 23) # 8 Mb (1Mb memory) ...
Secret phrase used to calculate the nonce value used to challenge the client for authentication.
If you use multiple servers in your installation, and would like to authenticate on the second server against the nonce generated at the first one its necessary to explicitly set the secret to the same value on all servers. However, as the use of a shared (and fixed) secret as nonce is insecure, it is much better is to stay with the default. Any clients should send the authenticated request to the server that issued the challenge.
Default value is randomly generated string.
Example 1.10. Setting secret module parameter
... modparam("auth", "secret", "johndoessecretphrase") ...
Nonces have limited lifetime. After a given period of time nonces
will be considered invalid. This is to protect replay
attacks. Credentials containing a stale nonce will be not
authorized, but the user agent will be challenged again. This time
the challenge will contain stale
parameter which
will indicate to the client that it doesn't have to disturb user by
asking for username and password, it can recalculate credentials
using existing username and password.
The value is in seconds and default value is 300 seconds.
Example 1.11. nonce_expire example
... modparam("auth", "nonce_expire", 600) # Set nonce_expire to 600s ...
Maximum difference in seconds between a nonce creation time and the current time, if the nonce creation time appears to be in the future.
In some cases, like shortly after a system time backward adjustment
or when the current proxy is part of a cluster which is not
time-synchronized, it's possible to receive a nonce with creation time
in the future. In this case if the difference is greater then
nonce_auth_max_drift
seconds, consider the nonce
stale and re-challenge (otherwise after a dramatic time change
backwards, it might happen that some previously generated nonces will
be valid for too much time).
The default value is 3 seconds
See also: nonce_expire
.
Example 1.12. nonce_auth_max_drift example
... modparam("auth", "nonce_auth_max_drift", 1) # set max drift to 1 s ...
If set to 1, www_challenge()
and
proxy_challenge()
functions send reply statelessly no matter if transaction
exists or not. If set to 0 (default), reply is sent statefully
if transaction exists and statelessly otherwise.
Prefix to be automatically stripped from the realm. As an alternative to SRV records (not all SIP clients support SRV lookup), a subdomain of the master domain can be defined for SIP purposes (like sip.mydomain.net pointing to same IP address as the SRV record for mydomain.net). By ignoring the realm_prefix “sip.”, at authentication, sip.example.com will be equivalent to example.com .
Default value is empty string.
If set to 1, pv_auth_check()
uses
domain parts of the URIs to check user identity.
Configure hash algorithm used for digest authentication. Possible values are "MD5" or "SHA-256". If left empty MD5 is used. If specified, the specified algorithm is used and is also put in the 'algorithm' field of the challenge header.
Warning: SHA-256 hash values take twice the space of MD5 hash values. So a buffer overflow might occur if this option is used in combination with another auth_* module that does not allocate at least 65 bytes to store hash values. SHA-256 can safely be used with the module auth_db as it allocates 256 bytes to store HA1 values.
Should an Authentication-Info header be added on 200 OK responses? The Authentication-Info header offers mutual authentication. The server proves to the client that it knows the user's secret.
The header also includes the next nonce which may be used by the client in a future request. If one_time_nonce is enabled, a new nonce is calculated for the next nonce. Otherwise the current nonce is used for the next nonce.
The default value is 0 (no).
Example 1.17. add Authentication-Info header example
... modparam("auth", "add_authinfo_hdr", yes) ...
This function removes previously authorized credential headers from the
message being processed by the server. That means that the
downstream message will not contain credentials there were used by
this server. This ensures that the proxy will not reveal
information about credentials used to downstream elements and also
the message will be a little bit shorter. The function must be
called after www_authorize
,
proxy_authorize
,
www_authenticate
or
proxy_authenticate
.
Example 1.18. consume_credentials example
... if (www_authenticate("realm", "subscriber")) { consume_credentials(); } ...
This function returns true of the request has Authorization or Proxy-Authorization header with provided realm. The parameter can be string with pseudo-variables.
The function challenges a user agent. It will generate a WWW-Authorize header field containing a digest challenge, it will put the header field into a response generated from the request the server is processing and send the 401 reply. Upon reception of such a reply the user agent should compute credentials and retry the request. For more information regarding digest authentication see RFC2617. See module parameter force_stateless_reply regarding sending of the reply.
Meaning of the parameters is as follows:
realm - Realm is an opaque string that the user agent should present to the user so he can decide what username and password to use. Usually this is domain of the host the server is running on.
It must not be empty string “”. In case of REGISTER requests, the To header field domain (e.g., variable $td) can be used (because this header field represents the user being registered), for all other messages From header field domain can be used (e.g., variable $fd).
The string may contain pseudo variables.
flags - Value of this parameter can be a bitmask of following:
1 - build challenge header with qop=auth
2 - build challenge header with qop=auth-int
4 - do not send '500 Internal Server Error' reply automatically in failure cases (error code is returned to config)
16 - build challenge header with stale=true
This function can be used from REQUEST_ROUTE.
Example 1.20. www_challenge usage
... if (!www_authenticate("$td", "subscriber")) { www_challenge("$td", "1"); exit; } ...
The function challenges a user agent. It will generate a Proxy-Authorize header field containing a digest challenge, it will put the header field into a response generated from the request the server is processing and send the 407 reply. Upon reception of such a reply the user agent should compute credentials and retry the request. For more information regarding digest authentication see RFC2617. See module parameter force_stateless_reply regarding sending of the reply.
Meaning of the parameters is the same as for function www_challenge(realm, flags)
This function can be used from REQUEST_ROUTE.
Example 1.21. proxy_challenge usage
... if (!proxy_authenticate("$fd", "subscriber")) { proxy_challenge("$fd", "1"); exit; } ...
The function challenges a user agent for authentication. It combines the functions www_challenge() and proxy_challenge(), by calling internally the first one for REGISTER requests and the second one for the rest of other request types. In other words, it challenges for authentication by sending a 401 reply for REGISTER requests and 407 reply for the other types of SIP requests.
Meaning of the parameters the same as for function www_challenge(realm, flags)
This function can be used from REQUEST_ROUTE.
Example 1.22. auth_challenge usage
... if (!auth_check("$fd", "subscriber", "1")) { auth_challenge("$fd", "1"); exit; } ...
The function verifies credentials according to
RFC2617.
If the credentials are verified successfully then the function
will succeed and mark the credentials as authorized (marked
credentials can be later used by some other functions). If the
function was unable to verify the credentials for some reason
then it will fail and the script should
call www_challenge
which will
challenge the user again.
Negative codes may be interpreted as follows:
-1 (generic error) - some generic error occurred and no reply was sent out
-2 (invalid password) - wrong password
-4 (nonce expired) - the nonce has expired
-5 (no credentials) - request does not contain an Authorization header with the correct realm
-6 (nonce reused) - the nonce has already been used to authenticate a previous request
Meaning of the parameters is as follows:
realm - Realm is an opaque string that the user agent should present to the user so he can decide what username and password to use. Usually this is domain of the host the server is running on.
It must not be empty string “”. In case of REGISTER requests To header field domain (e.g., variable $td) can be used (because this header field represents a user being registered), for all other messages From header field domain can be used (e.g., variable $fd).
The string may contain pseudo variables.
passwd - the password to be used for authentication. Can contain config variables. The Username is taken from Auth header.
flags - the value of this parameter can be a bitmask of following:
1 - the value of password parameter is HA1 format
2 - build challenge header with no qop and add it to avp
4 - build challenge header with qop=auth and add it to avp
8 - build challenge header with qop=auth-int and add it to avp
16 - build challenge header with stale=true
method - the method to be used for authentication. This parameter is optional and if not set is the first "word" on the request-line.
When challenge header is built and stored in avp, append_to_reply() and the sl reply functions can be used to send appropriate SIP reply to challenge for authentication.
This function can be used from REQUEST_ROUTE.
Example 1.23. pv_www_authenticate
usage
... if (!pv_www_authenticate("$td", "123abc", "0")) { www_challenge("$td", "1"); exit; } ...
The function verifies credentials according to
RFC2617. If
the credentials are verified successfully then the function will
succeed and mark the credentials as authorized (marked credentials can
be later used by some other functions). If the function was unable to
verify the credentials for some reason then it will fail and
the script should call
proxy_challenge
which will
challenge the user again. For more about the negative return codes,
see the above function.
Meaning of the parameters is the same as for pv_www_authenticate(realm, passwd, flags)
This function can be used from REQUEST_ROUTE.
Example 1.24. pv_proxy_authenticate usage
... $avp(password)="xyz"; if (!pv_proxy_authenticate("$fd", "$avp(password)", "0")) { proxy_challenge("$fd", "1"); exit; } ...
The function combines the functionalities of
pv_www_authenticate
and
pv_proxy_authenticate
, first being
executed if the SIP request is a REGISTER, the second for the rest.
Meaning of the first three parameters is the same as for pv_www_authenticate(realm, passwd, flags).
Parameter checks can be used to control the behaviour of the function. If it is 1, then the function will check to see if the authentication username matches either To or From header username, a matter of whether it is for a REGISTER request or not. The parameter may be a pseudo variable.
The set of possible return codes is the same than pv_{www,proxy}_authenticate, with one more possible value:
-8 (auth user mismatch) - the auth user is different than the From/To user
This function can be used from REQUEST_ROUTE.
Example 1.25. pv_auth_check usage
... $avp(password)="xyz"; if (!pv_auth_check("$fd", "$avp(password)", "0", "1")) { auth_challenge("$fd", "1"); exit; } ...
Build WWW-Authentication header and set the resulting value in 'pvdest' pseudo-variable parameter.
Meaning of the realm and flags parameters is the same as for pv_www_authenticate(realm, passwd, flags)
This function can be used from ANY_ROUTE.
Example 1.26. auth_get_www_authenticate
... if (auth_get_www_authenticate("$fd", "0", "$var(wauth)")) { xlog("www authenticate header is [$var(wauth)]\n"); } ...