feat(libsrtp): add component (libsrtp v2.8.0 + ESP-IDF mbedTLS port)

Adds libsrtp — an ESP-IDF wrapper around cisco/libsrtp pinned at v2.8.0
(commit 24b3bf8). Crypto routes through ESP-IDF's mbedTLS, so AES
protect/unprotect goes through the chip's on-chip AES peripheral by
default (CONFIG_MBEDTLS_HARDWARE_AES=y on esp32 / s2 / s3 / c3 / c5 /
c6 / p4). Pairs with libwebsockets and (upcoming) usrsctp for the
WebRTC transport stack.

The wrapper bundles cisco/libsrtp as a git submodule and compiles its
sources directly into the IDF component archive — no internal libsrtp2.a
dance. One small port-side delta in port/crypto_kernel.c opts out of
the AES-ICM-192 cipher registration when GCM is enabled (saves binary
size; AES-CM-128 + AES-GCM cover all WebRTC SRTP suites in use).

Naming + version follow cisco's release line. Component is named
'libsrtp' (registry: espressif/libsrtp) tracking whichever 2.x release
is current upstream — v2.8.0 today. The IDF version constraint
(>=5.4,<6) reflects the fact that libsrtp v2.x's mbedTLS adapters
predate the mbedTLS 4 / TF-PSA-Crypto split shipped by IDF v6; bump
when the component tracks a release that speaks mbedTLS 4.

Supported SRTP profiles via the mbedTLS backend:
  AEAD: AEAD_AES_128_GCM, AEAD_AES_256_GCM
  SRTP: AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32

Tests included:
  test_apps/         — embedded Unity smoke (esp32 + esp32c3 via
                       .build-test-rules)
  host_test/         — IDF Linux-target binary, AES-GCM-128 protect/
                       unprotect roundtrip; aborts on the first libsrtp
                       failure with EXPECT() for boolean assertions
  examples/get_started/ — minimal init/shutdown sanity app

License: Apache-2.0 (port glue) AND BSD-3-Clause (bundled cisco/libsrtp).

