Have you ever received a call from someone with a caller ID which looked like the one you know but appeared not what you expected? Or had dozens of spam calls during a day? This can be utterly annoying, isn’t it?

You are right, unwanted calls can be a real pain in the neck. But they can also become a threat to the called party because fraudulent calls are often used to steal your sensitive data and use it against you.

Robocalls and Caller ID Spoofing Problems

Security is very important for VoIP calls. As the call sometimes originates not from a regular phone connected via the PSTN but from a software phone, the caller ID might be controlled not by the originating service provider but can be incredibly easily software-modified. In this case the caller ID will be different from what it originally is, and alas: you see a known caller ID on your phone screen, pick up the phone, and become a new victim to the telephone fraud.

Robocallers fake (or spoof) the caller ID to increase the chance that the called party will answer a robocall. Fraudsters may impersonate a legitimate source and ask for some data, which can be then used to steal something from you.

Caller ID spoofing often pretends the call to be from a nearby phone number with the same area code that you have. Once the caller ID is spoofed to look like something familiar, the consumers are more likely to pick up the telephone call. With calls originating from VoIP systems, the caller can be located in another part of the world.

Criminals are unscrupulous, and you cannot be sure that the calling number is what you expect it to be unless there is a mechanism to verify the caller. As with email spam, we cannot totally eliminate the threat but CarrierX can dramatically reduce the chances of this happening.


STIR/SHAKEN is a complex of protocols and procedures intended to fight caller ID spoofing on telephone networks. It enables telephone service providers to authenticate and verify caller identities to mitigate caller ID spoofing. It is a certificate-based technology that uses private and public keys to identify the source of a call.

STIR stands for Secure Telephony Identity Revisited. This is a series of RFC standards documents, defining a protocol for creating a digital signature with the calling party. It also allows this digital signature to be created and verified in various locations.

SHAKEN stands for Signature-based Handling of Asserted information using toKENs. SHAKEN specifies how STIR can be deployed in service provider networks. It provides both a reference architecture for SIP and a certificate management framework.


The common STIR/SHAKEN flow can be described by the following diagram:


Attestation Levels

The attestation levels serve two main purposes:

  1. They identify the originating service provider, which is useful for call traceback. This information can be used by other providers and legal authorities to investigate suspected illegal robocalls or telephone scams.
  2. They indicate the scope of information that the originating service provider will vouch for.

To make sure that the call is valid, comes from a trusted caller, and not spoofed, the following three attestation levels are used:

Being a certified communications service provider, CarrierX complies with the US Federal Communications Commission requirements and can attest the call and add the attestation information to the call data.

Depending on the attestation level, the appropriate Identity header is added to the call data. Refer to the next section for more information on what data this header contains.

SIP Identity Header

A typical SIP INVITE message containing an Identity header in CarrierX looks like the following:

INVITE sip:12059999926;npdi=yes@ SIP/2.0
Via: SIP/2.0/UDP;branch=z9hG4bK5af6e0ac;rport
Max-Forwards: 70
From: "John Smith*" <sip:15162065613@>;tag=as062a2e2a
To: <sip:12059999926;npdi=yes@>
Call-ID: 22cccd5d13df02344314b8440baed1c5@
CSeq: 102 INVITE
Identity: eyJ0eXAiOiJwYXNzcG9ydCIsImFsZyI6IkVTMjU2IiwicHB0Ijoic2hha2VuIiwieDV1IjoiaHR0cHM6Ly9zdG9yYWdlLmNhcnJpZXJ4LmNvbS9jZXJ0LmNydCJ9.eyJhdHRlc3QiOiJBIiwiZGVzdCI6eyJ0biI6WyIxMjA1OTk5OTkyNiJdfSwiaWF0IjoxNjE0MTcxOTIyLCJvcmlnIjp7InRuIjoiMTUxNjIwNjU2MTMifSwib3JpZ2lkIjoiZjQyMjA3MTAtNzZhMC0xMWViLWEyYTgtOTBlOWVlOWY1NGQ1In0.tx7OkEv36tmH9NYPD9HSIcrmA0i7ABRha-QBjlbVdYH-MrbGkdL-G7qIJbe7wLDB;info=<>alg=ES256;ppt=shaken

The Identity header contains the following parts:

When we decode the token header, we can see that it contains the information about the means used to sign the call:

  "alg": "ES256",
  "ppt": "shaken",
  "typ": "passport",
  "x5u": ""
Attribute Data Type Description
alg string Specifies the encryption algorithm used to create signature. Repeats the alg parameter of the Identity header. Value accepted in this field is ES256.
ppt string Declares that the token is used for STIR/SHAKEN. Repeats the ppt parameter of the Identity header. Value accepted in this field is shaken.
typ string Defines the token type. Value accepted in this field is passport, corresponding to the base64-encoded Persona Assertion Token (PASSporT).
x5u string Contains the link to the certificate used to sign the token and is equal to the info parameter of the Identity header.

