Skip to content

Commit 8c177e8

Browse files
committed
Stir/Shaken Refactor DRAFT
THIS IS A DRAFT PR/COMMIT and will not be merged as is. To make reviewing easier, there's an earlier commit that removes the existing completely. Otherwise, the review diffs would be an unfollowable mess of deletions and additions. The final commit will be a traditional single "update" commit without the removal. There are also outstanding items that I'm waiting on resolution of. * Do we need to support the compact form of the Identity PASSporT? Based on ATIS-10000074, I don't _think_ we do but I'm awaiting clarification. NOT AT THIS TIME. * ATIS-10000074 also states that we must not follow redirections or attempt to retrieve certificates using URLs that have user:password components or path or query parameters. I still need to implement that check. DONE. * RFC-8224 says we must include one or more "mky" Media Key entries in the PASSporT containing the fingerprints in the SDP if DTLS is in use. Although this is now implemented, it defaults to "off" because I can't find any other implementation that respects them. In fact OpenSIPS will fail to validate any Identity header that has them. * Many enums and functions that are private to res_stir_shaken still have "ast_stir_shaken" prefixes on them. They should be renamed just for clarity's sake. * It was my intention to have the stir-shaken internals set error codes and text responses in the contexts to be passed back to the outside caller so the caller could decide whether to emit messages or not. I never got to that and need to either implement that or remove the associated fields in the contexts and clean up the error messages. Things that need to be done ouside this commit: * Implement dialplan function that allows a dialplan author to reject a call with a specific SIP response code if they deem it necessary based on the stir-shaken results passed to them. DONE * Add alembic scripts so the configuration can be database based. * Decide if/how to implement RFC-9090 Certificate Delegation. * Decide if/how to implement validation of the TNAuthList extension in certificates. Right now we only validate that it's present, not its content. * Decide if/how to implement RFC-8946 Diverted Calls. * Decide if/how to handle multiple Identity headers. * Decide if/how to handle passing received identity headers to an outgoing INVITE. REAL COMMIT MESSAGE: Why do we need a refactor? The original stir/shaken implementation was started over 3 years ago when little was understood about practical implementation. The result was an implementation that, until now, wouldn't interoperate with any other stir-shaken implementations. There were also a number of stir-shaken features and RFC requirements that were never implemented such as TNAuthList certificate validation, sending Reason headers in SIP responses when verification failed but we wished to continue the call, and the ability to send Media Key(mky) grants in the Identity header when the call involved DTLS. Finally, there were some performance concerns around outgoing calls and selection of the correct certificate and private key. The configuration was keyed by an arbitrary name which meant that for every outgoing call, we had to scan the entire list of configured TNs to find the correct cert to use. With only a few TNs configured, this wasn't an issue but if you have a thousand, it could be. What's changed? * Configuration objects have been refactored to be clearer about their uses and to fix issues. * The "general" object was renamed to "verification" since it contains parameters specific to the incoming verification process. It also never handled ca_path and crl_path correctly. * A new "attestation" object was added that controls the outgoing attestation process. It sets default certificates, keys, etc. * The "certificate" object was renamed to "tn" and had it's key change to telephone number since outgoing call attestation needs to look up certificates by telephone number. * The "profile" object had more parameters added to it that can override default parameters specified in the "attestation" and "verification" objects. * The "store" object was removed altogther as it was never implemented. * We now use libjwt to create outgoing Identity headers and to parse and validate signatures on incoming Identiy headers. Our previous custom implementation was much of the source of the interoperability issues. * General code cleanup and refactor. * Moved things to better places. * Separated some of the complex functions to smaller ones. * Using context objects rather than passing tons of parameters in function calls. * Removed some complexity and unneeded encapsuation from the config objects. UserNote: Asterisk's stir-shaken feature has been refactored to correct interoperability, RFC compliance, and performance issues. See https://docs.asterisk.org/Deployment/STIR-SHAKEN for more information. UpgradeNote: The stir-shaken refactor is a breaking change but since it's not working now we don't think it matters. The stir_shaken.conf file has changed significantly which means that existing ones WILL need to be changed. The stir_shaken.conf.sample file in configs/samples/ has quite a bit more information. This is also an ABI breaking change since some of the existing objects needed to be changed or removed, and new ones added.
1 parent db45705 commit 8c177e8

30 files changed

+7196
-8
lines changed
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
;--
2+
3+
There are 4 object types used by the STIR/SHAKEN process...
4+
5+
The "verification" object sets the parameters for verification
6+
of the Identity header and caller id on incoming INVITE requests.
7+
8+
The "attestation" object sets the parameters for creating an Identity
9+
header which attests to the ownership of the caller id on outgoing
10+
INVITE requests.
11+
12+
One or more "tn" objects that are used to create the outgoing Identity
13+
header. Each object's "id" is a specific caller-id telephone number
14+
and the object contains the URL to the certificate that was used to
15+
attest to the ownership of the caller-id, the level (A,B,C) of the
16+
attestation you're making, and the private key the asterisk
17+
attestation service will use to sign the Identity header. When
18+
an outgoing INVITE request is placed, the attestation service will
19+
look up the caller-id in the tn object list and if it's found, use
20+
the information in the object to create the Identity header.
21+
22+
One or more "profile" objects that can be associated to channel
23+
driver endpoints (currently only chan_pjsip). Profiles can set
24+
whether verification, attestation, both or neither should be
25+
performed on requests coming in to this endpoint or requests
26+
going out from this endpoint. They can also set acls on what URLs
27+
we should be allowed to retrieve certificates from on incoming
28+
requests.
29+
30+
--;
31+
32+
33+
;--
34+
=======================================================================
35+
Verification Object Description
36+
=======================================================================
37+
The "verification" object sets the parameters for verification
38+
of the Identity header on incoming INVITE requests.
39+
Only one "verification" object may exist.
40+
41+
Parameters:
42+
43+
-- global_disable -----------------------------------------------------
44+
If set, globally disables the verification service.
45+
Default: no
46+
47+
-- load_system_certs---------------------------------------------------
48+
If set, loads the system Certificate Authority certificates
49+
(usually located in /etc/pki/CA) into the trust store used to
50+
validate the certificates in incoming requests. This is not
51+
normally required as service providers will usually provide their
52+
CA certififcate to you separately.
53+
Default: no
54+
55+
-- ca_file -----------------------------------------------------------
56+
Path to a single file containing a CA certificate or certificate chain
57+
to be used to validate the certificates in incoming requests.
58+
Default: none
59+
60+
-- ca_path -----------------------------------------------------------
61+
Path to a directory containing one or more CA certificates to be used
62+
to validate the certificates in incoming requests. The files in that
63+
directory must contain only one certificate each and the directory
64+
must be hashed using the OpenSSL 'c_rehash' utility.
65+
Default: none
66+
67+
NOTE: Both ca_file and ca_path can be specified but at least one
68+
MUST be.
69+
70+
-- crl_file -----------------------------------------------------------
71+
Path to a single file containing a CA certificate revocation list
72+
to be used to validate the certificates in incoming requests.
73+
Default: none
74+
75+
-- crl_path -----------------------------------------------------------
76+
Path to a directory containing one or more CA certificate revocation
77+
lists to be used to validate the certificates in incoming requests.
78+
The files in that directory must contain only one certificate each and
79+
the directory must be hashed using the OpenSSL 'c_rehash' utility.
80+
Default: none
81+
82+
NOTE: Neither crl_file nor crl_path are required.
83+
84+
-- cert_cache_dir -----------------------------------------------------
85+
Incoming Identity headers will have a URL pointing to the certificate
86+
used to sign the header. To prevent us from having to retrieve the
87+
certificate for every request, we maintain a cache of them at the
88+
'cert_cache_dir' specified. The directory will be checked for
89+
existence and writability at startup.
90+
Default: <astvarlibdir>/keys/stir_shaken/cache
91+
92+
-- max_cache_entry_age ------------------------------------------------
93+
Maximum number of seconds after retrieval a certificate in the cache
94+
can be used before re-retrieving it.
95+
Default: 3600 (1 hour)
96+
97+
-- max_cache_size -----------------------------------------------------
98+
Maximum number of entries the cache can hold.
99+
Not presently implemented.
100+
101+
-- curl_timeout -------------------------------------------------------
102+
The number of seconds we'll wait for a response when trying to retrieve
103+
the certificate specified in the incoming Identity header.
104+
Default: 2
105+
106+
-- max_iat_age --------------------------------------------------------
107+
The "iat" parameter in the Identity header indicates the time the
108+
sender actually created their attestation. If that is older than the
109+
number of seconds set here, the request will be considered "failed".
110+
Default: 15
111+
112+
-- max_date_header_age ------------------------------------------------
113+
The sender MUST also send a SIP Date header in their request. If we
114+
receive one that is older than the number of seconds set here, the
115+
request will be considered "failed".
116+
Default: 15
117+
118+
-- failure_action -----------------------------------------------------
119+
Indicates what will happen to requests that have failed verification.
120+
Must be one of:
121+
- continue -
122+
Continue processing the request. You can use the
123+
STIR_SHAKEN dialplan function to determine whether
124+
the request passed or failed verification and take
125+
the action you deem appropriate.
126+
127+
- reject_request -
128+
Reject the request immediately using the SIP response codes
129+
defined by RFC8224.
130+
131+
- continue_return_reason -
132+
Continue processing the request but send a SIP Reason header
133+
back to the originator in the next provisional response indicating
134+
the issue according to RFC8224. You can use the STIR_SHAKEN
135+
dialplan function to determine whether the request passed or
136+
failed verification and take the action you deem appropriate.
137+
138+
Default: continue
139+
NOTE: This parameter may be overridden in profile objects defined
140+
below.
141+
142+
-- use_rfc9410_responses ----------------------------------------------
143+
If set, when sending Reason headers back to originators, the protocol
144+
header parameter will be set to "STIR" rather than "SIP". This is a
145+
new protocol defined in RFC9410 and may not be supported by all
146+
participants.
147+
Default: no
148+
NOTE: This parameter may be overridden in profile objects defined
149+
below.
150+
151+
Example:
152+
--;
153+
154+
;[verification]
155+
;global_disable = yes
156+
;load_system_certs = no
157+
;ca_path = /var/lib/asterisk/keys/stir_shaken/verification_ca
158+
;cert_cache_dir = /var/lib/asterisk/keys/stir_shaken/verification_cache
159+
;failure_action = reject_request
160+
;curl_timeout=5
161+
;max_iat_age=60
162+
;max_date_header_age=60
163+
;max_cache_entry_age = 300
164+
165+
;--
166+
=======================================================================
167+
Attestation Object Description
168+
=======================================================================
169+
The "attestation" object sets the parameters for creating an Identity
170+
header which attests to the ownership of the caller id on outgoing
171+
INVITE requests.
172+
Only one "attestation" object may exist.
173+
174+
Parameters:
175+
176+
-- global_disable -----------------------------------------------------
177+
If set, globally disables the attestation service. No Identity headers
178+
will be added to any outgoing INVITE requests.
179+
Default: no
180+
181+
-- check_tn_cert_public_url -------------------------------------------
182+
Identity headers in outgoing requests must contain a URL that points
183+
to the certificate used to sign the header. Setting this parameter
184+
tells Asterisk to actually try to retrieve the certificates defined
185+
in the "tn" objects defined below and fail loading that tn if the cert
186+
can't be retrieved or if its 'Not Valid Before" -> 'Not Valid After"
187+
date range doesn't include today. This is a network intensive process
188+
so use with caution.
189+
Default: no
190+
191+
-- default_public_cert_url --------------------------------------------
192+
The URL to the certificate you received from the issueing authority.
193+
They may give you a URL to use or you may have to host the certificate
194+
yourself and provide your own URL here.
195+
Default: none
196+
WARNING: Make absolutely sure the file that's made public doesn't
197+
accidentally include the privite key as well as the certificate.
198+
If you set "check_tn_cert_public_url" in the "attestation" section
199+
above, the tn will not be loaded and a "DANGER" message will be output
200+
on the asterisk console if the file does contain a private key.
201+
NOTE: This parameter may be overridden in "tn" objects defined below.
202+
203+
-- default_private_key_file -------------------------------------------
204+
The path to a file containing the private key you received from the
205+
issuing authority. The file must NOT be group or world readable or
206+
writable so make sure the user the asterisk process is running as is
207+
the owner.
208+
Default: none
209+
NOTE: This parameter may be overridden in "tn" objects defined below.
210+
211+
-- default_attest_level -----------------------------------------------
212+
The level of the attestation you're making.
213+
One of "A", "B", "C"
214+
Default: none
215+
NOTE: This parameter may be overridden in "tn" objects defined below.
216+
217+
-- default_send_mky -----------------------------------------------------------
218+
If set and an outgoing call uses DTLS, an "mky" Media Key grant will
219+
be added to the Identity header. Although RFC8224/8225 require this,
220+
not many implementations support it so a remote verification service
221+
may fail to verify the signature.
222+
Default: no
223+
224+
Example:
225+
--;
226+
227+
;[attestation]
228+
;global_disable = no
229+
;default_private_key_path = /var/lib/asterisk/keys/stir_shaken/tns/multi-tns-key.pem
230+
;default_public_cert_url = https://example.com/tncerts/multi-tns-cert.pem
231+
;default_attest_level = C
232+
233+
;--
234+
=======================================================================
235+
TN Object Description
236+
=======================================================================
237+
Each "tn" object contains the parameters needed to create the Identity
238+
header used to attest to the ownership of the caller-id on outgoing
239+
requests. When an outgoing INVITE request is placed, the attestation
240+
service will look up the caller-id in this list and if it's found, use
241+
the information in the object to create the Identity header.
242+
The private key and certificate needed to sign the Identity header are
243+
usually provided to you by the telephone number issuing authority along
244+
with their certificate authority certificate. You should give the CA
245+
certificate to any recipients who expect to receive calls from you
246+
although this has probably already been done by the issuing authority.
247+
248+
The "id" of this object MUST be a canonicalized telephone nmumber which
249+
starts with a country code. The only valid characters are the numbers
250+
0-9, '#' and '*'.
251+
252+
Parameters:
253+
254+
-- type (required) ----------------------------------------------------
255+
Must be set to "tn"
256+
Default: none
257+
258+
-- public_cert_url (required) -----------------------------------------
259+
The URL to the certificate you received from the issueing authority.
260+
They may give you a URL to use or you may have to host the certificate
261+
yourself and provide your own URL here.
262+
Default: <default_public_cert_url from attestation>
263+
WARNING: Make absolutely sure the file that's made public doesn't
264+
accidentally include the privite key as well as the certificate.
265+
If you set "check_tn_cert_public_url" in the "attestation" section
266+
above, the tn will not be loaded and a "DANGER" message will be output
267+
on the asterisk console if the file does contain a private key.
268+
269+
-- private_key_file (required) ----------------------------------------
270+
The path to a file containing the private key you received from the
271+
issuing authority. The file must NOT be group or world readable or
272+
writable so make sure the user the asterisk process is running as is
273+
the owner.
274+
Default: <default_private_key_file from attestation>
275+
276+
-- attest_level (required) --------------------------------------------
277+
The level of the attestation you're making.
278+
One of "A", "B", "C"
279+
Default: <default_attest_level from attestation>
280+
281+
Example:
282+
--;
283+
284+
;[18005551515]
285+
;type = tn
286+
;private_key_path = /var/lib/asterisk/keys/stir_shaken/tns/18005551515-key.pem
287+
;public_cert_url = https://example.com/tncerts/18005551515-cert.pem
288+
;attest_level = C
289+
290+
291+
;--
292+
=======================================================================
293+
Profile Object Description
294+
=======================================================================
295+
A "profile" object can be associated to channel driver endpoint
296+
(currently only chan_pjsip) and can set verification and attestation
297+
parameters specific to endpoints using this profile. If you have
298+
multiple upstream providers, this is the place to set parameters
299+
specific to them.
300+
301+
The "id" of this object is arbitrary and you'd specify it in the
302+
"stir_shaken_profile" parameter of the endpoint.
303+
304+
Parameters:
305+
306+
-- type (required) ----------------------------------------------------
307+
Must be set to "profile"
308+
Default: none
309+
310+
-- permit/deny --------------------------------------------------------
311+
To help prevent MITM attacks, you can restrict from where you can
312+
retrieve certificates during the verification process. This can prevent
313+
an attacker from sending you a request pretending to be a known
314+
originator with a mailcious certificate URL. See acl.conf.sample to
315+
see examples of how to specify the permit/deny parameters.
316+
Default: none
317+
318+
-- acllist ------------------------------------------------------------
319+
Rather than providing individual permit/deny parameters, you can set
320+
the acllist parameter to an acl list predefined in acl.conf.
321+
Default: none
322+
323+
All of the "verification" parameters defined above can be set on a profile
324+
with the exception of 'global_disable' and 'load_system_certs'.
325+
326+
All of the "attestation" parameters defined aboive can be set on a profile
327+
with the exception of 'global_disable'.
328+
329+
Example:
330+
--;
331+
332+
;[myprofile]
333+
;type = profile
334+
;behavior = verify
335+
;failure_action = continue_return_reason
336+
;acllist = myacllist
337+
338+
;In pjsip.conf...
339+
;[myendpoint]
340+
;type = endpoint
341+
;stir_shaken_profile = myprofile
342+
343+
;In acl.conf...
344+
;[myacllist]
345+
;permit=0.0.0.0/0.0.0.0
346+
;deny=10.24.20.171
347+

include/asterisk/astdb.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ int ast_db_get(const char *family, const char *key, char *value, int valuelen);
5050
*/
5151
int ast_db_get_allocated(const char *family, const char *key, char **out);
5252

53+
/*!
54+
* \brief Check if family/key exitsts
55+
*
56+
* \param family
57+
* \param key
58+
* \retval 1 if family/key exists
59+
* \retval 0 if family/key does not exist or an error occurred
60+
*/
61+
int ast_db_exists(const char *family, const char *key);
62+
5363
/*! \brief Store value addressed by family/key */
5464
int ast_db_put(const char *family, const char *key, const char *value);
5565

include/asterisk/res_pjsip.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,8 @@ struct ast_sip_endpoint {
975975
AST_STRING_FIELD(accountcode);
976976
/*! If set, we'll push incoming MWI NOTIFYs to stasis using this mailbox */
977977
AST_STRING_FIELD(incoming_mwi_mailbox);
978+
/*! STIR/SHAKEN profile to use */
979+
AST_STRING_FIELD(stir_shaken_profile);
978980
);
979981
/*! Configuration for extensions */
980982
struct ast_sip_endpoint_extensions extensions;
@@ -1044,6 +1046,8 @@ struct ast_sip_endpoint {
10441046
enum ast_sip_security_negotiation security_negotiation;
10451047
/*! Client security mechanisms (RFC 3329). */
10461048
struct ast_sip_security_mechanism_vector security_mechanisms;
1049+
/*! Set which STIR/SHAKEN behaviors we want on this endpoint */
1050+
unsigned int stir_shaken;
10471051
/*! Should we authenticate OPTIONS requests per RFC 3261? */
10481052
unsigned int allow_unauthenticated_options;
10491053
/*! The name of the geoloc profile to apply when Asterisk receives a call from this endpoint */

0 commit comments

Comments
 (0)