(Previously prepared as espressif/idf-extra-components#753; relocated to
esp-protocols where it naturally sits alongside libwebsockets and the
other transport-stack components.)
This commit is contained in:
Vikram Dattu
2026-05-25 14:48:56 +05:30
committed by david-cermak
parent 67f205bb8e
commit e5997168d9
35 changed files with 1455 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
name: "libsrtp: build-tests"
on:
push:
branches:
- master
pull_request:
types: [opened, synchronize, reopened, labeled]
jobs:
build_libsrtp:
if: contains(github.event.pull_request.labels.*.name, 'libsrtp') || github.event_name == 'push'
name: libsrtp build
strategy:
fail-fast: false
matrix:
idf_ver: ["release-v5.4", "release-v5.5"]
app:
- { name: "get_started", path: "components/libsrtp/examples/get_started" }
- { name: "test_apps", path: "components/libsrtp/test_apps" }
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build ${{ matrix.app.name }} with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
python ./ci/build_apps.py -c ${{ matrix.app.path }} -m components/libsrtp/.build-test-rules.yml
host_test_libsrtp:
if: contains(github.event.pull_request.labels.*.name, 'libsrtp') || github.event_name == 'push'
name: libsrtp host test
strategy:
fail-fast: false
matrix:
idf_ver: ["release-v5.4", "release-v5.5"]
runs-on: ubuntu-22.04
container: espressif/idf:${{ matrix.idf_ver }}
steps:
- name: Checkout esp-protocols
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build + run host_test with IDF-${{ matrix.idf_ver }}
shell: bash
run: |
. ${IDF_PATH}/export.sh
python -m pip install idf-build-apps
python ./ci/build_apps.py -c components/libsrtp/host_test -m components/libsrtp/.build-test-rules.yml
cd components/libsrtp/host_test
for dir in $(ls -d build_linux_* 2>/dev/null); do
"./$dir/host_test_libsrtp.elf"
done
+3
View File
@@ -7,3 +7,6 @@
[submodule "components/libwebsockets/libwebsockets"]
path = components/libwebsockets/libwebsockets
url = https://github.com/warmcat/libwebsockets.git
[submodule "components/libsrtp/libsrtp"]
path = components/libsrtp/libsrtp
url = https://github.com/cisco/libsrtp.git
+1
View File
@@ -1 +1,2 @@
components/mosquitto/examples/serverless_mqtt/components/libjuice/port/juice_random.c
components/libsrtp/port/crypto_kernel.c
+42
View File
@@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
# libsrtp requires ESP-IDF 5.4+ (idf_component.yml `idf: ">=5.4"`). The
# disable rules below skip the build on older IDF releases so the repo-wide
# CI matrix (v5.1 / v5.2 / v5.3 / v5.4 / v5.5 / latest) doesn't try them.
#
# IDF v6+ is also disabled for now: libsrtp 2.x's mbedTLS adapters
# (aes_gcm_mbedtls.c, aes_icm_mbedtls.c, hmac_mbedtls.c) include the
# classic <mbedtls/aes.h> / <mbedtls/gcm.h> headers which moved under the
# TF-PSA-Crypto split in mbedTLS 4.x (shipped by IDF v6+). Re-enable once
# libsrtp adapts or we ship a port-side compatibility shim.
components/libsrtp/examples/get_started:
enable:
- if: IDF_TARGET in ["esp32", "esp32c3", "esp32s3", "esp32c5", "esp32c6", "esp32p4"]
reason: "Build sanity on representative Xtensa + RISC-V targets."
disable:
- if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4
reason: "libsrtp requires ESP-IDF 5.4+."
- if: IDF_VERSION_MAJOR >= 6
reason: "libsrtp 2.x mbedTLS adapters not yet ported to mbedTLS 4.x (TF-PSA-Crypto split)."
components/libsrtp/test_apps:
enable:
- if: IDF_TARGET in ["esp32", "esp32c3"]
reason: "Sufficient to exercise one Xtensa and one RISC-V target."
disable:
- if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4
reason: "libsrtp requires ESP-IDF 5.4+."
- if: IDF_VERSION_MAJOR >= 6
reason: "libsrtp 2.x mbedTLS adapters not yet ported to mbedTLS 4.x (TF-PSA-Crypto split)."
components/libsrtp/host_test:
enable:
- if: IDF_TARGET == "linux"
reason: "Linux host build runs the SRTP roundtrip smoke test."
disable:
- if: IDF_VERSION_MAJOR <= 5 and IDF_VERSION_MINOR < 4
reason: "libsrtp requires ESP-IDF 5.4+."
- if: IDF_VERSION_MAJOR >= 6
reason: "libsrtp 2.x mbedTLS adapters not yet ported to mbedTLS 4.x (TF-PSA-Crypto split)."
+8
View File
@@ -0,0 +1,8 @@
---
commitizen:
bump_message: 'bump(libsrtp): $current_version -> $new_version'
pre_bump_hooks: python ../../ci/changelog.py libsrtp
tag_format: libsrtp-v$version
version: 2.8.0
version_files:
- idf_component.yml
+10
View File
@@ -0,0 +1,10 @@
# Changelog
## [2.8.0](https://github.com/espressif/esp-protocols/commits/libsrtp-v2.8.0)
### Features
- First release. Tracks upstream cisco/libsrtp [`v2.8.0`](https://github.com/cisco/libsrtp/releases/tag/v2.8.0) (commit `24b3bf8`); component version follows upstream.
- Wraps libsrtp as an ESP-IDF component using mbedTLS for AES-ICM, AES-GCM and HMAC-SHA1. ESP-IDF's mbedTLS routes AES through the on-chip AES peripheral by default (`CONFIG_MBEDTLS_HARDWARE_AES=y`), so SRTP protect/unprotect leverages hardware crypto with no wrapper-side code.
- One small port-side delta in `port/crypto_kernel.c`: opts out of the AES-ICM-192 cipher registration when GCM is enabled (saves binary size; AES-CM-128 + AES-GCM cover all WebRTC SRTP suites).
- Embedded smoke test (`test_apps/`) and host-side AES-GCM-128 protect/unprotect roundtrip test (`host_test/`) included.
+79
View File
@@ -0,0 +1,79 @@
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
set(SRTP_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/libsrtp")
# Vendored port-side source — replaces the upstream crypto/kernel/crypto_kernel.c
# (which we exclude from SRCS below). The only delta vs upstream is opting out
# of the AES-ICM-192 cipher registration when GCM is enabled, to save binary
# size — AES-CM-128 + AES-GCM cover all WebRTC SRTP suites in use.
#
# Bundled into port/ rather than applied as a `git apply` patch at configure
# time, so the wrapper works cleanly when installed via the IDF Component
# Registry (the registry tarball has no .git dir for `git apply` to operate
# on). Re-port from upstream when bumping the libsrtp submodule.
set(SRTP_PORT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/port")
idf_component_register(
SRCS "${SRTP_ROOT}/srtp/srtp.c"
"${SRTP_ROOT}/crypto/cipher/aes_gcm_mbedtls.c"
"${SRTP_ROOT}/crypto/cipher/aes_icm_mbedtls.c"
"${SRTP_ROOT}/crypto/cipher/aes_icm.c"
"${SRTP_ROOT}/crypto/cipher/aes.c"
"${SRTP_ROOT}/crypto/cipher/cipher.c"
"${SRTP_ROOT}/crypto/cipher/cipher_test_cases.c"
"${SRTP_ROOT}/crypto/cipher/null_cipher.c"
"${SRTP_ROOT}/crypto/hash/auth.c"
"${SRTP_ROOT}/crypto/hash/hmac.c"
"${SRTP_ROOT}/crypto/hash/hmac_mbedtls.c"
"${SRTP_ROOT}/crypto/hash/auth_test_cases.c"
"${SRTP_ROOT}/crypto/hash/null_auth.c"
"${SRTP_ROOT}/crypto/hash/sha1.c"
"${SRTP_PORT_DIR}/crypto_kernel.c" # replaces ${SRTP_ROOT}/crypto/kernel/crypto_kernel.c
"${SRTP_ROOT}/crypto/kernel/alloc.c"
"${SRTP_ROOT}/crypto/kernel/err.c"
"${SRTP_ROOT}/crypto/kernel/key.c"
"${SRTP_ROOT}/crypto/math/datatypes.c"
"${SRTP_ROOT}/crypto/replay/rdb.c"
"${SRTP_ROOT}/crypto/replay/rdbx.c"
PRIV_INCLUDE_DIRS
"${SRTP_ROOT}/crypto/include"
"${CMAKE_CURRENT_SOURCE_DIR}/port"
INCLUDE_DIRS
"${SRTP_ROOT}/include" # upstream API headers (srtp.h, ekt.h, ...)
"${CMAKE_CURRENT_SOURCE_DIR}/include" # srtp2/ namespace shim so consumers can still <srtp2/srtp.h>
REQUIRES "mbedtls"
)
# Fully suppress (not just downgrade) warnings from third-party libsrtp
# sources. The repo-wide CI pipeline runs idf-build-apps with strict
# warning checking, so -Wno-error=* alone (which keeps the warning
# printed) trips the matrix on otherwise-valid builds. We can't fix the
# warnings upstream, so silence them here. Apple clang on IDF's Linux
# target does not recognise -Wno-conflicting-types, so probe first.
include(CheckCCompilerFlag)
check_c_compiler_flag("-Wno-conflicting-types" SRTP2_HAS_NO_CONFLICTING_TYPES)
target_compile_options(${COMPONENT_LIB} PRIVATE
-Wno-format
-Wno-unused-function
-Wno-unused-variable
-Wno-unused-but-set-variable
-Wno-sign-compare
-Wno-type-limits
-Wno-pointer-sign
-Wno-implicit-function-declaration
-Wno-strict-prototypes
-Wno-old-style-definition
-Wno-incompatible-pointer-types
)
if(SRTP2_HAS_NO_CONFLICTING_TYPES)
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-conflicting-types)
endif()
target_compile_definitions(${COMPONENT_LIB} PUBLIC
-DHAVE_CONFIG_H
)
+14
View File
@@ -0,0 +1,14 @@
menu "libsrtp (libsrtp)"
# The ESP-IDF port wires libsrtp's crypto exclusively through mbedTLS
# (AES-CM, AES-GCM, HMAC-SHA1). No Kconfig knob — the alternative
# backends (OpenSSL, NSS, WolfSSL) aren't built in this component.
config SRTP2_LOG_RTP_TRACE
bool "Enable verbose RTP trace logging"
default n
help
Enables libsrtp's internal debug-trace logging at runtime
(extra binary size; meant only for development).
endmenu
+175
View File
@@ -0,0 +1,175 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
+17
View File
@@ -0,0 +1,17 @@
libsrtp
Copyright 2024-2026 Espressif Systems (Shanghai) CO LTD
This product includes software developed by the following third parties:
================================================================================
libsrtp
https://github.com/cisco/libsrtp
Copyright (c) 2001-2017, Cisco Systems, Inc.
Licensed under the BSD 3-Clause License (see libsrtp/LICENSE).
The Secure Real-time Transport Protocol (SRTP) and Secure RTCP (SRTCP)
implementation. Bundled as a submodule, pinned at upstream release tag
v2.8.0 (commit 24b3bf8).
================================================================================
+46
View File
@@ -0,0 +1,46 @@
# libsrtp
[![Component Registry](https://components.espressif.com/components/espressif/libsrtp/badge.svg)](https://components.espressif.com/components/espressif/libsrtp)
[libsrtp](https://github.com/cisco/libsrtp) (Cisco) port for ESP-IDF using the mbedtls crypto backend with AES-GCM.
Used for SRTP/SRTCP packet protection in WebRTC and other RTP-based protocols on ESP32-series chips.
> **Not the same as `espressif/esp_libsrtp`.** The existing `espressif/esp_libsrtp` component is a pre-built closed-source libSRTP binary distributed via `esp-adf-libs` (Custom license). `libsrtp` is an open-source wrapper around upstream [`cisco/libsrtp` 2.x](https://github.com/cisco/libsrtp) — built from source as part of your project, BSD-3-Clause upstream + Apache-2.0 port code. Pick `libsrtp` when you need the source-built, open-source path (e.g. for WebRTC integrations); pick `esp_libsrtp` when you're already on the ADF binary stack.
## Features
- libsrtp [`v2.8.0`](https://github.com/cisco/libsrtp/releases/tag/v2.8.0) (commit `24b3bf8`)
- mbedtls crypto backend (AES-CM, AES-GCM, HMAC-SHA1) — IDF's mbedTLS routes AES through the on-chip AES peripheral when `CONFIG_MBEDTLS_HARDWARE_AES=y` (default)
- AEAD profiles: `AEAD_AES_128_GCM`, `AEAD_AES_256_GCM`
- SRTP profiles: `AES_CM_128_HMAC_SHA1_80`, `AES_CM_128_HMAC_SHA1_32`
## Add to a project
```bash
idf.py add-dependency "espressif/libsrtp^2.8.0"
```
Or in your project's `main/idf_component.yml`:
```yaml
dependencies:
espressif/libsrtp: "^2.8.0"
```
Requires ESP-IDF ≥ 5.4.
## Tests
- `test_apps/` — embedded Unity smoke test (init/shutdown + version). Run with
`pytest_libsrtp.py` against `esp32` / `esp32c3`.
- `host_test/` — IDF Linux-target binary that performs an AES-GCM-128
protect/unprotect roundtrip. Run with `pytest_libsrtp_linux.py`.
## Source
This wrapper bundles [cisco/libsrtp](https://github.com/cisco/libsrtp) as a git submodule pinned at the upstream release tag. All SRTP cryptographic implementation is upstream; this repo adds only the ESP-IDF build glue (`CMakeLists.txt`, `port/config.h`) plus one small port-side delta in `port/crypto_kernel.c` (replaces the upstream `crypto/kernel/crypto_kernel.c`) to opt out of the AES-ICM-192 cipher registration when GCM is enabled. Re-port from upstream when bumping the libsrtp submodule.
## License
`Apache-2.0 AND BSD-3-Clause` — the ESP-IDF port glue under this repo (`CMakeLists.txt`, `port/`, `Kconfig`, build scripts) is Apache-2.0 (see `LICENSE`); the bundled `libsrtp/` submodule remains under upstream's BSD-3-Clause (see `libsrtp/LICENSE`).
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(libsrtp_get_started)
@@ -0,0 +1,18 @@
# libsrtp — get_started
Minimal sanity-check application for [`libsrtp`](https://github.com/espressif/idf-extra-components/tree/master/libsrtp). Initializes libsrtp via `srtp_init()` and shuts it down. Used by the repo's CI to verify the component compiles and links across supported targets; also useful as a copy-paste starting point.
## Build
```bash
idf.py set-target esp32p4 # or esp32, esp32s3, esp32c3, esp32c6
idf.py build
idf.py -p <PORT> flash monitor
```
The example consumes the parent component via `override_path: ../../..` in `main/idf_component.yml`, so it always tracks the in-tree source. Replace with a registry version to consume the published component instead:
```yaml
dependencies:
espressif/libsrtp: "^2.8.0"
```
@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
idf_component_register(
SRCS "main.c"
INCLUDE_DIRS "."
REQUIRES libsrtp
)
@@ -0,0 +1,7 @@
## Build-check app for libsrtp.
## During CI / local build, override_path points at the parent repo so we
## consume the in-tree component instead of the registry version.
dependencies:
espressif/libsrtp:
version: "^2.8.0"
override_path: ../../..
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* Minimal sanity-check app for libsrtp: initializes and shuts down libsrtp.
* Used by .github/workflows/build.yml to verify the component compiles and
* links across supported ESP-IDF targets.
*/
#include <stdio.h>
#include "esp_log.h"
#include "srtp2/srtp.h"
static const char *TAG = "libsrtp_check";
void app_main(void)
{
srtp_err_status_t status = srtp_init();
if (status == srtp_err_status_ok) {
ESP_LOGI(TAG, "srtp_init() OK");
} else {
ESP_LOGE(TAG, "srtp_init() failed: %d", status);
}
srtp_shutdown();
ESP_LOGI(TAG, "libsrtp build check complete");
}
@@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.16)
set(COMPONENTS main)
set(EXTRA_COMPONENT_DIRS "..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(host_test_libsrtp)
@@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
idf_component_register(
SRCS "host_test_main.c"
INCLUDE_DIRS "."
REQUIRES libsrtp
)
@@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* Host (IDF Linux target) smoke + crypto-roundtrip test for libsrtp.
*
* - srtp_init() / srtp_shutdown()
* - srtp_create() with AES-GCM-128 policy
* - srtp_protect() + srtp_unprotect() roundtrip; assert plaintext is recovered
*
* Deeper coverage lives in libsrtp's own test/srtp_driver.c; we exercise
* the protect/unprotect happy path here as a sanity-check that the
* ESP-IDF Linux-target build produces a working library.
*
* Both CHECK() (libsrtp return-status) and EXPECT() (boolean condition)
* bail out immediately on failure — continuing past a context/init failure
* would either mask the original error or crash on uninitialised state.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "srtp2/srtp.h"
#define CHECK(_e) \
do { \
srtp_err_status_t _s = (_e); \
if (_s != srtp_err_status_ok) { \
fprintf(stderr, "FAIL: %s -> %d\n", #_e, (int)_s); \
exit(1); \
} \
} while (0)
#define EXPECT(_cond, _fmt, ...) \
do { \
if (!(_cond)) { \
fprintf(stderr, "FAIL: " _fmt "\n", ##__VA_ARGS__); \
exit(1); \
} \
} while (0)
static int run_smoke(void)
{
printf("libsrtp host_test: libsrtp version %s\n", srtp_get_version_string());
CHECK(srtp_init());
/* Build a sender + receiver context against the same AES-GCM-128 policy. */
static const uint8_t key[SRTP_AES_GCM_128_KEY_LEN_WSALT] = { 0 };
srtp_policy_t policy_tx = { 0 };
srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy_tx.rtp);
srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy_tx.rtcp);
policy_tx.ssrc.type = ssrc_any_outbound;
policy_tx.key = (uint8_t *)key;
policy_tx.window_size = 128;
srtp_policy_t policy_rx = policy_tx;
policy_rx.ssrc.type = ssrc_any_inbound;
srtp_t sender = NULL;
srtp_t receiver = NULL;
CHECK(srtp_create(&sender, &policy_tx));
CHECK(srtp_create(&receiver, &policy_rx));
/* Minimal RTP-shaped buffer:
* 12B header (V=2, PT=0, seq=1, ts=0, ssrc=0xCAFEBABE)
* payload "hello srtp"
*/
uint8_t pkt[12 + 10 + SRTP_MAX_TRAILER_LEN] = {
0x80, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
0xCA, 0xFE, 0xBA, 0xBE,
'h', 'e', 'l', 'l', 'o', ' ', 's', 'r', 't', 'p',
};
int protected_len = 12 + 10;
CHECK(srtp_protect(sender, pkt, &protected_len));
EXPECT(protected_len > 12 + 10,
"protect did not expand the packet (got len=%d)", protected_len);
int unprotected_len = protected_len;
CHECK(srtp_unprotect(receiver, pkt, &unprotected_len));
EXPECT(unprotected_len == 12 + 10,
"unprotect returned wrong len (got %d, want %d)", unprotected_len, 12 + 10);
EXPECT(memcmp(pkt + 12, "hello srtp", 10) == 0,
"recovered payload mismatch");
srtp_dealloc(sender);
srtp_dealloc(receiver);
CHECK(srtp_shutdown());
printf("libsrtp host_test: PASS\n");
return 0;
}
void app_main(void)
{
exit(run_smoke());
}
@@ -0,0 +1,4 @@
dependencies:
libsrtp:
version: "*"
override_path: "../.."
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import glob
from pathlib import Path
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.host_test
@pytest.mark.skipif(
not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),
reason='Skip the idf version that not build',
)
@idf_parametrize('target', ['linux'], indirect=['target'])
def test_libsrtp_linux(dut: Dut) -> None:
dut.expect_exact('libsrtp host_test: PASS', timeout=30)
@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="linux"
CONFIG_COMPILER_OPTIMIZATION_DEBUG=y
+35
View File
@@ -0,0 +1,35 @@
version: "2.8.0"
description: "libsrtp (Cisco) wrapper for ESP-IDF — mbedTLS crypto backend with AES-GCM + AES-CM + HMAC-SHA1. SRTP/SRTCP packet protection for WebRTC and other RTP-based protocols."
url: https://github.com/espressif/esp-protocols/tree/master/components/libsrtp
repository: https://github.com/espressif/esp-protocols.git
issues: https://github.com/espressif/esp-protocols/issues
documentation: https://github.com/espressif/esp-protocols/blob/master/components/libsrtp/README.md
license: "Apache-2.0 AND BSD-3-Clause"
tags:
- libsrtp
- srtp
- webrtc
- mbedtls
dependencies:
# Upper bound is intentional. libsrtp v2.x's mbedTLS adapters use the
# legacy <mbedtls/aes.h> / <mbedtls/gcm.h> headers; ESP-IDF v6 ships
# mbedTLS 4 which reorganised those into the TF-PSA-Crypto split.
# Bump the bound once the component tracks a libsrtp release that
# speaks mbedTLS 4 (see cisco/libsrtp#812 for context).
idf: ">=5.4,<6"
# SBOM manifest for the wrapped upstream — see sbom_libsrtp.yml.
sbom:
manifests:
- path: sbom_libsrtp.yml
dest: libsrtp
# Files excluded from the registry tarball (saves bytes, avoids confusion).
files:
exclude:
- "libsrtp/test/**" # upstream tests are linked at host_test/ build time
- "libsrtp/doc/**"
- "libsrtp/**/.git*"
- "host_test/build*"
- "test_apps/build*"
- "examples/*/build*"
+11
View File
@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* Thin shim that re-exposes upstream cisco/libsrtp's public API header
* under the `srtp2/` install-path namespace, so downstream consumers
* can use the canonical `#include <srtp2/srtp.h>` form without us
* vendoring a copy of the upstream header in this repo.
*/
#include <srtp.h>
+99
View File
@@ -0,0 +1,99 @@
/*
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* ESP-IDF build configuration for libsrtp. Define values are chosen to
* match the ESP-IDF/newlib environment; format follows libsrtp's
* upstream config.h.in template (BSD-3-Clause).
*/
#ifndef CONFIG_H
#define CONFIG_H
#include <stdint.h>
#include <inttypes.h> // For PRIx64 / PRIu64 macros (needed on Apple clang / Linux target)
#include <stddef.h> // For size_t definition
/*
* CPU architecture hint. libsrtp uses this only to select a fast endian-flip
* path in a few places; the C fallback is correct on all targets. ESP-IDF's
* supported targets are Xtensa (esp32 / s2 / s3) and RISC-V (c3 / c5 / c6 /
* p4 / h2), so CPU_CISC would be wrong here. Set CPU_RISC for the embedded
* targets and leave it unset (= C fallback) on the IDF Linux host target.
*/
#if defined(__XTENSA__) || defined(__riscv)
#define CPU_RISC 1
#endif
/* Report errors to stdout. */
#define ERR_REPORTING_STDOUT 1
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#define HAVE_NETINET_IN_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you want to use external crypto. */
#define SRTP_CRYPTO_MBEDTLS 1
/* Define package info */
#define PACKAGE_NAME "libsrtp"
#define PACKAGE_VERSION "2.8.0"
#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
/* The size of `unsigned long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG 4
/* The size of `unsigned long long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG_LONG 8
/* Force SRTP to use system types */
#define HAVE_STDINT_H 1
#define HAVE_INTTYPES_H 1
#define HAVE_SYS_TYPES_H 1
#define HAVE_UINT64_T 1
#define HAVE_UINT32_T 1
#define HAVE_UINT16_T 1
#define HAVE_UINT8_T 1
#define HAVE_INT64_T 1
#define HAVE_INT32_T 1
#define HAVE_INT16_T 1
#define HAVE_INT8_T 1
/* Prevent SRTP from redefining types */
#define INTEGERS_H
/* Prevent srtp_ssrc_t redefinition */
#ifdef __XTENSA__
#define SRTP_KERNEL_COMPAT
#endif
/* Prevent in_addr_t redefinition */
#ifndef _LWIP_INET_H
typedef uint32_t in_addr_t;
#endif
#define GCM 1
#define MBEDTLS 1
#define ERR_REPORTING_STDOUT 1
#endif /* CONFIG_H */
+561
View File
@@ -0,0 +1,561 @@
/*
* crypto_kernel.c
*
* header for the cryptographic kernel
*
* David A. McGrew
* Cisco Systems, Inc.
*/
/*
*
* Copyright(c) 2001-2017 Cisco Systems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* Neither the name of the Cisco Systems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "alloc.h"
#include "crypto_kernel.h"
#include "cipher_types.h"
/* the debug module for the crypto_kernel */
srtp_debug_module_t srtp_mod_crypto_kernel = {
0, /* debugging is off by default */
"crypto kernel" /* printable name for module */
};
/* crypto_kernel is a global variable, the only one of its datatype */
static srtp_crypto_kernel_t crypto_kernel = {
srtp_crypto_kernel_state_insecure, /* start off in insecure state */
NULL, /* no cipher types yet */
NULL, /* no auth types yet */
NULL /* no debug modules yet */
};
#define MAX_RNG_TRIALS 25
srtp_err_status_t srtp_crypto_kernel_init(void)
{
srtp_err_status_t status;
/* check the security state */
if (crypto_kernel.state == srtp_crypto_kernel_state_secure) {
/*
* we're already in the secure state, but we've been asked to
* re-initialize, so we just re-run the self-tests and then return
*/
return srtp_crypto_kernel_status();
}
/* initialize error reporting system */
status = srtp_err_reporting_init();
if (status) {
return status;
}
/* load debug modules */
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_crypto_kernel);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_auth);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_cipher);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_alloc);
if (status) {
return status;
}
/* load cipher types */
status = srtp_crypto_kernel_load_cipher_type(&srtp_null_cipher,
SRTP_NULL_CIPHER);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_128,
SRTP_AES_ICM_128);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_256,
SRTP_AES_ICM_256);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_aes_icm);
if (status) {
return status;
}
#ifdef GCM
#if 0
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_icm_192,
SRTP_AES_ICM_192);
if (status) {
return status;
}
#endif
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_gcm_128,
SRTP_AES_GCM_128);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_cipher_type(&srtp_aes_gcm_256,
SRTP_AES_GCM_256);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_aes_gcm);
if (status) {
return status;
}
#endif
/* load auth func types */
status = srtp_crypto_kernel_load_auth_type(&srtp_null_auth, SRTP_NULL_AUTH);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_auth_type(&srtp_hmac, SRTP_HMAC_SHA1);
if (status) {
return status;
}
status = srtp_crypto_kernel_load_debug_module(&srtp_mod_hmac);
if (status) {
return status;
}
/* change state to secure */
crypto_kernel.state = srtp_crypto_kernel_state_secure;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_status(void)
{
srtp_err_status_t status;
srtp_kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list;
srtp_kernel_auth_type_t *atype = crypto_kernel.auth_type_list;
/* for each cipher type, describe and test */
while (ctype != NULL) {
srtp_err_report(srtp_err_level_info, "cipher: %s\n",
ctype->cipher_type->description);
srtp_err_report(srtp_err_level_info, " self-test: ");
status = srtp_cipher_type_self_test(ctype->cipher_type);
if (status) {
srtp_err_report(srtp_err_level_error, "failed with error code %d\n",
status);
exit(status);
}
srtp_err_report(srtp_err_level_info, "passed\n");
ctype = ctype->next;
}
/* for each auth type, describe and test */
while (atype != NULL) {
srtp_err_report(srtp_err_level_info, "auth func: %s\n",
atype->auth_type->description);
srtp_err_report(srtp_err_level_info, " self-test: ");
status = srtp_auth_type_self_test(atype->auth_type);
if (status) {
srtp_err_report(srtp_err_level_error, "failed with error code %d\n",
status);
exit(status);
}
srtp_err_report(srtp_err_level_info, "passed\n");
atype = atype->next;
}
srtp_crypto_kernel_list_debug_modules();
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_list_debug_modules(void)
{
srtp_kernel_debug_module_t *dm = crypto_kernel.debug_module_list;
/* describe each debug module */
srtp_err_report(srtp_err_level_info, "debug modules loaded:\n");
while (dm != NULL) {
srtp_err_report(srtp_err_level_info, " %s ", dm->mod->name);
if (dm->mod->on) {
srtp_err_report(srtp_err_level_info, "(on)\n");
} else {
srtp_err_report(srtp_err_level_info, "(off)\n");
}
dm = dm->next;
}
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_shutdown(void)
{
/*
* free dynamic memory used in crypto_kernel at present
*/
/* walk down cipher type list, freeing memory */
while (crypto_kernel.cipher_type_list != NULL) {
srtp_kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list;
crypto_kernel.cipher_type_list = ctype->next;
debug_print(srtp_mod_crypto_kernel, "freeing memory for cipher %s",
ctype->cipher_type->description);
srtp_crypto_free(ctype);
}
/* walk down authentication module list, freeing memory */
while (crypto_kernel.auth_type_list != NULL) {
srtp_kernel_auth_type_t *atype = crypto_kernel.auth_type_list;
crypto_kernel.auth_type_list = atype->next;
debug_print(srtp_mod_crypto_kernel,
"freeing memory for authentication %s",
atype->auth_type->description);
srtp_crypto_free(atype);
}
/* walk down debug module list, freeing memory */
while (crypto_kernel.debug_module_list != NULL) {
srtp_kernel_debug_module_t *kdm = crypto_kernel.debug_module_list;
crypto_kernel.debug_module_list = kdm->next;
debug_print(srtp_mod_crypto_kernel,
"freeing memory for debug module %s", kdm->mod->name);
srtp_crypto_free(kdm);
}
/* return to insecure state */
crypto_kernel.state = srtp_crypto_kernel_state_insecure;
return srtp_err_status_ok;
}
static inline srtp_err_status_t srtp_crypto_kernel_do_load_cipher_type(
const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id,
int replace)
{
srtp_kernel_cipher_type_t *ctype;
srtp_kernel_cipher_type_t *new_ctype = NULL;
srtp_err_status_t status;
/* defensive coding */
if (new_ct == NULL) {
return srtp_err_status_bad_param;
}
if (new_ct->id != id) {
return srtp_err_status_bad_param;
}
/* check cipher type by running self-test */
status = srtp_cipher_type_self_test(new_ct);
if (status) {
return status;
}
/* walk down list, checking if this type is in the list already */
ctype = crypto_kernel.cipher_type_list;
while (ctype != NULL) {
if (id == ctype->id) {
if (!replace) {
return srtp_err_status_bad_param;
}
status =
srtp_cipher_type_test(new_ct, ctype->cipher_type->test_data);
if (status) {
return status;
}
new_ctype = ctype;
break;
} else if (new_ct == ctype->cipher_type) {
return srtp_err_status_bad_param;
}
ctype = ctype->next;
}
/* if not found, put new_ct at the head of the list */
if (ctype == NULL) {
/* allocate memory */
new_ctype = (srtp_kernel_cipher_type_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_cipher_type_t));
if (new_ctype == NULL) {
return srtp_err_status_alloc_fail;
}
new_ctype->next = crypto_kernel.cipher_type_list;
/* set head of list to new cipher type */
crypto_kernel.cipher_type_list = new_ctype;
}
/* set fields */
new_ctype->cipher_type = new_ct;
new_ctype->id = id;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_load_cipher_type(
const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id)
{
return srtp_crypto_kernel_do_load_cipher_type(new_ct, id, 0);
}
srtp_err_status_t srtp_replace_cipher_type(const srtp_cipher_type_t *new_ct,
srtp_cipher_type_id_t id)
{
return srtp_crypto_kernel_do_load_cipher_type(new_ct, id, 1);
}
srtp_err_status_t srtp_crypto_kernel_do_load_auth_type(
const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id,
int replace)
{
srtp_kernel_auth_type_t *atype;
srtp_kernel_auth_type_t *new_atype = NULL;
srtp_err_status_t status;
/* defensive coding */
if (new_at == NULL) {
return srtp_err_status_bad_param;
}
if (new_at->id != id) {
return srtp_err_status_bad_param;
}
/* check auth type by running self-test */
status = srtp_auth_type_self_test(new_at);
if (status) {
return status;
}
/* walk down list, checking if this type is in the list already */
atype = crypto_kernel.auth_type_list;
while (atype != NULL) {
if (id == atype->id) {
if (!replace) {
return srtp_err_status_bad_param;
}
status = srtp_auth_type_test(new_at, atype->auth_type->test_data);
if (status) {
return status;
}
new_atype = atype;
break;
} else if (new_at == atype->auth_type) {
return srtp_err_status_bad_param;
}
atype = atype->next;
}
/* if not found, put new_at at the head of the list */
if (atype == NULL) {
/* allocate memory */
new_atype = (srtp_kernel_auth_type_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_auth_type_t));
if (new_atype == NULL) {
return srtp_err_status_alloc_fail;
}
new_atype->next = crypto_kernel.auth_type_list;
/* set head of list to new auth type */
crypto_kernel.auth_type_list = new_atype;
}
/* set fields */
new_atype->auth_type = new_at;
new_atype->id = id;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_load_auth_type(
const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id)
{
return srtp_crypto_kernel_do_load_auth_type(new_at, id, 0);
}
srtp_err_status_t srtp_replace_auth_type(const srtp_auth_type_t *new_at,
srtp_auth_type_id_t id)
{
return srtp_crypto_kernel_do_load_auth_type(new_at, id, 1);
}
const srtp_cipher_type_t *srtp_crypto_kernel_get_cipher_type(
srtp_cipher_type_id_t id)
{
srtp_kernel_cipher_type_t *ctype;
/* walk down list, looking for id */
ctype = crypto_kernel.cipher_type_list;
while (ctype != NULL) {
if (id == ctype->id) {
return ctype->cipher_type;
}
ctype = ctype->next;
}
/* haven't found the right one, indicate failure by returning NULL */
return NULL;
}
srtp_err_status_t srtp_crypto_kernel_alloc_cipher(srtp_cipher_type_id_t id,
srtp_cipher_pointer_t *cp,
int key_len,
int tag_len)
{
const srtp_cipher_type_t *ct;
/*
* if the crypto_kernel is not yet initialized, we refuse to allocate
* any ciphers - this is a bit extra-paranoid
*/
if (crypto_kernel.state != srtp_crypto_kernel_state_secure) {
return srtp_err_status_init_fail;
}
ct = srtp_crypto_kernel_get_cipher_type(id);
if (!ct) {
return srtp_err_status_fail;
}
return ((ct)->alloc(cp, key_len, tag_len));
}
const srtp_auth_type_t *srtp_crypto_kernel_get_auth_type(srtp_auth_type_id_t id)
{
srtp_kernel_auth_type_t *atype;
/* walk down list, looking for id */
atype = crypto_kernel.auth_type_list;
while (atype != NULL) {
if (id == atype->id) {
return atype->auth_type;
}
atype = atype->next;
}
/* haven't found the right one, indicate failure by returning NULL */
return NULL;
}
srtp_err_status_t srtp_crypto_kernel_alloc_auth(srtp_auth_type_id_t id,
srtp_auth_pointer_t *ap,
int key_len,
int tag_len)
{
const srtp_auth_type_t *at;
/*
* if the crypto_kernel is not yet initialized, we refuse to allocate
* any auth functions - this is a bit extra-paranoid
*/
if (crypto_kernel.state != srtp_crypto_kernel_state_secure) {
return srtp_err_status_init_fail;
}
at = srtp_crypto_kernel_get_auth_type(id);
if (!at) {
return srtp_err_status_fail;
}
return ((at)->alloc(ap, key_len, tag_len));
}
srtp_err_status_t srtp_crypto_kernel_load_debug_module(
srtp_debug_module_t *new_dm)
{
srtp_kernel_debug_module_t *kdm, *new;
/* defensive coding */
if (new_dm == NULL || new_dm->name == NULL) {
return srtp_err_status_bad_param;
}
/* walk down list, checking if this type is in the list already */
kdm = crypto_kernel.debug_module_list;
while (kdm != NULL) {
if (strncmp(new_dm->name, kdm->mod->name, 64) == 0) {
return srtp_err_status_bad_param;
}
kdm = kdm->next;
}
/* put new_dm at the head of the list */
/* allocate memory */
new = (srtp_kernel_debug_module_t *)srtp_crypto_alloc(
sizeof(srtp_kernel_debug_module_t));
if (new == NULL) {
return srtp_err_status_alloc_fail;
}
/* set fields */
new->mod = new_dm;
new->next = crypto_kernel.debug_module_list;
/* set head of list to new cipher type */
crypto_kernel.debug_module_list = new;
return srtp_err_status_ok;
}
srtp_err_status_t srtp_crypto_kernel_set_debug_module(const char *name, int on)
{
srtp_kernel_debug_module_t *kdm;
/* walk down list, checking if this type is in the list already */
kdm = crypto_kernel.debug_module_list;
while (kdm != NULL) {
if (strncmp(name, kdm->mod->name, 64) == 0) {
kdm->mod->on = on;
return srtp_err_status_ok;
}
kdm = kdm->next;
}
return srtp_err_status_fail;
}
+6
View File
@@ -0,0 +1,6 @@
name: 'libsrtp'
supplier: 'Organization: Espressif Systems (Shanghai) CO LTD'
originator: 'Organization: Espressif Systems (Shanghai) CO LTD'
description: ESP-IDF wrapper for libsrtp (Cisco) using mbedtls crypto backend with AES-GCM. Used for SRTP/SRTCP packet protection in WebRTC and other RTP-based protocols.
virtpackages:
- sbom_libsrtp.yml
+10
View File
@@ -0,0 +1,10 @@
name: libsrtp
version: 2.8.0
cpe: cpe:2.3:a:cisco:libsrtp:{}:*:*:*:*:*:*:*
supplier: 'Organization: Cisco Systems, Inc. <https://github.com/cisco/libsrtp>'
description: Library for the Secure Real-time Transport Protocol (SRTP, RFC 3711) and Secure RTCP (SRTCP). Submodule pinned at upstream release tag v2.8.0 (commit 24b3bf8). One small ESP-IDF specific delta lives in port/crypto_kernel.c — it opts out of the AES-ICM-192 cipher registration when GCM is enabled (saves binary size; AES-CM-128 and AES-GCM cover all WebRTC SRTP suites).
url: https://github.com/cisco/libsrtp
hash: 24b3bf8f19b6f5ab4cd2bcceb4f4064efca86fd5
cve-exclude-list:
- cve: CVE-2023-31222
reason: Resolved in 2.6.0; current pin (v2.8.0) is well past.
@@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.16)
# Pull the parent component via override_path so the test exercises
# THIS working tree, not whatever's in the registry / managed_components.
set(EXTRA_COMPONENT_DIRS "..")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_app_libsrtp)
@@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: Apache-2.0
idf_component_register(
SRCS "test_libsrtp_main.c"
INCLUDE_DIRS "."
REQUIRES unity libsrtp
)
@@ -0,0 +1,4 @@
dependencies:
libsrtp:
version: "*"
override_path: "../.."
@@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* Embedded smoke test for libsrtp. Validates that the component
* links cleanly on the chosen target and exposes the libsrtp public
* API. Deeper coverage lives in host_test/ (runs against the IDF
* Linux target and reuses upstream libsrtp's own test suite).
*/
#include <string.h>
#include "unity.h"
#include "srtp2/srtp.h"
TEST_CASE("srtp_init then srtp_shutdown succeed", "[srtp2]")
{
TEST_ASSERT_EQUAL(srtp_err_status_ok, srtp_init());
TEST_ASSERT_EQUAL(srtp_err_status_ok, srtp_shutdown());
}
TEST_CASE("srtp_get_version_string returns non-empty", "[srtp2]")
{
const char *v = srtp_get_version_string();
TEST_ASSERT_NOT_NULL(v);
TEST_ASSERT_GREATER_THAN(0, strlen(v));
}
void app_main(void)
{
UNITY_BEGIN();
unity_run_all_tests();
UNITY_END();
}
@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
@pytest.mark.generic
@pytest.mark.parametrize("target", ["esp32", "esp32c3"], indirect=True)
def test_libsrtp_smoke(dut):
dut.expect_unity_test_output(timeout=30)
@@ -0,0 +1,3 @@
# Speed up CI run + small binary
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_FREERTOS_UNICORE=y