
There is no doubt about the danger and security threats presented by the robocalls or identity thieves.
Also there is no doubt that STIR/SHAKEN is the solution that addresses the threats. And the most important aspect of this solution is the fact that this is a standardized, well accepted and (nevertheless) viable solution (see SIPNOC2019). It is worth mentioning that STIR/SHAKEN raised and gained thrust mainly within the US borders, where all the operators are compelled by a federal bill to address the robocalls and identity thieves danger.
Why STIR/SHAKEN in OpenSIPS
Without getting into details on how STIR/SHAKEN works (as there are plenty docs on that, one of the best explained being this paper from TransNexus), let’s see why have we considered an STIR/SHAKEN implementation in OpenSIPS.
Well, STIR/SHAKEN is about authenticating or verifying the identity/CLI of the caller (and maybe more). So, almost any operator/carrier originating or terminating calls should implement STIR/SHAKEN.
With OpenSIPS you can implement a large variety of SIP components or solutions where such origination and termination is needed:
- Class 4/5 Soft-Switches/PBXes – terminating (and verifying) the calls from other carriers/operators, originating (and authenticating) the calls from its own users (direct or behind PBX users)
- Session Border Controller – performing verification over the incoming calls, before routing them to the core network
- Carrier FrontEnds/Load-Balancers – originating (and authenticating) the calls from the internal GW/switches, terminating (and verifying) the calls received calls, before routing to internal GW/switches.
- Trunking / Wholesale Solutions – mainly performing verification over the incoming calls, before applying any routing decisions.
The STIR/SHAKEN implementation
The purpose of any implementation is to be highly usable. Having this in mind, we allocated a couple of months to talk and get feedback from various operators and carriers, before writing down the requirements of our implementation. The idea was to be 100% sure we end up with not only a usable implementation (from the perspective of how STIR/SHAKEN will be deployed), but also to try to cover as many usage scenarios as possible (in terms of certificate manipulation).
Looking at the whole STIR/SHAKEN big picture, it is clear that the Certificate Issuing is not something to be addressed by a SIP Server/Proxy. So, what is covered by the OpenSIPS implementation is :
- certificate managing (fetching remote certificates, local storage, caching)
- certificate usage (sign or verify the payload with the right certificate)
- passport handling (data collecting, pack/unpack, encode/decode, SIP stack interaction)
The resulting work is the “stir_shaken” module developed by Vlad Patrascu, a senior OpenSIPS developer.
Usage models
The goal is to have a versatile implementation, able to satisfy various usage scenarios. And right now there are still some STIR/SHAKEN aspects still under discussion (or subject to future changes), like how the certificates should be exchanges between the parties for verification purposes. From this perspective, some operators want to do “manual”/static exchange of the certificates, other do want to automatically/dynamically fetch them based on the received passports.
To address both scenarios, we decided to have two usage models in OpenSIPS:
- Certificate agnostic (or external handling) – OpenSIPS is totally certificate managing unaware, it expects to get the the required certificate (for each call) from other sub-systems in the platform/service;
- Certificate self managing – OpenSIPS is performing the certificate managing by itself, via its own mechanisms of fetching and storing the required certificates (like using the “rest_client” and the “cachedb_local” modules)
The Agnostic model
By external tools, you need to provide to the “stir_shaken” module the exact certificate(and key) to use.
Authenticating the originating calls: OpenSIPS will collect the data, construct the passport, sign it and add the payload to the SIP request.
loadmodule "stir_shaken.so" stir_shaken_auth("A", "$var(oid)", "$var(cert)", "$var(pkey)", "https://cert.example.org/passport.cer" [,"$var(orig)","$var(dest)"]); if ($rc < 0) { xlog("stir_shaken_auth() failed\n"); send_reply(500, "Server Internal Error"); exit; }
Verifying the terminating calls: OpenSIPS will verify the signature, unpack the passport and extract the data from it.
loadmodule "stir_shaken.so" modparam("stir_shaken", "ca_list", "/etc/pki/opensips/passport.cer") stir_shaken_verify("$var(cert)", $var(code), $var(reason)); if ($rc < 0) { xlog("stir_shaken_verify() failed: " "$var(code), $var(reason) \n"); send_reply($var(code), $var(reason)); exit; } # available variables for further handling: # $identity(x5u) # $identity(attest) # $identity(origid) # $identity(dest) # $identity(orig)
The Self-Managing model
By OpenSIPS scripting or by external tools, you need to provide to the “stir_shaken” module the exact certificate to use.
Authenticating the originating calls: based on the identifier $var(certid) of the certificate (determined by the routing logic), fetch the actual certificate and its key.
loadmodule "stir_shaken.so" # certificate managing $var(cert) = $sql_cached_value(C_repo:certificate:$var(certid)); $var(privkey) = $sql_cached_value(C_repo:private_key:$var(certid)); $var(x5u) = $sql_cached_value(C_repo:x5u:$var(certid)); $var(origid) = "4437c7eb-8f7a-4f0e-a863-f53a0e60251a"; # doing STIR/SHAKEN authentication stir_shaken_auth("A", "$var(origid)", "$var(cert)", "$var(privkey)", "$var(x5u)"); if ($rc < 0) { xlog("stir_shaken_auth() failed\n"); send_reply(500, "Server Internal Error"); exit; }
Verifying the terminating calls: OpenSIPS will try to fetch the needed certificate (based on x5u) from its local cache or it will download via HTTP using the “rest_client” module.
# certificate managing $var(found) = cache_fetch("local", $identity(x5u), $var(cert)); if (!$var(found) || !stir_shaken_check_cert("$var(cert)")) { # if the certificate is not found in the cache # or is expired, we try to fetch it from the # certificate repository rest_get( "$identity(x5u)", "$var(cert)", $var(ctype), $var(http_rc)); if ($rc<0 || $var(http_rc) != 200) { send_reply(436, "Bad Identity Info"); exit; } # certificate successfully fetched, cache it now cache_store("local", $identity(x5u), $var(cert)); } # do the STIR/SHAKEN verification stir_shaken_verify( "$var(cert)", $var(err_sip_code), $var(err_sip_reason)); if ($rc < 0) { xlog("stir_shaken_verify() failed: " "$var(code), $var(reason) \n"); send_reply( $var(err_sip_code), $var(err_sip_reason)); exit; }
SIP flow insertion
Depending on the SIP architecture you have, the STIR/SHAKEN handling may be added in proxy mode or redirect mode.
In proxy mode, the STIR/SHAKEN handling is done by the same SIP server handling the traffic.

In the redirect mode, the STIR/SHAKEN handling is done by a dedicated SIP entity which interacts with the main proxy via INVITE/302 reply redirection mechanism. This dedicated SIP entity will not stay in the path of the call, it will be involved only at the INVITE time.

The redirect-based insertions enables:
- creation of micro-services based architectures
- creation of third-party STIR/SHAKEN service providers
Conclusions
The standards, the regulations and the deployments around STIR/SHAKEN are dynamic, still subject to changes and improvements. Nevertheless, for the US operators there is a must to comply and adopt STIR/SHAKEN. And the implementation in OpenSIPS, an Open Source implementation, is ready to help with that, whatever the strategy is managing the certificates is.
For more information, do not hesitate to join us to the OpenSIPS Summit 2020 in May, Amsterdam.
One thought on “Shaken, not stirred”