Skip to content

Commit f5abaa4

Browse files
authored
Merge pull request #559 from bifurcation/null-vuln
Use a full-length key even with null ciphers
2 parents 80e90da + 812a683 commit f5abaa4

File tree

2 files changed

+208
-7
lines changed

2 files changed

+208
-7
lines changed

srtp/srtp.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -757,22 +757,40 @@ static inline int base_key_length(const srtp_cipher_type_t *cipher,
757757
int key_length)
758758
{
759759
switch (cipher->id) {
760+
case SRTP_NULL_CIPHER:
761+
return 0;
760762
case SRTP_AES_ICM_128:
761763
case SRTP_AES_ICM_192:
762764
case SRTP_AES_ICM_256:
763765
/* The legacy modes are derived from
764766
* the configured key length on the policy */
765767
return key_length - SRTP_SALT_LEN;
766-
break;
767768
case SRTP_AES_GCM_128:
768769
return key_length - SRTP_AEAD_SALT_LEN;
769-
break;
770770
case SRTP_AES_GCM_256:
771771
return key_length - SRTP_AEAD_SALT_LEN;
772-
break;
773772
default:
774773
return key_length;
775-
break;
774+
}
775+
}
776+
777+
/* Get the key length that the application should supply for the given cipher */
778+
static inline int full_key_length(const srtp_cipher_type_t *cipher)
779+
{
780+
switch (cipher->id) {
781+
case SRTP_NULL_CIPHER:
782+
case SRTP_AES_ICM_128:
783+
return SRTP_AES_ICM_128_KEY_LEN_WSALT;
784+
case SRTP_AES_ICM_192:
785+
return SRTP_AES_ICM_192_KEY_LEN_WSALT;
786+
case SRTP_AES_ICM_256:
787+
return SRTP_AES_ICM_256_KEY_LEN_WSALT;
788+
case SRTP_AES_GCM_128:
789+
return SRTP_AES_GCM_128_KEY_LEN_WSALT;
790+
case SRTP_AES_GCM_256:
791+
return SRTP_AES_ICM_256_KEY_LEN_WSALT;
792+
default:
793+
return 0;
776794
}
777795
}
778796

@@ -870,6 +888,7 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp,
870888
srtp_err_status_t stat;
871889
srtp_kdf_t kdf;
872890
uint8_t tmp_key[MAX_SRTP_KEY_LEN];
891+
int input_keylen, input_keylen_rtcp;
873892
int kdf_keylen = 30, rtp_keylen, rtcp_keylen;
874893
int rtp_base_key_len, rtp_salt_len;
875894
int rtcp_base_key_len, rtcp_salt_len;
@@ -906,6 +925,12 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp,
906925

907926
session_keys->mki_size = master_key->mki_size;
908927

928+
input_keylen = full_key_length(session_keys->rtp_cipher->type);
929+
input_keylen_rtcp = full_key_length(session_keys->rtcp_cipher->type);
930+
if (input_keylen_rtcp > input_keylen) {
931+
input_keylen = input_keylen_rtcp;
932+
}
933+
909934
rtp_keylen = srtp_cipher_get_key_length(session_keys->rtp_cipher);
910935
rtcp_keylen = srtp_cipher_get_key_length(session_keys->rtcp_cipher);
911936
rtp_base_key_len =
@@ -920,6 +945,11 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp,
920945
kdf_keylen = 46; /* AES-CTR mode is always used for KDF */
921946
}
922947

948+
if (input_keylen > kdf_keylen) {
949+
kdf_keylen = 46; /* AES-CTR mode is always used for KDF */
950+
}
951+
952+
debug_print(mod_srtp, "input key len: %d", input_keylen);
923953
debug_print(mod_srtp, "srtp key len: %d", rtp_keylen);
924954
debug_print(mod_srtp, "srtcp key len: %d", rtcp_keylen);
925955
debug_print(mod_srtp, "base key len: %d", rtp_base_key_len);
@@ -932,7 +962,7 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp,
932962
* the legacy CTR mode KDF, which uses a 112 bit master SALT.
933963
*/
934964
memset(tmp_key, 0x0, MAX_SRTP_KEY_LEN);
935-
memcpy(tmp_key, key, (rtp_base_key_len + rtp_salt_len));
965+
memcpy(tmp_key, key, input_keylen);
936966