When we decode the token payload, we can see that it contains the information about the call itself and the call participants:

  "attest": "A",
  "dest": {
    "tn": [
  "iat": 1614171922,
  "orig": {
    "tn": "15162065613"
  "origid": "f4220710-76a0-11eb-a2a8-90e9ee9f54d5"
Attribute Data Type Description
attest string Defines the attestation level used with the call. Values accepted in this field are: A, B, or C. Refer to the Attestation Levels section for more information.
dest object An object containing the tn array, which lists the destination numbers or called URIs.
iat integer The UNIX timestamp of the moment when the token was created.
orig object An object containing the calling number or URI.
origid string A globally unique identifier corresponding to the service provider-initiated calls themselves, customers, classes of devices, or other groupings that a service provider might want to use for determining reputation or trace back identification of customers or gateways.

The last part of the base64-encoded PASSporT token is a digital signature. SHAKEN implements digital signatures to enable service providers to detect and block call spoofing. To create the digital signature, the authentication service inputs the token header and payload into the hashing algorithm and obtains the hash value. Then it uses the originating provider’s private key from the secure key store and the resulting hash value to create a digital signature unique to the originating provider.

The digital signature is then combined with the original token header and payload to create the signed PASSporT token.

Storing Verification Results

After the digital signature in the Identity header is submitted to the verification service, it will return the result of the call verification.

The service providers can add the result (both successful and failed) to other call headers. For example, the verification results can be stored in:

There are currently three options to pass the verification results through header parameters:

The usage of a specific header to store the verification results depends on the terminating telephone service provider software and hardware, and should be coordinated across the network.

CarrierX STIR/SHAKEN Implementation

According to the US Federal Communications Commission rules, the obligations of a voice service provider depend on the provider role for a particular call:

CarrierX can act as any of the provider type: originating, intermediate, or terminating.

To comply with all the rules, CarrierX uses transformations to implement STIR/SHAKEN procedures at various call stages.

CarrierX Call Verification

The stir_validate transformation will verify the call and return data that can be used with other transformations.

STIR Validate Transformation

Its syntax looks like the following:

    "action": "stir_validate",
    "direction": "any",
    "operands": []

The stir_validate transformation does not have any operands, instead it returns call verification data that can be used in the further call flow:

The system then saves the verification data to the Call Detail Record object stir_attest, stir_origid, and stir_verstat attributes accordingly.

Verification Examples

The stir_validate transformation is normally not used all by itself. You can use it to verify the call signature and then use the output data with other transformations to manage the further call behavior.

An example of such a behavior can look like this:

Chaining Transformations

Here is the list of the transformations used from the figure above:

"transformations": [
        "action": "stir_validate",
        "direction": "inbound",
        "operands": []
        "action": "set_header",
        "direction": "inbound",
        "operands": ["X-StirResult", "{{stir_verstat}}-{{stir_attest}}"]
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}:{{stir_attest}}", "TN-Validation-Passed:[AB]", "rewrite_from_header_param", "cnam", "(.{1,14})", "\\1*"]
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}", "No-TN-Validation", "rewrite_from_header_param", "cnam", ".*", "POSSIBLE FRAUD"]
        "action": "if_match",
        "direction": "inbound",
        "operands": ["{{stir_verstat}}", "TN-Validation-Failed", "reject", "forbidden"]

These transformations will be used depending on the call source and their resulting call flow will be the following:

  1. The call from the Calling Party #1 is digitally signed by the originating provider, it returns a valid origid, together with the A attestation level (received from the {{stir_attest}} variable) and the TN-Validation-Passed verification status (received from the {{stir_verstat}} variable). In this case, CarrierX comes to a conclusion that this is a trusted caller, adds the verification information as either the P-Asserted-Identity header parameter or the X-StirResult header, marks the CNAM of the From header with some sign (e.g., *) to signify a trusted caller, and after this the caller can be displayed as verified to the called party.

  2. The call from the Calling Party #2 is not signed by the originating provider. It returns the No-TN-Validation verification status (received from the {{stir_verstat}} variable). Nor it is originating from CarrierX network. In this case, CarrierX cannot be sure whether it is a trusted caller or the number might be spoofed. CarrierX adds the verification information as either the P-Asserted-Identity header parameter or the X-StirResult header, and after this the caller will be displayed with some warning to the called party.

  3. The call from the Calling Party #3 is signed by the originating provider, but fails the verification. It returns the TN-Verification-Failed verification status (received from the {{stir_verstat}} variable). In this case, CarrierX stops any further call flow using the reject transformation, and the called party will never receive such a call.

Further Reading

Read the following articles to get a better understanding of how things work in CarrierX: