Sunday, 6 April 2014

The problem with SIP

SIP (Session Initiation Protocol), used for VoIP, has a slight problem, in my opinion.

If I am lucky, someone will post a reply to this blog and tell me I have missed the bleeding obvious here, but somehow I doubt it.

When you send an INVITE (to make a call), or indeed any message, the receiving end has the option to challenge you. The challenge allows you to send your identity and respond to the challenge with a signed response confirming your identity based on a password. The challenge/response system is pretty common in many protocols.

The problem with SIP is that the initial INVITE does not have any way to tell the recipient "I have some authentication details for you". This means the recipient has to work that out from the From/To headers. It does not know the username the sender may use if challenged, and the local part of the From header is likely to be a calling number.

The issue is that some times you are trusting the far end based on IP address and not generating a challenge, and some times you want to generate a challenge to confirm the identity. You may have a mixture of the two on the same box. A fixed config that trusts the far end is not that uncommon and avoids an extra exchange of messages.

This causes a lot of problems for things like asterisk. It is quite complicated to configure asterisk to work out if it should challenge the INVITE or not. What is worse is that asterisk does a DNS lookup of the configured host name when it checks and expects one IP address against which to check. This is a really pain when you have a group of call servers you want to trust, and makes the config quite large.

We are hitting a snag with our SIP2SIM. We have a set of call servers which can send REGISTER and INVITE messages to the customer's server. People using us for VoIP have their asterisk servers set up to understand that calls can come from that same set of servers for normal calls. But that means asterisk does not think it is sensible to challenge us for the SIP2SIM calls where we are acting like a SIP device, and hence have a username and password to use. We are working out the best way around this at the moment. We don't really want to have to set up a second set of call servers (or additional IP addresses) just for sending the SIP2SIM calls and registrations.

If SIP had a way to tell the recipient that it has credentials, and force the challenge, that would solve this. We would send the username when we have it, and the recipient can consider it in that context.


  1. Doesn't setting type=user in sip.conf in Asterisk achieve this? Type=peer matches on IP address & port and ignores authentication details, whereas type=user ignores the ip address and matches on username/password. If you have multiple lines from the same provider which come from the same ip address/port and use type=peer, Asterisk will match the first account it finds in sip.conf (working from bottom up), regardless of any authentication details added, and to get it to work properly you need to use type=user (or short out the lines in extensions.conf on the dialled CID). There is a security risk with this, as Asterisk will accept connections from any ip address as long as the credentials are correct, but I stop these at the firewall, since all my INVITES should come from AAISP.

    I was going to test this myself, as my lines have just moved from A server and I am using the long list of host lines from the wiki. In theory, using type=user should mean you don't need to specify any host (apart from outgoing calls, obviously).

    1. Well, you cannot match on user unless you knew to challenge the request so as to find the user against which to match, if you see what I mean.

  2. Theoretically this is possible in SIP because you should be able to use a different realm/domain for your SIP2SIM traffic. This works exactly like Apache virtualhost constructs. Typically in most systems that understand domains, Freeswitch for example, can use the domain instead of the IP address, along with the port number to designate a SIP profile. Those profiles can be configured to do the challenge/response, or not (just like Asterisk user/peer setup). Unfortunately, Asterisk doesn't understand domains and as a result has a flat hierarchy of profiles based on IP/port only.

    Seeing as you're controlling the User Agent on your side, you might be able to hack it by sending the second INVITE with the authentication details straight away. It's a long shot, but it might work on the more basic security levels (probably now deprecated in Asterisk) where the response doesn't need to include any details from the challenge.

    Failing that, you'll just have to setup your gateways with a second set of IP addresses.

    1. Indeed, I have added a new FireBrick feature that allows a different default source IP for any exchange that has authentication details and so expects a challenge. We'll have to give customers notice of the change before rolling it out.

  3. In theory this should be reasonably similar to something like HTTP: A specific destination should be either restricted or unrestricted - i.e. a "restricted" destination is something that always requires authentication and an "unrestricted" destination is something that never requires authentication. After all, what is the point in demanding authentication credentials if you were going to allow access to the extension so anonymous people anyway? (i.e. an authenticated user should never have less access than an anonymous user, so no need to authenticate people when they call a destination that is accessible by anonymous users. As mentioned, this is more or less the same as HTTP - the browser only sends credentials if the server demands them, and the server can't demand them for people accessing public resources.

    I guess the times when this falls down are:
    1. You want to route anonymous and authenticated users differently for the same destination, rather than outright rejecting anonymous users (e.g. playing them a friendly "permission denied" message instead of just rejecting the SIP session). Arguably a "permission denied" message should be machine readable though, so just sending a human audible "permission denied" recording is probably a Bad Thing.
    2. You want to allow public access to the destination, but you want to know how trustworthy the originator details are and therefore handle "trustworthy" sources differently to "non-trustworthy" sources with respect to stuff like the CLID. e.g. you probably trust the CLID data of an incoming call that's come in through your SS7 gateway and display it on the recipient's phone; but you don't want to trust the CLID data from a random SIP call coming from elsewhere on the internet, so don't want the recipient to see it.

    (2) does indeed seem to be a problem, and I guess the only sensible way to deal with this is to give your SS7 gateway a different (authenticated) URI to anonymous users, whether that be a different lpart, or a different domain part.

    I will say that I find Asterisk's handling of whether or not to authenticate certain clients rather confusing.

  4. I'm not sure that I fully understand the problem but I can tell you that it is not strictly necessary to use the "From" header for the caller ID. There are two alternatives, P-Asserted-Identity and Remote-Party-ID. The latter was never ratified but appears to be better supported, particularly by Asterisk. This page explains how you can use them.

    This should free up the From field for the username.