937967
/* initialize KDF state */
938968
#if defined(OPENSSL) && defined(OPENSSL_KDF)
@@ -3247,7 +3277,7 @@ void srtp_crypto_policy_set_null_cipher_hmac_sha1_80(srtp_crypto_policy_t *p)
32473277
*/
32483278

32493279
p->cipher_type = SRTP_NULL_CIPHER;
3250-
p->cipher_key_len = 0;
3280+
p->cipher_key_len = 16;
32513281
p->auth_type = SRTP_HMAC_SHA1;
32523282
p->auth_key_len = 20;
32533283
p->auth_tag_len = 10;
@@ -3261,7 +3291,7 @@ void srtp_crypto_policy_set_null_cipher_hmac_null(srtp_crypto_policy_t *p)
32613291
*/
32623292

32633293
p->cipher_type = SRTP_NULL_CIPHER;
3264-
p->cipher_key_len = 0;
3294+
p->cipher_key_len = 16;
32653295
p->auth_type = SRTP_NULL_AUTH;
32663296
p->auth_key_len = 0;
32673297
p->auth_tag_len = 0;

test/srtp_driver.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161

6262
srtp_err_status_t srtp_validate(void);
6363

64+
srtp_err_status_t srtp_validate_null(void);
65+
6466
#ifdef GCM
6567
srtp_err_status_t srtp_validate_gcm(void);
6668
#endif
@@ -442,6 +444,15 @@ int main(int argc, char *argv[])
442444
exit(1);
443445
}
444446

447+
printf("testing srtp_protect and srtp_unprotect against "
448+
"reference packet using null cipher and HMAC\n");
449+
if (srtp_validate_null() == srtp_err_status_ok) {
450+
printf("passed\n\n");
451+
} else {
452+
printf("failed\n");
453+
exit(1);
454+
}
455+
445456
#ifdef GCM
446457
printf("testing srtp_protect and srtp_unprotect against "
447458
"reference packet using GCM\n");
@@ -1806,6 +1817,166 @@ srtp_err_status_t srtp_validate()
18061817
return srtp_err_status_ok;
18071818
}
18081819

