Robo-calls finally meet their Robocop: libstirshaken

Stopping spoofed caller ID

Solutions Architect

Luca Pradovera

The telephony industry has struggled with spam calls and robo-calling almost since its inception. As soon as someone had a phone number, they could be called by anyone, and the caller could pretend to have any identity.

The number and identity of the caller, known as Caller ID, are relatively easy to falsify or “spoof”, as that action is known in VoIP circles, and leads to difficult situations when it comes to filtering calls, because it used to be hard to verify the claim that the call was indeed coming from a legitimate party.

SignalWire has been contributing to the mitigation of that problem with the development of libstirshaken, the open source implementation of the STIR/SHAKEN protocol.

How does the protocol work?

When signing a call, the caller uses a certificate they received from an FCC authority to create block of data that is included in the call header.

On reception, the callee will verify that block of data using the referenced certificate that was used to create the signed data.

Everything is very simple and transparent to end users, who enjoy enhanced security without any changes to their usual call flow.


STIR/SHAKEN is a technology to mitigate caller ID spoofing, and its acronym is quite explanatory despite being a bit contrived.

STIR, short for Secure Telephony Identity Revisited, is a set of RFC standard documents that define how authenticity certificates should be added to the SIP protocol and verified when a call is received.

By itself, that would solve the problem of falsified caller IDs in Voice over IP calls, but it does not handle the case of a PSTN call routed over SS7, because the special headers and certificates would be missing.

SHAKEN (Signature-based Handling of Asserted information using toKENs) is a set of recommendations to deal with calls on the public switched network, mainly through the addition of special information to CNAM records, which are normally used to verify and display caller ID on the PSTN.

STIR/SHAKEN does not only specify a way to verify a caller ID certificate, but also mechanisms to attach other information to the call. This Rich Call Data (RCD) payload could for example contain a picture of the caller, or some other extra information.

Mode of operation

STIR uses JSON objects (called PASSporTS) to convey cryptographically signed information about a call.

These PASSporTs are signed with private keys associated with certificates to which a link is embedded in PASSporTs, so that during a process of verification of PASSporT those SSL certificates are downloaded and can be checked for authenticity.

They must be special SHAKEN certificates, which means they have been issued by a certified SHAKEN certificate authority (CA).

Why it matters

The FCC’s Second Order for the TRACED Act mandates that calls from any voice service provider not registered with the new FCC SHAKEN/Robocall Mitigation Database by June 30, 2021 must be blocked.

SITR/SHAKEN provides a few main features out of the box:

1. Information about the call can be sent along with a SIP message and verified at the terminating point, so it is known that it couldn’t possibly have been changed. Aside from simple caller ID verification, the information contains the intended destination, and the originating point. Thus, if all of the information in the PASSporT header matches, the identity of the caller and the call path are confirmed as valid.

This simple integrity check is performed by decoding PASSporT with a public key taken from the certificate that the header references. This confirms the call path has not been tampered with, and might be enough for simple usage, provided the entity who signed that particular PASSporT is trusted.

2. To find out if the call origin is trustable, we need to validate the STIR/SHAKEN certificate that signed the call PASSporT. It should have been signed by a dedicated Certificate Authority, who in turn must have received its credentials by the trusted network, consisting of entities who possess certificates signed by the STIR/SHAKEN root certificates. As you can see, this has many similarities with how HTTPS operates.

In the United States the STIR/SHAKEN network is built and managed by the FCC. The root authority is Iconectiv and there will be many CAs started by other entities. This initiative intends to be the global authority for STIR/SHAKEN, but technically it is possible for other trust networks to (co)exist. The only requirement is that end entity certificates (service provider certificates) must be derived from root CA certificates, and root CA certificates are managed properly both during creation and storage.

These X.509 certificates are checked as part of the verification process together with the service provider’s own certificate. This means that the process will eventually encounter a trusted party up the chain, including the root CA, and will be able to trust the entire chain.

3. The last part of a STIR/SHAKEN check will be the verification of authority of the Service Provider over the telephone number given as orig grant in PASSporT (caller ID). The exact way the authority check is going to be performed has not been defined, but there is most likely going to be one or more central databases, similar to the FCC registry for robocallers, but containing information about which provider manages each phone number.

The Open Source implementation of STIR/SHAKEN: libstirshaken

Libstirshaken is an open source library, sponsored by SignalWire, implementing all of the building blocks of STIR/SHAKEN. Its goal is to make it easy to integrate STIR/SHAKEN in telephony applications.

It can be used in two main modes. The first, which will be the most common, is to use libstirshaken to sign and verify calls on the official FCC network, to provide better security to users and customers. The library can also be used effectively as a Letsencrypt-style tool, to generate child certificates from a FCC-certified parent obtained from a verified CA.

