diff --git a/Dockerfile b/Dockerfile index f12e3c3..ad45e5c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ RUN curl -o /usr/share/keyrings/opensips-org.gpg https://apt.opensips.org/opensi # 3. Install OpenSIPS & Modules RUN apt-get -y update -qq && apt-get -y install opensips opensips-mysql-module \ opensips-regex-module opensips-restclient-module opensips-http-modules \ - opensips-json-module opensips-tls-module opensips-auth-modules opensips-wss-module make && \ + opensips-json-module opensips-tls-module opensips-auth-modules opensips-wss-module opensips-stir-shaken-module make && \ rm -rf /var/lib/apt/lists/* # 4. Setup Dual Logging Routing (rsyslog) diff --git a/configs/opensips.cfg.template b/configs/opensips.cfg.template index 8f5235e..41e725c 100644 --- a/configs/opensips.cfg.template +++ b/configs/opensips.cfg.template @@ -189,6 +189,11 @@ loadmodule "rtpengine.so" modparam("rtpengine", "db_url", "mysql://{{{db_user}}}:{{{db_pass}}}@{{{db_host}}}/{{{db_opensips}}}") #modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:2223") +loadmodule "stir_shaken.so" +# Path to your signing certificate (Public Key) +modparam("stir_shaken", "ca_list", "/etc/opensips/tls/vs/ca_bundle.crt") + + loadmodule "uac.so" #### ACCounting module @@ -413,6 +418,48 @@ route{ route(RELAY); } +route[AS_SERVICE] { + # 1. Define your parameters + $var(attest) = "A"; # Attestation Level (A, B, or C) + $var(origid) = "your-orig-uuid"; # Your UUID/Originating ID + $var(cert) = "/etc/opensips/tls/vs/cert.pem"; # Local Path to Public Cert + $var(key) = "/etc/opensips/tls/vs/key.pem"; # Local Path to Private Key + + # The X5U is the URL where the CALLEE can download your public cert + $var(x5u) = "https://{{{deployment_domain}}}/stir-shaken/cert.pem"; + + # 2. Call the function with correct parameter order: + # stir_shaken_auth(attest, origid, cert, pkey, x5u) + if (!stir_shaken_auth($var(attest), $var(origid), $var(cert), $var(key), $var(x5u))) { + xlog("L_ERR", "STIR/SHAKEN signing failed with error code $rc!\n"); + # Optional: You may want to exit or send a reply if signing is mandatory + } else { + xlog("L_INFO", "STIR/SHAKEN Identity header successfully generated\n"); + } +} + +route[VS_SERVICE] { + if (is_present_hf("Identity")) { + # 1. Provide the variable names directly (no quotes) + # OpenSIPS will populate these variables automatically on call + if (stir_shaken_verify($var(cert_out), $var(err_code), $var(err_reason))) { + xlog("L_INFO", "STIR/SHAKEN Verification Successful - Identity Verified\n"); + } else { + # 2. Now you can use them as normal with the $ prefix + xlog("L_WARN", "STIR/SHAKEN Verification Failed - Code: $var(err_code) Reason: $var(err_reason)\n"); + + if ($var(err_code) == "-4") { + send_reply(438, "Stale Identity Header"); + } else { + send_reply(438, "Invalid Identity Header"); + } + exit; + } + } else { + xlog("L_INFO", "No Identity header present to verify\n"); + } +} + route[WITHINDLG] { # Handle in-dialog requests (ACK/BYE/reINVITE/UPDATE/INFO/OPTIONS/etc.) # Must be called only when has_totag() is true. @@ -664,6 +711,9 @@ route[INTERNAL_EXTENSION_ROUTING] { route[PSTN_ROUTING] { xlog("SOURCE IP IS: $si"); + + # STIR/SHAKEN verification + # route(VS_SERVICE); if ($hdr(X-LineBlocs-RingSubscriber) == "true") { xlog("sending to extension...\r\n"); @@ -812,7 +862,7 @@ route[INCOMING_VALIDATION_2] { route[DID_ASSIGNED] { if ($var(rcode) != 200) { - send_reply(400, "Bad Request -- DID lookup failed"); + send_reply(400, "Bad Request (scenario 1)"); exit; } @@ -828,7 +878,7 @@ route[DID_ASSIGNED] { route[TRUNK_ASSIGNED] { if ($var(rcode) != 200) { - send_reply(400, "Bad Request"); + send_reply(400, "Bad Request (scenario 2)"); exit; } @@ -845,7 +895,7 @@ route[TRUNK_ASSIGNED] { route[CALL_ACTION] { if ($var(rcode) != 200) { - send_reply(400, "Bad Request"); + send_reply(400, "Bad Request (scenario 3)"); exit; } @@ -1588,4 +1638,4 @@ route[RTPENGINE_ANSWER] { rtpengine_use_set(1); xlog("L_INFO", "RTP Answer Flags: $var(ans_flags)\n"); rtpengine_answer("$var(ans_flags)"); -} \ No newline at end of file +} diff --git a/tls/vs/ca_bundle.crt b/tls/vs/ca_bundle.crt new file mode 100644 index 0000000..3a7d76d --- /dev/null +++ b/tls/vs/ca_bundle.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSzCCAfGgAwIBAgIUL1NXIQGwQ1KYrDV2jUm1h2jcuWgwCgYIKoZIzj0EAwIw +ezELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB0FsYmVydGExETAPBgNVBAcMCEVkbW9u +dG9uMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxJDAiBgkqhkiG +9w0BCQEWFW5oYW1pZEBkeW5hbW9jbG91ZC5jYTAeFw0yNjA0MTMwMDI2NDBaFw0y +NzA0MTMwMDI2NDBaMHsxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMREw +DwYDVQQHDAhFZG1vbnRvbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg +THRkMSQwIgYJKoZIhvcNAQkBFhVuaGFtaWRAZHluYW1vY2xvdWQuY2EwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAAThGp9Vwm6X9rKZaRujtr75d7Ll7hfPcM0s1mp7 +Cne5SeueDGvYALmaLHtvMMzHC1vI4KxeUfJuPEdeZptQSOngo1MwUTAdBgNVHQ4E +FgQUIFeNyAHqObnvm/XCtqQL5SgUiWMwHwYDVR0jBBgwFoAUIFeNyAHqObnvm/XC +tqQL5SgUiWMwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAoqYv +39l3OS/Q6GLcBC7d1yGBoih10+haa/YM+7l+UTYCIB7F32kL8J0W70t5M/k6zdWQ +5O/O+pS/162fbt6VEOev +-----END CERTIFICATE----- diff --git a/tls/vs/cert.pem b/tls/vs/cert.pem new file mode 100644 index 0000000..3a7d76d --- /dev/null +++ b/tls/vs/cert.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSzCCAfGgAwIBAgIUL1NXIQGwQ1KYrDV2jUm1h2jcuWgwCgYIKoZIzj0EAwIw +ezELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB0FsYmVydGExETAPBgNVBAcMCEVkbW9u +dG9uMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxJDAiBgkqhkiG +9w0BCQEWFW5oYW1pZEBkeW5hbW9jbG91ZC5jYTAeFw0yNjA0MTMwMDI2NDBaFw0y +NzA0MTMwMDI2NDBaMHsxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMREw +DwYDVQQHDAhFZG1vbnRvbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg +THRkMSQwIgYJKoZIhvcNAQkBFhVuaGFtaWRAZHluYW1vY2xvdWQuY2EwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAAThGp9Vwm6X9rKZaRujtr75d7Ll7hfPcM0s1mp7 +Cne5SeueDGvYALmaLHtvMMzHC1vI4KxeUfJuPEdeZptQSOngo1MwUTAdBgNVHQ4E +FgQUIFeNyAHqObnvm/XCtqQL5SgUiWMwHwYDVR0jBBgwFoAUIFeNyAHqObnvm/XC +tqQL5SgUiWMwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAoqYv +39l3OS/Q6GLcBC7d1yGBoih10+haa/YM+7l+UTYCIB7F32kL8J0W70t5M/k6zdWQ +5O/O+pS/162fbt6VEOev +-----END CERTIFICATE----- diff --git a/tls/vs/key.pem b/tls/vs/key.pem new file mode 100644 index 0000000..67a1e97 --- /dev/null +++ b/tls/vs/key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIHQ9A7eboPAePSYseNa2XKmgB6OuH4yr13T1Rb2LVvT+oAoGCCqGSM49 +AwEHoUQDQgAE4RqfVcJul/aymWkbo7a++Xey5e4Xz3DNLNZqewp3uUnrngxr2AC5 +mix7bzDMxwtbyOCsXlHybjxHXmabUEjp4A== +-----END EC PRIVATE KEY-----