Commit fe67753da4 for openssl.org
commit fe67753da40968765166f13f128ae7a3dc54081b
Author: Helen Zhang <helzhang@cisco.com>
Date: Wed Dec 17 21:45:26 2025 +0000
Add SRTPKDF implementation
In compliance with RFC 3711, Section 4.3.3
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
MergeDate: Fri Jan 23 10:19:32 2026
(Merged from https://github.com/openssl/openssl/pull/29435)
diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml
index 113e65e9f8..49c21ca17b 100644
--- a/.github/workflows/run-checker-daily.yml
+++ b/.github/workflows/run-checker-daily.yml
@@ -105,6 +105,7 @@ jobs:
no-sm4,
no-snmpkdf,
no-sock,
+ no-srtpkdf,
no-sse2,
no-sshkdf,
no-sskdf,
diff --git a/.gitignore b/.gitignore
index f5b55b927b..ba7f69828b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@ providers/implementations/digests/sha3_prov.inc
providers/implementations/digests/ml_dsa_mu_prov.inc
providers/implementations/include/prov/blake2_params.inc
providers/implementations/kdfs/snmpkdf.inc
+providers/implementations/kdfs/srtpkdf.inc
providers/implementations/macs/cmac_prov.inc
providers/implementations/macs/gmac_prov.inc
providers/implementations/macs/hmac_prov.inc
diff --git a/CHANGES.md b/CHANGES.md
index 757cea73ec..9901b34609 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -167,6 +167,10 @@ OpenSSL 4.0
*Simo Sorce*
+ * Added SRTP KDF (EVP_KDF_SRTPKDF) to EVP_KDF
+
+ *Barry Fussell and Helen Zhang*
+
OpenSSL 3.6
-----------
diff --git a/Configure b/Configure
index efded13f3e..a8bf855a1a 100755
--- a/Configure
+++ b/Configure
@@ -535,6 +535,7 @@ my @disablables = (
"sock",
"srp",
"srtp",
+ "srtpkdf",
"sse2",
"sshkdf",
"sskdf",
@@ -655,7 +656,7 @@ my @disable_cascades = (
"pvkkdf", "rc2", "rc4", "rmd160",
"scrypt", "seed", "siphash", "siv",
"slh-dsa", "sm3", "sm4", "snmpkdf",
- "srp", "srtp", "sshkdf", "sskdf",
+ "srp", "srtp", "srtpkdf", "sshkdf", "sskdf",
"ssl-trace",
"tfo",
"ts", "ui-console", "whirlpool",
diff --git a/INSTALL.md b/INSTALL.md
index 9a21f72db8..8350567e9e 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1177,7 +1177,7 @@ The `lms` algorithm support is currently limited to verification only as per
md4|mdc2|
ml-dsa|ml-kem|
ocb|poly1305|pvkkdf|rc2|rc4|rmd160|scrypt|
- seed|siphash|siv|slh-dsa|sm2|sm3|sm4|snmpkdf|sshkdf|sskdf|
+ seed|siphash|siv|slh-dsa|sm2|sm3|sm4|snmpkdf|srtpkdf|sshkdf|sskdf|
x942kdf|x963kdf|whirlpool}
Build without support for the specified algorithm.
diff --git a/build.info b/build.info
index 5607fbdad4..d6c4c2ba3e 100644
--- a/build.info
+++ b/build.info
@@ -68,6 +68,7 @@ DEPEND[]=include/openssl/asn1.h \
providers/implementations/kdfs/pvkkdf.inc \
providers/implementations/kdfs/scrypt.inc \
providers/implementations/kdfs/snmpkdf.inc \
+ providers/implementations/kdfs/srtpkdf.inc \
providers/implementations/kdfs/sshkdf.inc \
providers/implementations/kdfs/sskdf.inc \
providers/implementations/kdfs/tls1_prf.inc \
@@ -189,6 +190,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \
providers/implementations/kdfs/pvkkdf.inc \
providers/implementations/kdfs/scrypt.inc \
providers/implementations/kdfs/snmpkdf.inc \
+ providers/implementations/kdfs/srtpkdf.inc \
providers/implementations/kdfs/sshkdf.inc \
providers/implementations/kdfs/sskdf.inc \
providers/implementations/kdfs/tls1_prf.inc \
@@ -301,6 +303,8 @@ GENERATE[providers/implementations/kdfs/scrypt.inc]=\
providers/implementations/kdfs/scrypt.inc.in
GENERATE[providers/implementations/kdfs/snmpkdf.inc]=\
providers/implementations/kdfs/snmpkdf.inc.in
+GENERATE[providers/implementations/kdfs/srtpkdf.inc]=\
+ providers/implementations/kdfs/srtpkdf.inc.in
GENERATE[providers/implementations/kdfs/sshkdf.inc]=\
providers/implementations/kdfs/sshkdf.inc.in
GENERATE[providers/implementations/kdfs/sskdf.inc]=\
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 3302b94a1e..da6a2e70ec 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -1,4 +1,4 @@
-# Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 1999-2026 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the Apache License 2.0 (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
@@ -1077,8 +1077,10 @@ PROV_R_INVALID_INPUT_LENGTH:230:invalid input length
PROV_R_INVALID_ITERATION_COUNT:123:invalid iteration count
PROV_R_INVALID_IV_LENGTH:109:invalid iv length
PROV_R_INVALID_KDF:232:invalid kdf
+PROV_R_INVALID_KDR:256:invalid kdr
PROV_R_INVALID_KEY:158:invalid key
PROV_R_INVALID_KEY_LENGTH:105:invalid key length
+PROV_R_INVALID_LABEL:257:invalid label
PROV_R_INVALID_MAC:151:invalid mac
PROV_R_INVALID_MEMORY_SIZE:235:invalid memory size
PROV_R_INVALID_MGF1_MD:167:invalid mgf1 md
diff --git a/doc/build.info b/doc/build.info
index 589516632a..07b77e4ef0 100644
--- a/doc/build.info
+++ b/doc/build.info
@@ -4629,6 +4629,10 @@ DEPEND[html/man7/EVP_KDF-SNMPKDF.html]=man7/EVP_KDF-SNMPKDF.pod
GENERATE[html/man7/EVP_KDF-SNMPKDF.html]=man7/EVP_KDF-SNMPKDF.pod
DEPEND[man/man7/EVP_KDF-SNMPKDF.7]=man7/EVP_KDF-SNMPKDF.pod
GENERATE[man/man7/EVP_KDF-SNMPKDF.7]=man7/EVP_KDF-SNMPKDF.pod
+DEPEND[html/man7/EVP_KDF-SRTPKDF.html]=man7/EVP_KDF-SRTPKDF.pod
+GENERATE[html/man7/EVP_KDF-SRTPKDF.html]=man7/EVP_KDF-SRTPKDF.pod
+DEPEND[man/man7/EVP_KDF-SRTPKDF.7]=man7/EVP_KDF-SRTPKDF.pod
+GENERATE[man/man7/EVP_KDF-SRTPKDF.7]=man7/EVP_KDF-SRTPKDF.pod
DEPEND[html/man7/EVP_KDF-SS.html]=man7/EVP_KDF-SS.pod
GENERATE[html/man7/EVP_KDF-SS.html]=man7/EVP_KDF-SS.pod
DEPEND[man/man7/EVP_KDF-SS.7]=man7/EVP_KDF-SS.pod
@@ -5204,6 +5208,7 @@ html/man7/EVP_KDF-PKCS12KDF.html \
html/man7/EVP_KDF-PVKKDF.html \
html/man7/EVP_KDF-SCRYPT.html \
html/man7/EVP_KDF-SNMPKDF.html \
+html/man7/EVP_KDF-SRTPKDF.html \
html/man7/EVP_KDF-SS.html \
html/man7/EVP_KDF-SSHKDF.html \
html/man7/EVP_KDF-TLS13_KDF.html \
@@ -5366,6 +5371,7 @@ man/man7/EVP_KDF-PKCS12KDF.7 \
man/man7/EVP_KDF-PVKKDF.7 \
man/man7/EVP_KDF-SCRYPT.7 \
man/man7/EVP_KDF-SNMPKDF.7 \
+man/man7/EVP_KDF-SRTPKDF.7 \
man/man7/EVP_KDF-SS.7 \
man/man7/EVP_KDF-SSHKDF.7 \
man/man7/EVP_KDF-TLS13_KDF.7 \
diff --git a/doc/man1/openssl-kdf.pod.in b/doc/man1/openssl-kdf.pod.in
index ae153b4b81..90a95a27eb 100644
--- a/doc/man1/openssl-kdf.pod.in
+++ b/doc/man1/openssl-kdf.pod.in
@@ -141,7 +141,7 @@ This option is identical to the B<-mac> option.
Specifies the name of a supported KDF algorithm which will be used.
The supported algorithms names include TLS1-PRF, HKDF, SSKDF, PBKDF2,
-SNMPKDF, SSHKDF, X942KDF-ASN1, X942KDF-CONCAT, X963KDF and SCRYPT.
+SNMPKDF, SRTPKDF, SSHKDF, X942KDF-ASN1, X942KDF-CONCAT, X963KDF and SCRYPT.
=back
@@ -181,6 +181,14 @@ Use SNMPKDF to create a hex-encoded derived key from an engine ID, hash and pass
-kdfopt pass:IFUcNbMl \
-kdfopt hexeid:800002b805123456789abcdef0123456789abcdef0123456789abcdef0123456 SNMPKDF
+Use SRTPKDF to create a SRTP authentication derived key from a cipher, mkey, msalt,
+ kdr, index and label:
+
+ openssl kdf -keylen 20 -kdfopt cipher:AES-128-CTR \
+ -kdfopt key:E1F97A0D3E018BE0D64FA32C06DE4139 \
+ -kdfopt salt:0EC675AD498AFEEBB6960B3AABE6 \
+ -kdfopt index:000000000000 -kdfopt label:1 SRTPKDF
+
Use SSHKDF to create a hex-encoded derived key from a secret key, hash and session_id:
openssl kdf -keylen 16 -kdfopt digest:SHA2-256 \
@@ -215,6 +223,7 @@ L<EVP_KDF-TLS1_PRF(7)>,
L<EVP_KDF-PBKDF2(7)>,
L<EVP_KDF-HKDF(7)>,
L<EVP_KDF-SNMPKDF(7)>,
+L<EVP_KDF-SRTPKDF(7)>,
L<EVP_KDF-SS(7)>,
L<EVP_KDF-SSHKDF(7)>,
L<EVP_KDF-X942-ASN1(7)>,
diff --git a/doc/man7/EVP_KDF-SRTPKDF.pod b/doc/man7/EVP_KDF-SRTPKDF.pod
new file mode 100644
index 0000000000..c18853c2f9
--- /dev/null
+++ b/doc/man7/EVP_KDF-SRTPKDF.pod
@@ -0,0 +1,197 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF-SRTPKDF - The SRTP EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+Support for computing the B<SRTP> KDF through the B<EVP_KDF> API.
+
+The EVP_KDF-SRTP algorithm implements the SRTP key derivation function.
+SRTP follows the specification in RFC 3711 Section 4.3.3, where various
+cryptographic keys (encryption, authentication, and salt keys) are derived
+from a master key and master salt using AES encryption with specific labels.
+
+The output keys are used for SRTP and SRTCP packet protection.
+
+=head2 Identity
+
+"SRTP" is the name for this implementation; it can be used with the
+EVP_KDF_fetch() function.
+
+=head2 Supported parameters
+
+The supported parameters are:
+
+=over 4
+
+=item "properties" (B<OSSL_KDF_PARAM_PROPERTIES>) <UTF8 string>
+
+=item "cipher" (B<OSSL_KDF_PARAM_CIPHER>) <UTF8 string>
+
+This parameter sets the cipher to be used for the key derivation.
+Typically "AES-128-CTR" or "AES-256-CTR" is used.
+
+=item "key" (B<OSSL_KDF_PARAM_KEY>) <octet string>
+
+This parameter sets the master key value. This is typically 16 bytes
+for AES-128 or 32 bytes for AES-256.
+
+=item "salt" (B<OSSL_KDF_PARAM_SALT>) <octet string>
+
+This parameter sets the master salt value. This is typically 14 bytes
+as specified in RFC 3711.
+
+=item "kdr" (B<OSSL_KDF_PARAM_SRTPKDF_KDR>) <unsigned integer>
+
+This parameter sets the key derivation rate (KDR). The KDR controls
+how often keys are rederived. If not set or set to zero, no key
+rederivation is performed. The KDR value is power of 2 (range 2^0 to 2^24).
+
+=item "index" (B<OSSL_KDF_PARAM_SRTPKDF_INDEX>) <octet string>
+
+This parameter sets the index value used in key derivation. For RTP
+packets, this is typically a 48-bit (6 byte) value. For RTCP packets,
+this is typically a 32-bit (4 byte) value. If not set, defaults to zero.
+
+=item "label" (B<OSSL_KDF_PARAM_SRTPKDF_LABEL>) <unsigned integer>
+
+This parameter sets the label that identifies the type of key to derive.
+Valid values are:
+
+=over 4
+
+=item 0 - SRTP encryption key
+
+=item 1 - SRTP authentication key
+
+=item 2 - SRTP salt key
+
+=item 3 - SRTCP encryption key
+
+=item 4 - SRTCP authentication key
+
+=item 5 - SRTCP salt key
+
+=item 6 - SRTP encryption key (alternative)
+
+=item 7 - SRTP salt key (alternative)
+
+=back
+
+=back
+
+=head1 NOTES
+
+A context for SRTP can be obtained by calling:
+
+ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SRTP", NULL);
+ EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);
+
+The output length of the SRTP KDF operation is determined by the label:
+
+=over 4
+
+=item Labels 0, 3, 6: Output length equals the cipher key length
+
+=item Labels 1, 4: Output length is 20 bytes (160 bits)
+
+=item Labels 2, 5, 7: Output length is 14 bytes (112 bits)
+
+=back
+
+=head1 EXAMPLES
+
+This example derives an SRTP encryption key (label 0) using AES-128-CTR
+with a 16-byte master key and 14-byte master salt:
+
+ EVP_KDF *kdf;
+ EVP_KDF_CTX *kctx;
+ unsigned char out[16];
+ unsigned char master_key[16] = { /* master key bytes */ };
+ unsigned char master_salt[14] = { /* master salt bytes */ };
+ uint32_t label = 0;
+ OSSL_PARAM params[5], *p = params;
+
+ kdf = EVP_KDF_fetch(NULL, "SRTP", NULL);
+ kctx = EVP_KDF_CTX_new(kdf);
+ EVP_KDF_free(kdf);
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
+ "AES-128-CTR", 0);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
+ master_key, sizeof(master_key));
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
+ master_salt, sizeof(master_salt));
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SRTPKDF_LABEL, &label);
+ *p = OSSL_PARAM_construct_end();
+
+ if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
+ error("EVP_KDF_derive");
+ }
+
+ EVP_KDF_CTX_free(kctx);
+
+This example derives an SRTP authentication key (label 1) with key derivation
+rate and index:
+
+ EVP_KDF *kdf;
+ EVP_KDF_CTX *kctx;
+ unsigned char out[20];
+ unsigned char master_key[16] = { /* master key bytes */ };
+ unsigned char master_salt[14] = { /* master salt bytes */ };
+ uint32_t kdr = 0x1000; /* KDR */
+ unsigned char index[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; /* index */
+ uint32_t label = 1;
+ OSSL_PARAM params[7], *p = params;
+
+ kdf = EVP_KDF_fetch(NULL, "SRTP", NULL);
+ kctx = EVP_KDF_CTX_new(kdf);
+ EVP_KDF_free(kdf);
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CIPHER,
+ "AES-128-CTR", 0);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
+ master_key, sizeof(master_key));
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
+ master_salt, sizeof(master_salt));
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SRTPKDF_KDR, &kdr);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SRTPKDF_INDEX,
+ index, sizeof(index));
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_SRTPKDF_LABEL, &label);
+ *p = OSSL_PARAM_construct_end();
+
+ if (EVP_KDF_derive(kctx, out, sizeof(out), params) <= 0) {
+ error("EVP_KDF_derive");
+ }
+
+ EVP_KDF_CTX_free(kctx);
+
+=head1 CONFORMING TO
+
+RFC 3711 Section 4.3.3 (SRTP Key Derivation)
+
+=head1 SEE ALSO
+
+L<EVP_KDF(3)>,
+L<EVP_KDF_CTX_new(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_CTX_set_params(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF(3)/PARAMETERS>
+
+=head1 HISTORY
+
+The SRTPKDF was added in OpenSSL 4.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod
index 29ffe1592b..70fc2c597e 100644
--- a/doc/man7/OSSL_PROVIDER-FIPS.pod
+++ b/doc/man7/OSSL_PROVIDER-FIPS.pod
@@ -121,6 +121,8 @@ KECCAK-KMAC is only used internally as a sub algorithm of KMAC.
=item SNMPKDF, see L<EVP_KDF-SNMPKDF(7)>
+=item SRTPKDF, see L<EVP_KDF-SRTPKDF(7)>
+
=item SSHKDF, see L<EVP_KDF-SSHKDF(7)>
=item TLS1-PRF, see L<EVP_KDF-TLS1_PRF(7)>
@@ -489,6 +491,8 @@ Key agreement tests used with the "KAT_KA" type.
=item "SNMPKDF" (B<OSSL_SELF_TEST_DESC_KDF_SNMPKDF>)
+=item "SRTPKDF" (B<OSSL_SELF_TEST_DESC_KDF_SRTPKDF>)
+
=item "SSHKDF" (B<OSSL_SELF_TEST_DESC_KDF_SSHKDF>)
=item "TLS12_PRF" (B<OSSL_SELF_TEST_DESC_KDF_TLS12_PRF>)
diff --git a/doc/man7/OSSL_PROVIDER-default.pod b/doc/man7/OSSL_PROVIDER-default.pod
index 5cc5f490ec..207a46ce1e 100644
--- a/doc/man7/OSSL_PROVIDER-default.pod
+++ b/doc/man7/OSSL_PROVIDER-default.pod
@@ -143,6 +143,8 @@ The OpenSSL default provider supports these operations and algorithms:
=item SNMPKDF, see L<EVP_KDF-SNMPKDF(7)>
+=item SRTPKDF, see L<EVP_KDF-SRTPKDF(7)>
+
=item SSHKDF, see L<EVP_KDF-SSHKDF(7)>
=item TLS1-PRF, see L<EVP_KDF-TLS1_PRF(7)>
diff --git a/include/openssl/core_names.h.in b/include/openssl/core_names.h.in
index e0a4c5e632..1c4396e69b 100644
--- a/include/openssl/core_names.h.in
+++ b/include/openssl/core_names.h.in
@@ -76,6 +76,7 @@ extern "C" {
#define OSSL_KDF_NAME_PBKDF2 "PBKDF2"
#define OSSL_KDF_NAME_SCRYPT "SCRYPT"
#define OSSL_KDF_NAME_SNMPKDF "SNMPKDF"
+#define OSSL_KDF_NAME_SRTPKDF "SRTPKDF"
#define OSSL_KDF_NAME_SSHKDF "SSHKDF"
#define OSSL_KDF_NAME_SSKDF "SSKDF"
#define OSSL_KDF_NAME_TLS1_PRF "TLS1-PRF"
diff --git a/include/openssl/proverr.h b/include/openssl/proverr.h
index fdfa8916a2..e27048faed 100644
--- a/include/openssl/proverr.h
+++ b/include/openssl/proverr.h
@@ -69,8 +69,10 @@
#define PROV_R_INVALID_ITERATION_COUNT 123
#define PROV_R_INVALID_IV_LENGTH 109
#define PROV_R_INVALID_KDF 232
+#define PROV_R_INVALID_KDR 256
#define PROV_R_INVALID_KEY 158
#define PROV_R_INVALID_KEY_LENGTH 105
+#define PROV_R_INVALID_LABEL 257
#define PROV_R_INVALID_MAC 151
#define PROV_R_INVALID_MEMORY_SIZE 235
#define PROV_R_INVALID_MGF1_MD 167
diff --git a/include/openssl/self_test.h b/include/openssl/self_test.h
index 8dab9b6f99..c5e4be955e 100644
--- a/include/openssl/self_test.h
+++ b/include/openssl/self_test.h
@@ -84,6 +84,7 @@ extern "C" {
#define OSSL_SELF_TEST_DESC_KDF_X942KDF "X942KDF"
#define OSSL_SELF_TEST_DESC_KDF_PBKDF2 "PBKDF2"
#define OSSL_SELF_TEST_DESC_KDF_SNMPKDF "SNMPKDF"
+#define OSSL_SELF_TEST_DESC_KDF_SRTPKDF "SRTPKDF"
#define OSSL_SELF_TEST_DESC_KDF_SSHKDF "SSHKDF"
#define OSSL_SELF_TEST_DESC_KDF_TLS12_PRF "TLS12_PRF"
#define OSSL_SELF_TEST_DESC_KDF_KBKDF "KBKDF"
diff --git a/providers/common/provider_err.c b/providers/common/provider_err.c
index 6cdb728333..f8fb4c1679 100644
--- a/providers/common/provider_err.c
+++ b/providers/common/provider_err.c
@@ -99,9 +99,11 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
"invalid iteration count" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_IV_LENGTH), "invalid iv length" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KDF), "invalid kdf" },
+ { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KDR), "invalid kdr" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY), "invalid key" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_KEY_LENGTH),
"invalid key length" },
+ { ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_LABEL), "invalid label" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MAC), "invalid mac" },
{ ERR_PACK(ERR_LIB_PROV, 0, PROV_R_INVALID_MEMORY_SIZE),
"invalid memory size" },
diff --git a/providers/defltprov.c b/providers/defltprov.c
index cddec70369..87c53ca761 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -375,6 +375,9 @@ static const OSSL_ALGORITHM deflt_kdfs[] = {
#ifndef OPENSSL_NO_SNMPKDF
{ PROV_NAMES_SNMPKDF, "provider=default", ossl_kdf_snmpkdf_functions },
#endif
+#ifndef OPENSSL_NO_SRTPKDF
+ { PROV_NAMES_SRTPKDF, "provider=default", ossl_kdf_srtpkdf_functions },
+#endif
#ifndef OPENSSL_NO_SSHKDF
{ PROV_NAMES_SSHKDF, "provider=default", ossl_kdf_sshkdf_functions },
#endif
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index ce2645ce07..f321990b62 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -447,6 +447,9 @@ static const OSSL_ALGORITHM fips_kdfs[] = {
#ifndef OPENSSL_NO_SNMPKDF
{ PROV_NAMES_SNMPKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_snmpkdf_functions },
#endif
+#ifndef OPENSSL_NO_SRTPKDF
+ { PROV_NAMES_SRTPKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_srtpkdf_functions },
+#endif
#ifndef OPENSSL_NO_SSHKDF
{ PROV_NAMES_SSHKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_sshkdf_functions },
#endif
@@ -471,6 +474,9 @@ static const OSSL_ALGORITHM fips_kdfs_internal[] = {
#ifndef OPENSSL_NO_SNMPKDF
{ PROV_NAMES_SNMPKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_snmpkdf_functions },
#endif
+#ifndef OPENSSL_NO_SRTPKDF
+ { PROV_NAMES_SRTPKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_srtpkdf_functions },
+#endif
#ifndef OPENSSL_NO_SSHKDF
{ PROV_NAMES_SSHKDF, FIPS_DEFAULT_PROPERTIES, ossl_kdf_sshkdf_functions },
#endif
diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc
index 4d41126bc7..bc7e77bf1f 100644
--- a/providers/fips/self_test_data.inc
+++ b/providers/fips/self_test_data.inc
@@ -533,6 +533,40 @@ static const ST_KAT_PARAM snmpkdf_params[] = {
};
#endif
+#ifndef OPENSSL_NO_SRTPKDF
+static const char srtpkdf_cipher[] = "AES-256-CTR";
+static const int srtpkdf_kdr = 0x100;
+
+static const unsigned char srtpkdf_key[] = {
+ 0x4b, 0x26, 0xfa, 0xdc, 0x0a, 0x9b, 0xe8, 0x23,
+ 0xdc, 0xd6, 0xab, 0xc8, 0x2c, 0x04, 0x39, 0x75,
+ 0xa6, 0x03, 0xf0, 0x05, 0x87, 0xb8, 0x75, 0x34,
+ 0x60, 0xba, 0xf0, 0x50, 0x2e, 0xee, 0x66, 0xbb };
+
+static const unsigned char srtpkdf_salt[] = {
+ 0x99, 0x74, 0xa3, 0x00, 0x33, 0x28, 0x84, 0xfb,
+ 0xfa, 0x03, 0x71, 0x8c, 0xe0, 0xe0 };
+
+static const unsigned char srtpkdf_index[] = {
+ 0x6e, 0xe6, 0x30, 0x14 };
+
+static const int srtpkdf_label = 5;
+
+static const unsigned char srtpkdf_expected[] = {
+ 0x5c, 0x4e, 0x98, 0xd3, 0x29, 0x6e, 0x00, 0x9b,
+ 0x45, 0x38, 0x09, 0x6d, 0x72, 0xe4 };
+
+static const ST_KAT_PARAM srtpkdf_params[] = {
+ ST_KAT_PARAM_UTF8STRING(OSSL_KDF_PARAM_CIPHER, srtpkdf_cipher),
+ ST_KAT_PARAM_OCTET(OSSL_KDF_PARAM_KEY, srtpkdf_key),
+ ST_KAT_PARAM_OCTET(OSSL_KDF_PARAM_SALT, srtpkdf_salt),
+ ST_KAT_PARAM_OCTET(OSSL_KDF_PARAM_SRTPKDF_INDEX, srtpkdf_index),
+ ST_KAT_PARAM_INT(OSSL_KDF_PARAM_SRTPKDF_KDR, srtpkdf_kdr),
+ ST_KAT_PARAM_INT(OSSL_KDF_PARAM_SRTPKDF_LABEL, srtpkdf_label),
+ ST_KAT_PARAM_END()
+};
+#endif
+
#ifndef OPENSSL_NO_SSKDF
static const char sskdf_digest[] = "SHA256";
static const unsigned char sskdf_secret[] = {
@@ -864,6 +898,15 @@ static const ST_KAT_KDF st_kat_kdf_tests[] =
ITM(snmpkdf_expected)
},
#endif
+#ifndef OPENSSL_NO_SRTPKDF
+ {
+ OSSL_SELF_TEST_DESC_KDF_SRTPKDF,
+ OSSL_KDF_NAME_SRTPKDF,
+ 0,
+ srtpkdf_params,
+ ITM(srtpkdf_expected)
+ },
+#endif
#ifndef OPENSSL_NO_SSKDF
{
OSSL_SELF_TEST_DESC_KDF_SSKDF,
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index 5a7ffd276a..990dd25864 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -292,6 +292,7 @@ extern const OSSL_DISPATCH ossl_kdf_hkdf_sha384_functions[];
extern const OSSL_DISPATCH ossl_kdf_hkdf_sha512_functions[];
extern const OSSL_DISPATCH ossl_kdf_tls1_3_kdf_functions[];
extern const OSSL_DISPATCH ossl_kdf_snmpkdf_functions[];
+extern const OSSL_DISPATCH ossl_kdf_srtpkdf_functions[];
extern const OSSL_DISPATCH ossl_kdf_sshkdf_functions[];
extern const OSSL_DISPATCH ossl_kdf_sskdf_functions[];
extern const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[];
diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h
index 6863f64714..04b41d53c8 100644
--- a/providers/implementations/include/prov/names.h
+++ b/providers/implementations/include/prov/names.h
@@ -296,6 +296,7 @@
#define PROV_NAMES_PBKDF2 "PBKDF2:1.2.840.113549.1.5.12"
#define PROV_NAMES_PVKKDF "PVKKDF"
#define PROV_NAMES_SNMPKDF "SNMPKDF"
+#define PROV_NAMES_SRTPKDF "SRTPKDF"
#define PROV_NAMES_SSHKDF "SSHKDF"
#define PROV_NAMES_X963KDF "X963KDF:X942KDF-CONCAT"
#define PROV_NAMES_X942KDF_ASN1 "X942KDF-ASN1:X942KDF"
diff --git a/providers/implementations/kdfs/build.info b/providers/implementations/kdfs/build.info
index f94c78bf4d..60146804b3 100644
--- a/providers/implementations/kdfs/build.info
+++ b/providers/implementations/kdfs/build.info
@@ -12,6 +12,7 @@ $PKCS12KDF_GOAL=../../libdefault.a
$SSKDF_GOAL=../../libdefault.a ../../libfips.a
$SCRYPT_GOAL=../../libdefault.a
$SNMPKDF_GOAL=../../libdefault.a ../../libfips.a
+$SRTPKDF_GOAL=../../libdefault.a ../../libfips.a
$SSHKDF_GOAL=../../libdefault.a ../../libfips.a
$X942KDF_GOAL=../../libdefault.a ../../libfips.a
$HMAC_DRBG_KDF_GOAL=../../libdefault.a ../../libfips.a
@@ -51,6 +52,10 @@ IF[{- !$disabled{snmpkdf} -}]
SOURCE[$SNMPKDF_GOAL]=snmpkdf.c
ENDIF
+IF[{- !$disabled{srtpkdf} -}]
+ SOURCE[$SRTPKDF_GOAL]=srtpkdf.c
+ENDIF
+
IF[{- !$disabled{sshkdf} -}]
SOURCE[$SSHKDF_GOAL]=sshkdf.c
ENDIF
diff --git a/providers/implementations/kdfs/snmpkdf.c b/providers/implementations/kdfs/snmpkdf.c
index f81738fee0..5e4831fdeb 100644
--- a/providers/implementations/kdfs/snmpkdf.c
+++ b/providers/implementations/kdfs/snmpkdf.c
@@ -265,18 +265,21 @@ const OSSL_DISPATCH ossl_kdf_snmpkdf_functions[] = {
*
* Shared_key = SHA-1(Derived_password || snmpEngineID || Derived_password).
*
+ * Input:
* e_id - engine ID(eid)
* e_len - engineID length
* password - password
* password_len - password length
* okey - pointer to key output, FIPS testing limited to SHA-1.
- * okeylen - key output length
- * return - 1 pass 0 for error
+ * keylen - key length
+ * Output:
+ * okey - filled with derived key
+ * return - 1 on pass, 0 fail
*/
static int SNMPKDF(const EVP_MD *evp_md,
const unsigned char *e_id, size_t e_len,
unsigned char *password, size_t password_len,
- unsigned char *okey, size_t okeylen)
+ unsigned char *okey, size_t keylen)
{
EVP_MD_CTX *md = NULL;
unsigned char digest[EVP_MAX_MD_SIZE];
@@ -285,7 +288,7 @@ static int SNMPKDF(const EVP_MD *evp_md,
int ret = 0;
/* Limited to SHA-1 and SHA-2 hashes presently */
- if (okey == NULL || okeylen == 0)
+ if (okey == NULL || keylen == 0)
return 0;
md = EVP_MD_CTX_new();
@@ -295,7 +298,7 @@ static int SNMPKDF(const EVP_MD *evp_md,
}
mdsize = EVP_MD_get_size(evp_md);
- if (mdsize <= 0 || mdsize < okeylen)
+ if (mdsize <= 0 || mdsize > keylen)
goto err;
if (!EVP_DigestInit_ex(md, evp_md, NULL))
@@ -315,7 +318,7 @@ static int SNMPKDF(const EVP_MD *evp_md,
|| !EVP_DigestFinal_ex(md, digest, &md_len))
goto err;
- memcpy(okey, digest, okeylen);
+ memcpy(okey, digest, md_len);
ret = 1;
diff --git a/providers/implementations/kdfs/srtpkdf.c b/providers/implementations/kdfs/srtpkdf.c
new file mode 100644
index 0000000000..46e5411bf2
--- /dev/null
+++ b/providers/implementations/kdfs/srtpkdf.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include <openssl/bn.h>
+#include <openssl/core_names.h>
+#include <openssl/proverr.h>
+#include "internal/cryptlib.h"
+#include "internal/numbers.h"
+#include "crypto/evp.h"
+#include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
+#include "prov/implementations.h"
+#include "prov/provider_util.h"
+#include "providers/implementations/kdfs/srtpkdf.inc"
+
+#define KDF_SRTP_AUTH_KEY_LEN 20
+#define KDF_SRTP_SALT_KEY_LEN 14
+#define KDF_SRTCP_AUTH_KEY_LEN KDF_SRTP_AUTH_KEY_LEN
+#define KDF_SRTCP_SALT_KEY_LEN KDF_SRTP_SALT_KEY_LEN
+#define KDF_SRTP_SALT_LEN 14
+#define KDF_SRTP_KDR_LEN 6
+#define KDF_SRTP_IDX_LEN 6
+#define KDF_SRTCP_IDX_LEN 4
+#define KDF_SRTP_IV_LEN 16
+#define KDF_SRTP_MAX_KDR 24
+#define KDF_SRTP_MAX_LABEL 7
+#define KDF_SRTP_MAX_SALT_LEN (KDF_SRTP_SALT_LEN + 2)
+
+/* See RFC 3711, Section 4.3.3 */
+static OSSL_FUNC_kdf_newctx_fn kdf_srtpkdf_new;
+static OSSL_FUNC_kdf_dupctx_fn kdf_srtpkdf_dup;
+static OSSL_FUNC_kdf_freectx_fn kdf_srtpkdf_free;
+static OSSL_FUNC_kdf_reset_fn kdf_srtpkdf_reset;
+static OSSL_FUNC_kdf_derive_fn kdf_srtpkdf_derive;
+static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_srtpkdf_settable_ctx_params;
+static OSSL_FUNC_kdf_set_ctx_params_fn kdf_srtpkdf_set_ctx_params;
+static OSSL_FUNC_kdf_gettable_ctx_params_fn kdf_srtpkdf_gettable_ctx_params;
+static OSSL_FUNC_kdf_get_ctx_params_fn kdf_srtpkdf_get_ctx_params;
+
+static int SRTPKDF(OSSL_LIB_CTX *provctx, const EVP_CIPHER *cipher,
+ const unsigned char *mkey, const unsigned char *msalt, const unsigned char *index,
+ const uint32_t kdr, const uint32_t kdr_n,
+ const uint32_t label, unsigned char *obuffer, const size_t keylen);
+
+typedef struct {
+ /* Warning: Any changes to this structure may require you to update kdf_srtpkdf_dup */
+ void *provctx;
+ PROV_CIPHER cipher;
+ unsigned char *key;
+ size_t key_len;
+ unsigned char *salt;
+ size_t salt_len;
+ unsigned char *index;
+ size_t index_len;
+ uint32_t kdr;
+ uint32_t kdr_n; /* 2 ** kdr_n = kdr */
+ uint32_t label;
+} KDF_SRTPKDF;
+
+static void *kdf_srtpkdf_new(void *provctx)
+{
+ KDF_SRTPKDF *ctx;
+
+ if (!ossl_prov_is_running())
+ return NULL;
+
+ if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL)
+ ctx->provctx = provctx;
+ return ctx;
+}
+
+static void *kdf_srtpkdf_dup(void *vsrc)
+{
+ const KDF_SRTPKDF *src = (const KDF_SRTPKDF *)vsrc;
+ KDF_SRTPKDF *dest;
+
+ dest = kdf_srtpkdf_new(src->provctx);
+ if (dest != NULL) {
+ if (!ossl_prov_memdup(src->key, src->key_len,
+ &dest->key, &dest->key_len)
+ || !ossl_prov_memdup(src->salt, src->salt_len,
+ &dest->salt, &dest->salt_len)
+ || !ossl_prov_memdup(src->index, src->index_len,
+ &dest->index, &dest->index_len)
+ || !ossl_prov_cipher_copy(&dest->cipher, &src->cipher))
+ goto err;
+ dest->kdr = src->kdr;
+ dest->kdr_n = src->kdr_n;
+ dest->label = src->label;
+ }
+ return dest;
+
+err:
+ kdf_srtpkdf_free(dest);
+ return NULL;
+}
+
+static void kdf_srtpkdf_free(void *vctx)
+{
+ KDF_SRTPKDF *ctx = (KDF_SRTPKDF *)vctx;
+
+ if (ctx != NULL) {
+ kdf_srtpkdf_reset(ctx);
+ OPENSSL_free(ctx);
+ }
+}
+
+static void kdf_srtpkdf_reset(void *vctx)
+{
+ KDF_SRTPKDF *ctx = (KDF_SRTPKDF *)vctx;
+ void *provctx = ctx->provctx;
+
+ ossl_prov_cipher_reset(&ctx->cipher);
+ OPENSSL_clear_free(ctx->key, ctx->key_len);
+ OPENSSL_clear_free(ctx->index, ctx->index_len);
+ OPENSSL_clear_free(ctx->salt, ctx->salt_len);
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->provctx = provctx;
+}
+
+static int srtpkdf_set_membuf(unsigned char **dst, size_t *dst_len,
+ const OSSL_PARAM *p)
+{
+ OPENSSL_clear_free(*dst, *dst_len);
+ *dst = NULL;
+ *dst_len = 0;
+ return OSSL_PARAM_get_octet_string(p, (void **)dst, 0, dst_len);
+}
+
+static int is_power_of_two(uint32_t x, uint32_t *n)
+{
+ /* Check if we've been given an exact power of two */
+ if (x == 0 || (x & (x - 1)) != 0) {
+ *n = 0;
+ return 0;
+ }
+ /* Count the number of trailing bits in the passed value */
+#ifdef __GNUC__
+ *n = __builtin_ctz(x);
+#else
+ {
+ uint32_t count = 0;
+ while ((x & 1) == 0) {
+ count++;
+ x >>= 1;
+ }
+ *n = count;
+ }
+#endif
+ return 1;
+}
+
+static int kdf_srtpkdf_derive(void *vctx, unsigned char *key, size_t keylen,
+ const OSSL_PARAM params[])
+{
+ KDF_SRTPKDF *ctx = (KDF_SRTPKDF *)vctx;
+ const EVP_CIPHER *cipher;
+ OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
+
+ if (!ossl_prov_is_running() || !kdf_srtpkdf_set_ctx_params(ctx, params))
+ return 0;
+
+ cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+ if (cipher == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_CIPHER);
+ return 0;
+ }
+ if (ctx->key == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+ return 0;
+ }
+ if (ctx->salt == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_SALT);
+ return 0;
+ }
+ if (ctx->kdr > 0) {
+ uint32_t n = 0;
+ if (!is_power_of_two(ctx->kdr, &n)
+ || n > KDF_SRTP_MAX_KDR) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KDR);
+ return 0;
+ }
+ ctx->kdr_n = n;
+ }
+ if (ctx->label > KDF_SRTP_MAX_LABEL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_LABEL);
+ return 0;
+ }
+
+ return SRTPKDF(libctx, cipher, ctx->key, ctx->salt, ctx->index,
+ ctx->kdr, ctx->kdr_n, ctx->label, key, keylen);
+}
+
+static int kdf_srtpkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ struct srtp_set_ctx_params_st p;
+ KDF_SRTPKDF *ctx = vctx;
+ OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
+ const EVP_CIPHER *cipher;
+
+ if (params == NULL)
+ return 1;
+
+ if (ctx == NULL || !srtp_set_ctx_params_decoder(params, &p))
+ return 0;
+
+ if ((p.cipher != NULL)
+ && !ossl_prov_cipher_load(&ctx->cipher, p.cipher, p.propq, libctx))
+ return 0;
+
+ cipher = ossl_prov_cipher_cipher(&ctx->cipher);
+ if (cipher == NULL)
+ return 0;
+ if (!EVP_CIPHER_is_a(cipher, "AES-128-CTR") && !EVP_CIPHER_is_a(cipher, "AES-192-CTR")
+ && !EVP_CIPHER_is_a(cipher, "AES-256-CTR"))
+ return 0;
+
+ if ((p.key != NULL)
+ && !srtpkdf_set_membuf(&ctx->key, &ctx->key_len, p.key))
+ return 0;
+
+ if ((p.salt != NULL)
+ && !srtpkdf_set_membuf(&ctx->salt, &ctx->salt_len, p.salt))
+ return 0;
+
+ if ((p.index != NULL)
+ && !srtpkdf_set_membuf(&ctx->index, &ctx->index_len, p.index))
+ return 0;
+
+ if (p.kdr != NULL) {
+ if (!OSSL_PARAM_get_uint32(p.kdr, &ctx->kdr))
+ return 0;
+ }
+
+ if (p.label != NULL) {
+ if (!OSSL_PARAM_get_uint32(p.label, &ctx->label))
+ return 0;
+ }
+
+ return 1;
+}
+
+static const OSSL_PARAM *kdf_srtpkdf_settable_ctx_params(ossl_unused void *ctx,
+ ossl_unused void *p_ctx)
+{
+ return srtp_set_ctx_params_list;
+}
+
+static int kdf_srtpkdf_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ struct srtp_get_ctx_params_st p;
+ KDF_SRTPKDF *ctx = vctx;
+
+ if (ctx == NULL || !srtp_get_ctx_params_decoder(params, &p))
+ return 0;
+
+ if (p.size != NULL) {
+ size_t sz = EVP_CIPHER_key_length(ossl_prov_cipher_cipher(&ctx->cipher));
+
+ if (!OSSL_PARAM_set_size_t(p.size, sz))
+ return 0;
+ }
+ return 1;
+}
+
+static const OSSL_PARAM *kdf_srtpkdf_gettable_ctx_params(ossl_unused void *ctx,
+ ossl_unused void *p_ctx)
+{
+ return srtp_get_ctx_params_list;
+}
+
+const OSSL_DISPATCH ossl_kdf_srtpkdf_functions[] = {
+ { OSSL_FUNC_KDF_NEWCTX, (void (*)(void))kdf_srtpkdf_new },
+ { OSSL_FUNC_KDF_DUPCTX, (void (*)(void))kdf_srtpkdf_dup },
+ { OSSL_FUNC_KDF_FREECTX, (void (*)(void))kdf_srtpkdf_free },
+ { OSSL_FUNC_KDF_RESET, (void (*)(void))kdf_srtpkdf_reset },
+ { OSSL_FUNC_KDF_DERIVE, (void (*)(void))kdf_srtpkdf_derive },
+ { OSSL_FUNC_KDF_SETTABLE_CTX_PARAMS,
+ (void (*)(void))kdf_srtpkdf_settable_ctx_params },
+ { OSSL_FUNC_KDF_SET_CTX_PARAMS,
+ (void (*)(void))kdf_srtpkdf_set_ctx_params },
+ { OSSL_FUNC_KDF_GETTABLE_CTX_PARAMS,
+ (void (*)(void))kdf_srtpkdf_gettable_ctx_params },
+ { OSSL_FUNC_KDF_GET_CTX_PARAMS,
+ (void (*)(void))kdf_srtpkdf_get_ctx_params },
+ { 0, NULL }
+};
+
+/*
+ * SRTPKDF - In compliance with SP800-135 and RFC3711, calculate
+ * various keys defined by label using a master key,
+ * master salt, kdr(if non-zero) and index.
+ *
+ * Denote the cryptographic key (encryption key, cipher salt or
+ * authentication key(HMAC key), etc) to be derived as K. The
+ * length of K is denoted by L. Below is a description of the KDF.
+ *
+ * master_salt: a random non-salt value.
+ * kdr: the key derivation rate. kdr is a number from the set
+ * factor of 2.
+ * index: a 48-bit value in RTP or a 32-bit value in RTCP.
+ * See Sections 3.2.1 and 4.3.2 of RFC 3711 for details.
+ * A function, DIV, is defined as followed:
+ * a and x are non-negative integers.
+ * a DIV x = a | x (a DIV x) is represented as a bit string whose
+ * length (in bits) is the same as a.
+ * label: an 8-bit value represented by two hexadecimal numbers from
+ * the set of {0x00,0x01, 0x02, 0x03, 0x04, 0x05}.
+ * https://www.ietf.org/archive/id/draft-ietf-avtcore-srtp-encrypted-header-ext-01.html
+ * The values 06 and 07 are used.
+ * key_id = label || (index DIV kdr)
+ *
+ * Input:
+ * cipher - AES cipher
+ * mkey - pointer to master key
+ * msalt - pointer to master salt
+ * idx - pointer to index
+ * kdr - key derivation rate
+ * kdr_n - power of kdr (2**kdr_n = kdr)
+ * label - 8-bit label
+ * obuffer - buffer for output
+ * keylen - length of output buffer
+ * Output:
+ * obuffer - filled with derived key
+ * return - 1 on pass, 0 fail
+ */
+int SRTPKDF(OSSL_LIB_CTX *provctx, const EVP_CIPHER *cipher,
+ const unsigned char *mkey, const unsigned char *msalt, const unsigned char *index,
+ const uint32_t kdr, const uint32_t kdr_n,
+ const uint32_t label, unsigned char *obuffer, const size_t keylen)
+{
+ EVP_CIPHER_CTX *ctx = NULL;
+ int outl, i, index_len = 0, o_len = 0, salt_len = 0;
+ unsigned char buf[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[KDF_SRTP_IV_LEN];
+ unsigned char local_salt[KDF_SRTP_MAX_SALT_LEN];
+ unsigned char master_salt[KDF_SRTP_MAX_SALT_LEN];
+ BIGNUM *bn_index = NULL, *bn_salt = NULL;
+ int ret, iv_len = KDF_SRTP_IV_LEN, rv = 0;
+
+ salt_len = KDF_SRTP_SALT_LEN;
+
+ /* get label-specific lengths */
+ switch (label) {
+ case 0:
+ index_len = KDF_SRTP_IDX_LEN;
+ o_len = EVP_CIPHER_key_length(cipher);
+ break;
+ case 1:
+ index_len = KDF_SRTP_IDX_LEN;
+ o_len = KDF_SRTP_AUTH_KEY_LEN;
+ break;
+ case 2:
+ index_len = KDF_SRTP_IDX_LEN;
+ o_len = KDF_SRTP_SALT_KEY_LEN;
+ break;
+ case 3:
+ index_len = KDF_SRTCP_IDX_LEN;
+ o_len = EVP_CIPHER_key_length(cipher);
+ break;
+ case 4:
+ index_len = KDF_SRTCP_IDX_LEN;
+ o_len = KDF_SRTCP_AUTH_KEY_LEN;
+ break;
+ case 5:
+ index_len = KDF_SRTCP_IDX_LEN;
+ o_len = KDF_SRTCP_SALT_KEY_LEN;
+ break;
+ case 6:
+ index_len = KDF_SRTP_IDX_LEN;
+ o_len = EVP_CIPHER_key_length(cipher);
+ break;
+ case 7:
+ index_len = KDF_SRTP_IDX_LEN;
+ o_len = KDF_SRTP_SALT_KEY_LEN;
+ break;
+ default:
+ return rv;
+ }
+
+ if ((obuffer == NULL) || (keylen > INT_MAX) || (o_len > (int)keylen))
+ return rv;
+
+ /* set up a couple of work areas for the final logic on the salt */
+ memset(iv, 0, KDF_SRTP_IV_LEN);
+ memset(master_salt, 0, KDF_SRTP_MAX_SALT_LEN);
+ memcpy(master_salt, msalt, salt_len);
+
+ /* gather some bignums for some math */
+ bn_index = BN_new();
+ bn_salt = BN_new();
+ if ((bn_index == NULL) || (bn_salt == NULL)) {
+ BN_free(bn_index);
+ BN_free(bn_salt);
+ return rv;
+ }
+
+ /* if index is NULL or kdr=0, then index and kdr are not in play */
+ if ((index != NULL) && (kdr > 0)) {
+ if (!BN_bin2bn(index, index_len, bn_index))
+ goto err;
+
+ ret = BN_rshift(bn_salt, bn_index, kdr_n);
+ if (!ret)
+ goto err;
+ iv_len = BN_bn2bin(bn_salt, iv);
+ for (i = 1; i <= iv_len; i++)
+ master_salt[salt_len - i] ^= iv[iv_len - i];
+ }
+
+ /* take the munged up salt from above and add the label */
+ memset(local_salt, 0, KDF_SRTP_MAX_SALT_LEN);
+ memcpy(local_salt, master_salt, salt_len);
+ local_salt[((KDF_SRTP_SALT_LEN - 1) - index_len)] ^= label;
+
+ /* perform the AES encryption on the master key and derived salt */
+ memset(buf, 0, o_len);
+ if (!(ctx = EVP_CIPHER_CTX_new())
+ || (EVP_EncryptInit_ex(ctx, cipher, NULL, mkey, local_salt) <= 0)
+ || (EVP_CIPHER_CTX_set_padding(ctx, 0) <= 0)
+ || (EVP_EncryptUpdate(ctx, (unsigned char *)obuffer, &outl, buf, o_len) <= 0)
+ || (EVP_EncryptFinal_ex(ctx, (unsigned char *)obuffer, &outl) <= 0))
+ goto err;
+
+ rv = 1;
+err:
+ EVP_CIPHER_CTX_free(ctx);
+ OPENSSL_cleanse(iv, KDF_SRTP_IV_LEN);
+ OPENSSL_cleanse(local_salt, KDF_SRTP_MAX_SALT_LEN);
+ OPENSSL_cleanse(master_salt, KDF_SRTP_IV_LEN);
+ BN_clear_free(bn_index);
+ BN_clear_free(bn_salt);
+ return rv;
+}
diff --git a/providers/implementations/kdfs/srtpkdf.inc.in b/providers/implementations/kdfs/srtpkdf.inc.in
new file mode 100644
index 0000000000..0cf5ec15a3
--- /dev/null
+++ b/providers/implementations/kdfs/srtpkdf.inc.in
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the \"License\"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+{-
+use OpenSSL::paramnames qw(produce_param_decoder);
+-}
+
+{- produce_param_decoder('srtp_set_ctx_params',
+ (['OSSL_KDF_PARAM_PROPERTIES', 'propq', 'utf8_string'],
+ ['OSSL_KDF_PARAM_CIPHER', 'cipher', 'utf8_string'],
+ ['OSSL_KDF_PARAM_KEY', 'key', 'octet_string'],
+ ['OSSL_KDF_PARAM_SALT', 'salt', 'octet_string'],
+ ['OSSL_KDF_PARAM_SRTPKDF_INDEX', 'index', 'octet_string'],
+ ['OSSL_KDF_PARAM_SRTPKDF_KDR', 'kdr', 'uint32'],
+ ['OSSL_KDF_PARAM_LABEL', 'label', 'uint32'],
+ )); -}
+
+{- produce_param_decoder('srtp_get_ctx_params',
+ (['OSSL_KDF_PARAM_SIZE', 'size', 'size_t'],
+ )); -}
diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t
index c6bb748c4f..58221897a4 100644
--- a/test/recipes/30-test_evp.t
+++ b/test/recipes/30-test_evp.t
@@ -42,6 +42,7 @@ my $no_determinstic_nonce = disabled("hmac-drbg-kdf");
my $no_kbkdf = disabled("kbkdf");
my $no_krb5kdf = disabled("krb5kdf");
my $no_snmpkdf = disabled("snmpkdf");
+my $no_srtpkdf = disabled("srtpkdf");
my $no_sshkdf = disabled("sshkdf");
# Default config depends on if the legacy module is built or not
@@ -76,6 +77,7 @@ my @files = qw(
);
push @files, qw(evpkdf_ssh.txt) unless $no_sshkdf;
push @files, qw(evpkdf_snmp.txt) unless $no_snmpkdf;
+push @files, qw(evpkdf_srtp.txt) unless $no_srtpkdf;
push @files, qw(
evpkdf_kbkdf_counter.txt
evpkdf_kbkdf_kmac.txt
diff --git a/test/recipes/30-test_evp_data/evpkdf_srtp.txt b/test/recipes/30-test_evp_data/evpkdf_srtp.txt
new file mode 100644
index 0000000000..a810b90825
--- /dev/null
+++ b/test/recipes/30-test_evp_data/evpkdf_srtp.txt
@@ -0,0 +1,396 @@
+#
+# Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License"). You may not use
+# this file except in compliance with the License. You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+# Tests start with one of these keywords
+# Cipher Decrypt Derive Digest Encoding KDF MAC PBE
+# PrivPubKeyPair Sign Verify VerifyRecover
+# and continue until a blank line. Lines starting with a pound sign are ignored.
+
+Title = SRTPKDF tests (from RFC 3711 test vectors and additional cases)
+
+# Test Case 1: RFC 3711 test vectors B.3, encryption key
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+
+# Test Case 1.1, variation, missing kdr (default as zero)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+
+# Test Case 1.2, variation, missing index (default as zero)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+
+# Test Case 1.3, variation, default kdr and index
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+
+# Test Case 1.4, variation, missing label (default as zero)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Output = C61E7A93744F39EE10734AFE3FF7A087
+
+# Test Case 2: RFC 3711 test vectors B.3, salt key
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:2
+Output = 30CBBC08863D8C85D49DB34A9AE1
+
+# Test Case 3: RFC 3711 test vectors B.3, authentication key
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:1
+Output = CEBE321F6FF7716B6FD4AB49AF256A156D38BAA4
+
+# Negative Test case 1, missing cipher
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_CTRL_ERROR
+
+# Negative Test case 2, invalid cipher
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_CTRL_ERROR
+
+# Negative Test case 3, missing key
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_DERIVE_ERROR
+
+# Negative Test case 4, missing salt
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_DERIVE_ERROR
+
+# Negative Test case 5, invalid label
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:8
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_DERIVE_ERROR
+
+# Negative Test case 6, invalid kdr (not power of 2)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:5
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_DERIVE_ERROR
+
+# Negative Test case 7, invalid kdr (kdr out of range)
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:E1F97A0D3E018BE0D64FA32C06DE4139
+Ctrl.hexsalt = hexsalt:0EC675AD498AFEEBB6960B3AABE6
+Ctrl.kdr = kdr:0x10000000
+Ctrl.index = hexindex:000000000000
+Ctrl.label = label:0
+Output = C61E7A93744F39EE10734AFE3FF7A087
+Result = KDF_DERIVE_ERROR
+
+# Additional tests from
+# https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/kdf-components-srtp-1.0
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:08284B49F520
+Ctrl.label = label:0
+Output = A920DF50EAA111D03FBE9B203121C07D
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:08284B49F520
+Ctrl.label = label:1
+Output = A337DC070C0DAFA942F1E3A27ACD3C9917CE4B4D
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:08284B49F520
+Ctrl.label = label:2
+Output = 9E2BC99C86037F2AD98D72927428
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtcpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B62109
+Ctrl.label = label:3
+Output = 94D76CA7ADB05b8631CF62538D97BE74
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtcpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B62109
+Ctrl.label = label:4
+Output = FA02251D693645BC1001f83C5A13CB3E3D77F7EA
+
+# prompt.json tgId:3, tcid:21, expectedResults.json tcId:21 srtcpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:8C307F105F79D5D2C26B1A933AE22CD5
+Ctrl.hexsalt = hexsalt:563B4C15458D977B68080242CEE1
+Ctrl.kdr = kdr:1
+Ctrl.index = hexindex:69B62109
+Ctrl.label = label:5
+Output = 70C0481A04E3610EC8AF8623FA9B
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:3D6FECDCE1BE
+Ctrl.label = label:0
+Output = A2F4D858CCDF585D9C5CA787C5A3031F
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:3D6FECDCE1BE
+Ctrl.label = label:1
+Output = C140C97CAC05B2ED338AD353014A90012F37B45C
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:3D6FECDCE1BE
+Ctrl.label = label:2
+Output = AA6DE94B3BCB5108EFD350AD6936
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtcpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:1C7B571C
+Ctrl.label = label:3
+Output = 2844C8F56E2AF865E4EBBD0D083A4FAE
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtcpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:1C7B571C
+Ctrl.label = label:4
+Output = 50135309CF64D5162723749CCF085708F8E81636
+
+# prompt.json tgId:4, tcid:31, expectedResults.json tcId:31 srtcpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:127A535F66D5D43135E5DB87F04AF2DB
+Ctrl.hexsalt = hexsalt:82D0D04DC693E29E0FE7FECBF041
+Ctrl.kdr = kdr:2
+Ctrl.index = hexindex:1C7B571C
+Ctrl.label = label:5
+Output = 47CB081EC69F7E74FEB3FCD1BD20
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:F4EE616415B9
+Ctrl.label = label:0
+Output = B46322B06F6E4B189F27744EAD8C5173
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:F4EE616415B9
+Ctrl.label = label:1
+Output = F9F246054B3D4AA2520CE2612192749AA6970BB0
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:F4EE616415B9
+Ctrl.label = label:2
+Output = 18EA8EA36A90617224FBFBCB849A
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtcpKe
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:13DE080C
+Ctrl.label = label:3
+Output = F4140d2419f7A75CEE91FC942CD94514
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtcpKa
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:13DE080C
+Ctrl.label = label:4
+Output = 6E65548ABFE131FF91E7AE75409F96AD9D9FE345
+
+# prompt.json tgId:6, tcid:51, expectedResults.json tcId:51 srtcpKs
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:CF08F8159FCF18DA8108A3FE3B707C2B
+Ctrl.hexsalt = hexsalt:4AF8352708E0A164C6645A63E5BB
+Ctrl.kdr = kdr:8
+Ctrl.index = hexindex:13DE080C
+Ctrl.label = label:5
+Output = 2C195A5AA9F539BD7CC7D6E23483
+
+# internalProjection.json, tgId: 1
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:A48A570A43E12372BF58495FDFD88D78
+Ctrl.hexsalt = hexsalt:E1D109B42D6C16A8830F9E7DDF4B
+Ctrl.index = hexindex:8E5BDF08FA78
+Ctrl.label = label:0
+Output = 30371635BF658204857EC5BFE13AFFE3
+
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:A48A570A43E12372BF58495FDFD88D78
+Ctrl.hexsalt = hexsalt:E1D109B42D6C16A8830F9E7DDF4B
+Ctrl.index = hexindex:8E5BDF08FA78
+Ctrl.label = label:1
+Output = 83E0821E1DDBD044C2DD3A980BB445875F97B4D5
+
+FIPSversion = >=4.0.0
+KDF = SRTPKDF
+Ctrl.cipher = cipher:AES-128-CTR
+Ctrl.hexkey = hexkey:A48A570A43E12372BF58495FDFD88D78
+Ctrl.hexsalt = hexsalt:E1D109B42D6C16A8830F9E7DDF4B
+Ctrl.index = hexindex:8E5BDF08FA78
+Ctrl.label = label:2
+Output = B27816A7A139D73E71A55FCD7006
diff --git a/util/perl/OpenSSL/paramnames.pm b/util/perl/OpenSSL/paramnames.pm
index 8473aa2b07..cea9d2d068 100644
--- a/util/perl/OpenSSL/paramnames.pm
+++ b/util/perl/OpenSSL/paramnames.pm
@@ -228,6 +228,9 @@ my %params = (
'OSSL_KDF_PARAM_INFO' => "info", # octet string
'OSSL_KDF_PARAM_SEED' => "seed", # octet string
'OSSL_KDF_PARAM_SNMPKDF_EID' => "eid", # octet string
+ 'OSSL_KDF_PARAM_SRTPKDF_INDEX' => "index", # octet string
+ 'OSSL_KDF_PARAM_SRTPKDF_KDR' => "kdr", # uint32_t
+ 'OSSL_KDF_PARAM_SRTPKDF_LABEL' => "label", # uint32_t
'OSSL_KDF_PARAM_SSHKDF_XCGHASH' => "xcghash", # octet string
'OSSL_KDF_PARAM_SSHKDF_SESSION_ID' => "session_id", # octet string
'OSSL_KDF_PARAM_SSHKDF_TYPE' => "type", # int