1820+
/*
1821+
* srtp_validate_null() verifies the correctness of libsrtp by comparing
1822+
* some computed packets against some pre-computed reference values.
1823+
* These packets were made with a policy that applies null encryption
1824+
* and HMAC authentication.
1825+
*/
1826+
1827+
srtp_err_status_t srtp_validate_null()
1828+
{
1829+
// clang-format off
1830+
uint8_t srtp_plaintext_ref[28] = {
1831+
0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1832+
0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1833+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1834+
0xab, 0xab, 0xab, 0xab
1835+
};
1836+
uint8_t srtp_plaintext[38] = {
1837+
0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1838+
0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1839+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1840+
0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
1841+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1842+
};
1843+
uint8_t srtp_ciphertext[38] = {
1844+
0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
1845+
0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
1846+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1847+
0xab, 0xab, 0xab, 0xab, 0xab, 0xa1, 0x36, 0x27,
1848+
0x0b, 0x67, 0x91, 0x34, 0xce, 0x9b
1849+
};
1850+
uint8_t rtcp_plaintext_ref[24] = {
1851+
0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
1852+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1853+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1854+
};
1855+
uint8_t rtcp_plaintext[38] = {
1856+
0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
1857+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1858+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1859+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1860+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1861+
};
1862+
uint8_t srtcp_ciphertext[38] = {
1863+
0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
1864+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1865+
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
1866+
0x00, 0x00, 0x00, 0x01, 0xfe, 0x88, 0xc7, 0xfd,
1867+
0xfd, 0x37, 0xeb, 0xce, 0x61, 0x5d,
1868+
};
1869+
// clang-format on
1870+
1871+
srtp_t srtp_snd, srtp_recv;
1872+
srtp_err_status_t status;
1873+
int len;
1874+
srtp_policy_t policy;
1875+
1876+
/*
1877+
* create a session with a single stream using the default srtp
1878+
* policy and with the SSRC value 0xcafebabe
1879+
*/
1880+
memset(&policy, 0, sizeof(policy));
1881+
srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
1882+
srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtcp);
1883+
policy.ssrc.type = ssrc_specific;
1884+
policy.ssrc.value = 0xcafebabe;
1885+
policy.key = test_key;
1886+
policy.deprecated_ekt = NULL;
1887+
policy.window_size = 128;
1888+
policy.allow_repeat_tx = 0;
1889+
policy.next = NULL;
1890+
1891+
status = srtp_create(&srtp_snd, &policy);
1892+
if (status) {
1893+
return status;
1894+
}
1895+
1896+
/*
1897+
* protect plaintext, then compare with ciphertext
1898+
*/
1899+
len = 28;
1900+
status = srtp_protect(srtp_snd, srtp_plaintext, &len);
1901+
if (status || (len != 38)) {
1902+
return srtp_err_status_fail;
1903+
}
1904+
1905+
debug_print(mod_driver, "ciphertext:\n %s",
1906+
octet_string_hex_string(srtp_plaintext, len));
1907+
debug_print(mod_driver, "ciphertext reference:\n %s",
1908+
octet_string_hex_string(srtp_ciphertext, len));
1909+
1910+
if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) {
1911+
return srtp_err_status_fail;
1912+
}
1913+
1914+
/*
1915+
* protect plaintext rtcp, then compare with srtcp ciphertext
1916+
*/
1917+
len = 24;
1918+
status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len);
1919+
if (status || (len != 38)) {
1920+
return srtp_err_status_fail;
1921+
}
1922+
1923+
debug_print(mod_driver, "srtcp ciphertext:\n %s",
1924+
octet_string_hex_string(rtcp_plaintext, len));
1925+
debug_print(mod_driver, "srtcp ciphertext reference:\n %s",
1926+
octet_string_hex_string(srtcp_ciphertext, len));
1927+
1928+
if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) {
1929+
return srtp_err_status_fail;
1930+
}
1931+
1932+
/*
1933+
* create a receiver session context comparable to the one created
1934+
* above - we need to do this so that the replay checking doesn't
1935+
* complain
1936+
*/
1937+
status = srtp_create(&srtp_recv, &policy);
1938+
if (status) {
1939+
return status;
1940+
}
1941+
1942+
/*
1943+
* unprotect ciphertext, then compare with plaintext
1944+
*/
1945+
status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
1946+
if (status || (len != 28)) {
1947+
return status;
1948+
}
1949+
1950+
if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) {
1951+
return srtp_err_status_fail;
1952+
}
1953+
1954+
/*
1955+
* unprotect srtcp ciphertext, then compare with rtcp plaintext
1956+
*/
1957+
len = 38;
1958+
status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len);
1959+
if (status || (len != 24)) {
1960+
return status;
1961+
}
1962+
1963+
if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) {
1964+
return srtp_err_status_fail;
1965+
}
1966+
1967+
status = srtp_dealloc(srtp_snd);
1968+
if (status) {
1969+
return status;
1970+
}
1971+
1972+
status = srtp_dealloc(srtp_recv);
1973+
if (status) {
1974+
return status;
1975+
}
1976+
1977+
return srtp_err_status_ok;
1978+
}
1979+
18091980
#ifdef GCM
18101981
/*
18111982
* srtp_validate_gcm() verifies the correctness of libsrtp by comparing

0 commit comments

Comments
 (0)