Libstirshaken is available in FreeSWITCH and is used by Kamailio’s stirshaken module ( It was tested for interoperability with other leading Shaken implementations, e.g. TransNexus (January 2021).

You can find the source code on GitHub at, complete with examples and compilation instructions.

Usage examples

We will be now looking at the basic usage of libstirshaken via its bundled command line tool, as an easy way to start integrating STIR/SHAKEN in your application.

Signing the call

In our scenario, an user named Bob calls Alice through a service hosted on SignalWire. The service would like to sign the call on behalf of Bob using the SHAKEN certificate it obtained from a FCC-certified CA.

The “stirshaken” command line tool would be used in the following way:

Say Bob calls Allice and we got our private SSL key which is associated with our Shaken certificate that we obtained from CA. We create then PASSporT:

./stirshaken passport-create --privkey test/ref/sp/certificate.priv --url https://shaken.signalwire.clou... --attest B --origtn bob --desttn alice --origid e1532d44-f4db-4788-8ae5-e9442412510a -f passport.txt --vvv

In readable form, the PASSporT generated is:

   "alg": "ES256",
   "ppt": "shaken",
   "typ": "passport",
   "x5u": "https://shaken.signalwire.clou..."
   "attest": "B",
   "dest": {
       "tn": [
   "iat": 1617028773,
   "orig": {
       "tn": "bob"
   "origid": "e1532d44-f4db-4788-8ae5-e9442412510a"

After signing, the JSON above is encoded in a format suitable for including in a SIP INVITE. Note that the above command generates both the signed and unsigned version in the same output file we specify with “-f”.

Additionally, to be sent over SIP we need to add an info field with the necessary PEM information:


With the final output being:


In this form it may be sent down the protocol stack. In the case the header’s size becomes too large to be sent over UDP, it can be transmitted out of band using mechanisms such as the Call Placement Service specified in the STIR OOB draft.

The SIP Invite would look similar to this:

INVITE sip:alice@ SIP/2.0
Via: SIP/2.0/UDP;rport;branch=z9hG4bK62acZ0175HStD
Max-Forwards: 70
From: <sip:bob@>;tag=3U8B9aUFar8Fj
To: <sip:alice@>
Call-ID: 6aff79fa-0b3f-123a-1a91-0210aa0ae2ba
CSeq: 33960594 INVITE
Identity: eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly9zaGFrZW4uc2lnbmFsd2lyZS5jbG91ZC9zdGlyX3NoYWtlbi9zcC5wZW0ifQ.eyJhdHRlc3QiOiJCIiwiZGVzdCI6eyJ0biI6WyJhbGljZSJdfSwiaWF0IjoxNjE3MDI4NzczLCJvcmlnIjp7InRuIjoiYm9iIn0sIm9yaWdpZCI6ImUxNTMyZDQ0LWY0ZGItNDc4OC04YWU1LWU5NDQyNDEyNTEwYSJ9.C0_NbMmVwdcV645sru8SeIfWEeg_ARwLCjtVbUDHtSH_PVX5vErWKe6BnxSWHQu_Vc2e6ZrZKUJLoxSiamAjkg;info=<;;alg=ES256;ppt=shaken
Contact: <sip:mod_sofia@>
Date: Mon, 29 Mar 2021 14:39:33 GMT
User-Agent: FreeSWITCH-mod_sofia/20.20.8-dev+git~20210211T195954Z~b374add1ef~64bit
Supported: timer, path, replaces
Allow-Events: talk, hold, conference, refer
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 740
X-FS-Support: update_display,send_info
Remote-Party-ID: <sip:bob@>;party=calling;screen=yes;privacy=off
[...SDP omitted for brevity…]

Verification of a call

Alice or her provider will perform the following checks on the terminating side:

1. Extract PASSporT

2. Download referenced certificate

3. Check signature using public key from downloaded certificate

4. Check if certificate was signed by one of trusted CA roots

This can be done with:

./stirshaken jwt-check --jwt eyJhbGciOiJFUzI1NiIsInBwdCI6InNoYWtlbiIsInR5cCI6InBhc3Nwb3J0IiwieDV1IjoiaHR0cHM6Ly9zaGFrZW4uc2lnbmFsd2lyZS5jbG91ZC9zcC5wZW0ifQ.eyJhdHRlc3QiOiJCIiwiZGVzdCI6eyJ0biI6WyJBbGljZSJdfSwiaWF0IjoxNjE1OTM2MjQ1LCJvcmlnIjp7InRuIjoiQm9iIn0sIm9yaWdpZCI6ImUzMmY0MTg5LWNiODYtNDYwZi1iYjkyLWJkM2FjYjg5ZjI5YyJ9.jJSEUTpKlBuSGT_eoyWB6ngHl5J5OA0yAbDPMq8mjO1SkHaXxh8aL1oJ2Gl2qmqmMJNXMQeeA6KKZphensxljg;info=<;;alg=ES256;ppt=shaken --ca_dir test/ref/ca --vvv

With the redacted output being:

+ Processing OPTION 18 (jwt)
PASSporT is:
    "alg": "ES256",
    "ppt": "shaken",
    "typ": "passport",
    "x5u": "https://shaken.signalwire.clou..."
    "attest": "B",
    "dest": {
        "tn": [
    "iat": 1615936245,
    "orig": {
        "tn": "Bob"
    "origid": "e32f4189-cb86-460f-bb92-bd3acb89f29c"

Verified. JWT matches the referenced certificate
=== Done. Thank you.

The “Letsencrypt” of STIR/SHAKEN

There are many possible application of libstirshaken and the related CLI tools:

  • generating SSL keys

  • generating CSR

  • generating SSL certificates (end entity, self issued and self signed)

  • generate PASSporT for a call

  • run a simplified demo CA

  • obtain SP (end entity) certificate from that CA, simulating ACME

  • verify PASSporT:
    • (optionally) with X509 cert path check

    • (optionally) caching supplying certificates from cache through your callback

  • dump PASSporT (input is encoded JWT, output is human readable headers and grants)

  • specify connect timeout on http(s) request

  • Save CA certificate with hashed name (necessary when using CA dir)

There are examples for all of the use cases in the Github repository (

Using libstirshaken, it is possible to build out an entire STIR/SHAKEN infrastructure to support your use cases or even third parties.

This is the beginning of an exciting phase in the industry, where robo-calls and spammers will start meeting the same countermeasures that email users have enjoyed for years. Reach out to us on GitHub or Slack, and we will be happy to stop by for a chat!