`switch_core_media_add_crypto()` parses the SDP `a=crypto` keysalt and
decodes it into a fixed-size key buffer. Enforce the buffer contract at
the call site:
- Reject a zero-length, negative, or over-long keysalt (the length
check now has both a lower bound and an upper bound against the copy
buffer).
- Copy the keysalt token into a NUL-terminated buffer and decode from
that, so `switch_b64_decode` stops at the token instead of reading on
into the following key material (it consumes input to the NUL and
skips non-base64 bytes).
- Pass the destination buffer size as the decode bound rather than the
parsed token length.
- Require the decoded length to cover the crypto suite's key+salt so the
subsequent copy cannot read past the decoded bytes.
Add `test_add_crypto_keysalt_bounds`, a table-driven test covering the
accepted and rejected keysalt shapes across suites (AES-128/192/256),
including RFC 4568 lifetime/MKI and multi-key lines.
The RTCP NACK feedback handler used the packet's header length field as the
loop bound instead of the byte count the caller already validated. An
oversized length ran the loop past the fixed-size RTCP buffer, an
out-of-bounds access.
Clamp the entry count to the feedback words that fit in the received packet.
Add an end-to-end test feeding an oversized-length NACK through the RTCP
reader.
The positive-offset branch of `${variable:offset}` expansion advanced
`sub_val` past the cloned heap buffer without bounds-checking `offset`
against `strlen(sub_val)`. Subsequent `strlen()` and `strcat()` then
read adjacent heap memory into the output buffer.
* [Core, mod_commands] Interface allowlist (#3086)
* [core] Add interface allowlist to gate module app/api registration
Adds an optional, presence-activated allowlist in switch.conf.xml that
controls which modules may register application / api / json_api /
chat-application interfaces. With no <interface-allowlist> configured
nothing is enforced; when at least one <allow> entry is present, only
listed interfaces register at load time and all others are refused (the
module still loads and switch_loadable_module_process still returns
SUCCESS -- the blocked interface is simply never exposed).
Entries match at three levels of precision:
mod_commands - whole module
mod_commands.system - any interface named "system"
mod_commands.system.api - a specific type (app|api|json_api|chat_app)
Enforcement lives in switch_loadable_module_process() so every module, at
boot and at runtime `load`, is subject to the same policy. This gives
operators a way to disable the "system"/"spawn" shell-exec API commands
(and equivalents) system-wide.
Also adds the `interface_allowlist_dump [modules] [plain]` API, which
walks the loaded modules and prints their interfaces in the allowlist key
format so the current state can be captured and pruned offline into config.
* [mod_commands] Add tests for the interface allowlist
New test_interface_allowlist boots the core with an active
<interface-allowlist> (conf_interface_allowlist/) that permits only a
couple of mod_commands interfaces, then loads mod_commands and verifies:
- listed commands register and run (status, version) while unlisted and
shell-exec commands are refused (system, spawn, uptime) -- refusal
surfaces as switch_api_execute returning FALSE / command-not-found,
with the command function never invoked;
- a "module.name.type" entry gates by type: the API "status" loads while
the JSON API of the same name stays blocked;
- interface_allowlist_dump prints the config format in its xml, modules
and plain variants, and reflects module capabilities (system appears in
the dump even though it was blocked from registering).
* [config] Fix interior -- in interface-allowlist comment breaking XML parse
The explanatory comment used -- as em-dash pairs. The XML parser treats
-- inside a comment as the comment close, causing an "unclosed <!--"
error that prevents the whole freeswitch.xml from parsing (boot and
reloadxml both fail). Replace the -- pairs with ordinary punctuation.
* update .gitignore
* [core] Warn when interface-allowlist section is present but parses no entries
Co-authored-by: Chris Rienzo <chris@signalwire.com>
* Merge commit from fork
Add `switch_stun_packet_verify_integrity()`, an HMAC-SHA1
MESSAGE-INTEGRITY verifier that is const and non-mutating: it runs
over a private copy of the pristine network-order packet, so the
caller's buffer and byte order stay untouched, and walks attributes
with its own unsigned bounded helper `stun_wire_attr_bounds()`
instead of the host-order iterator macros. A trailing
MESSAGE-INTEGRITY-SHA256 or FINGERPRINT after MESSAGE-INTEGRITY is
tolerated; any other trailing attribute is rejected.
Gate it in `handle_ice()` behind `ice->verify_integrity`: verify
before any ICE state is touched, keyed by message type (local
`ice->pass` for a request, remote `ice->rpass` for a response or
error response), and drop on failure. Keepalive indications carry no
MESSAGE-INTEGRITY and are ignored.
`ice->verify_integrity` is read from the `ice_verify_message_integrity`
channel variable in `switch_rtp_activate_ice()` and defaults off, so
receive-path behavior is unchanged unless it is enabled. Adds unit
tests in `tests/unit/switch_stun.c`.
* Merge commit from fork
* [core] Verify DTLS client cert against SDP fingerprint (server role)
Add opt-in verification of the client certificate when FreeSWITCH is
the DTLS server, mirroring the binding the client role already performs
on the server certificate: match the peer certificate against the SDP
`a=fingerprint` in `dtls_state_setup()`.
Selected per call by the `rtp_dtls_client_cert_verify_mode` channel
variable (`dtls_client_cert_verify_t`). An unset variable keeps the
default `DTLS_CLIENT_CERT_VERIFY_NONE`, so existing behavior is
unchanged:
- `none`: the server does not request a client certificate.
- `fingerprint`: request it (`SSL_VERIFY_PEER` + `dtls_accept_any_cert`)
and require its fingerprint to match the SDP value; a self-signed
certificate is accepted at the TLS layer and the match provides
authenticity.
- `full`: additionally let OpenSSL enforce the certificate chain.
An unrecognized mode string falls back to `fingerprint` (fail closed)
with a warning.
The mode is set per `SSL` object in `switch_rtp_add_dtls()`. Verification
fails (`DS_FAIL`, no SRTP keys derived) when the client presents no
certificate, its fingerprint does not match, or the peer advertised no
usable `a=fingerprint`: `get_evp_by_name()` returns `NULL` for a missing
or empty hash type and `switch_core_cert_extract_fingerprint()` rejects a
`NULL` algorithm rather than passing it to `X509_digest()`.
`conf/vanilla/vars.xml` documents the knob as a disabled example. Tests
in `tests/unit/switch_rtp.c` cover matching, mismatched, absent-cert,
absent-fingerprint, `none`, and unrecognized-mode cases.
---------
Co-authored-by: Andrey Volk <andywolk@gmail.com>
Co-authored-by: Chris Rienzo <chris@signalwire.com>
`read_packet()` passed a peer-supplied `Content-Length` straight to
`switch_zmalloc(body, clen + 1)`. Huge values drove `calloc` failure
and `switch_zmalloc` `abort()`-ed the daemon.
- Cap `Content-Length` at 16 MiB; reject negatives.
- Destroy the partially-built `*event` at the new rejection site and
at the existing body-recv failure path so callers don't leak it.
- Add `test_mod_event_socket` covering `INT_MAX`, above-cap,
negative, `atoi`-overflow, zero, and valid-non-zero-body cases.
Add `switch_stun_packet_verify_integrity()`, an HMAC-SHA1
MESSAGE-INTEGRITY verifier that is const and non-mutating: it runs
over a private copy of the pristine network-order packet, so the
caller's buffer and byte order stay untouched, and walks attributes
with its own unsigned bounded helper `stun_wire_attr_bounds()`
instead of the host-order iterator macros. A trailing
MESSAGE-INTEGRITY-SHA256 or FINGERPRINT after MESSAGE-INTEGRITY is
tolerated; any other trailing attribute is rejected.
Gate it in `handle_ice()` behind `ice->verify_integrity`: verify
before any ICE state is touched, keyed by message type (local
`ice->pass` for a request, remote `ice->rpass` for a response or
error response), and drop on failure. Keepalive indications carry no
MESSAGE-INTEGRITY and are ignored.
`ice->verify_integrity` is read from the `ice_verify_message_integrity`
channel variable in `switch_rtp_activate_ice()` and defaults off, so
receive-path behavior is unchanged unless it is enabled. Adds unit
tests in `tests/unit/switch_stun.c`.
Cap `Content-Length` at `HTTP_POST_MAX_BODY` (10 MiB) and size the
allocation to the actual body length (`content_length + 1` for
the trailing NUL).
Also fix `WS_BLOCK` units — `kws_raw_read` takes ms, set to 10000.
Route IPv6 writes in `switch_stun_packet_attribute_add_binded_address`
and `switch_stun_packet_attribute_add_xor_binded_address` through
`switch_stun_ipv6_t` (16-byte `address[]`) instead of `switch_stun_ip_t`
(4-byte `uint32_t address`).
Add IPv4/IPv6 unit tests for both encoders.
Co-authored-by: Andrey Volk <andywolk@gmail.com>
* [Unit-tests] Add a test provoking switch_event_add_header to memory leak.
* [Core] Fix switch_event_base_add_header leaking memory when headers are with indexes.
Recent changes made it impossible to compile freeswitch without libyuv
support.
src/switch_core_video.c: In function 'switch_img_read_from_file':
src/switch_core_video.c:3139:4: error: implicit declaration of function 'RAWToI420' [-Werror=implicit-function-declaration]
RAWToI420(data, width * 3,
^
src/switch_core_video.c:3148:4: error: implicit declaration of function 'ABGRToARGB' [-Werror=implicit-function-declaration]
ABGRToARGB(data, width * 4, img->planes[SWITCH_PLANE_PACKED], img->stride[SWITCH_PLANE_PACKED], width, height);
^
Fix this my adding/moving the checks for "SWITCH_HAVE_YUV".
Signed-off-by: Sebastian Kemper <sebastian_ml@gmx.net>
* [core] Add SMBF_PAUSE media bug flag to pause an individual media bug.
[core] Add switch_ivr_record_session_pause() to pause a session recording.
[mod_dptools] Add record_session_pause and record_session_resume dialplan APPs.
[mod_commands] Add pause/resume sub-commands to uuid_record API.