res_stir_shaken: Add outbound INVITE support.

Integrated STIR/SHAKEN support with outgoing INVITEs. When an INVITE is
sent, the caller ID will be checked to see if there is a certificate
that corresponds to it. If so, that information will be retrieved and an
Identity header will be added to the SIP message. The format is:

header.payload.signature;info=<public_key_url>alg=ES256;ppt=shaken

Header, payload, and signature are all BASE64 encoded. The public key
URL is retrieved from the certificate. Currently the algorithm and ppt
are ES256 and shaken, respectively. This message is signed and can be
used for verification on the receiving end.

Two new configuration options have been added to the certificate object:
attestation and origid. The attestation is required and must be A, B, or
C. origid is the origination identifier.

A new utility function has been added as well that takes a string,
allocates space, BASE64 encodes it, then returns it, eliminating the
need to calculate the size yourself.

Change-Id: I1f84d6a5839cb2ed152ef4255b380cfc2de662b4
This commit is contained in:
Ben Ford
2020-06-02 09:04:23 -05:00
committed by Friendly Automation
parent db012e8cc6
commit 1274117102
8 changed files with 239 additions and 22 deletions

View File

@@ -99,6 +99,12 @@
Must be a valid http, or https, URL.
</para></description>
</configOption>
<configOption name="attestation">
<synopsis>Attestation level</synopsis>
</configOption>
<configOption name="origid" default="">
<synopsis>The origination ID</synopsis>
</configOption>
<configOption name="caller_id_number" default="">
<synopsis>The caller ID number to match on.</synopsis>
</configOption>
@@ -136,10 +142,6 @@
</function>
***/
#define STIR_SHAKEN_ENCRYPTION_ALGORITHM "ES256"
#define STIR_SHAKEN_PPT "shaken"
#define STIR_SHAKEN_TYPE "passport"
static struct ast_sorcery *stir_shaken_sorcery;
/* Used for AstDB entries */
@@ -184,6 +186,16 @@ void ast_stir_shaken_payload_free(struct ast_stir_shaken_payload *payload)
ast_free(payload);
}
unsigned char *ast_stir_shaken_payload_get_signature(const struct ast_stir_shaken_payload *payload)
{
return payload ? payload->signature : NULL;
}
char *ast_stir_shaken_payload_get_public_key_url(const struct ast_stir_shaken_payload *payload)
{
return payload ? payload->public_key_url : NULL;
}
unsigned int ast_stir_shaken_get_signature_timeout(void)
{
return ast_stir_shaken_signature_timeout(stir_shaken_general_get());
@@ -1020,6 +1032,7 @@ struct ast_stir_shaken_payload *ast_stir_shaken_sign(struct ast_json *json)
{
struct ast_stir_shaken_payload *ss_payload;
unsigned char *signature;
const char *public_key_url;
const char *caller_id_num;
const char *header;
const char *payload;
@@ -1049,22 +1062,19 @@ struct ast_stir_shaken_payload *ast_stir_shaken_sign(struct ast_json *json)
goto cleanup;
}
if (stir_shaken_add_x5u(json, stir_shaken_certificate_get_public_key_url(cert))) {
public_key_url = stir_shaken_certificate_get_public_key_url(cert);
if (stir_shaken_add_x5u(json, public_key_url)) {
ast_log(LOG_ERROR, "Failed to add 'x5u' (public key URL) to payload\n");
goto cleanup;
}
ss_payload->public_key_url = ast_strdup(public_key_url);
/* TODO: This is just a placeholder for adding 'attest', 'iat', and
* 'origid' to the payload. Later, additional logic will need to be
* added to determine what these values actually are, but the functions
* themselves are ready to go.
*/
if (stir_shaken_add_attest(json, "B")) {
if (stir_shaken_add_attest(json, stir_shaken_certificate_get_attestation(cert))) {
ast_log(LOG_ERROR, "Failed to add 'attest' to payload\n");
goto cleanup;
}
if (stir_shaken_add_origid(json, "asterisk")) {
if (stir_shaken_add_origid(json, stir_shaken_certificate_get_origid(cert))) {
ast_log(LOG_ERROR, "Failed to add 'origid' to payload\n");
goto cleanup;
}