diff --git a/srtp/srtp.c b/srtp/srtp.c index 0c9b7cb98..479473532 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -847,6 +847,7 @@ static inline int full_key_length(const srtp_cipher_type_t *cipher) { switch (cipher->id) { case SRTP_NULL_CIPHER: + return 0; case SRTP_AES_ICM_128: return SRTP_AES_ICM_128_KEY_LEN_WSALT; case SRTP_AES_ICM_192: @@ -862,6 +863,19 @@ static inline int full_key_length(const srtp_cipher_type_t *cipher) } } +/* Get the key length that the application should supply for the given auth */ +static inline int full_auth_key_length(const srtp_auth_type_t *auth) +{ + switch (auth->id) { + case SRTP_NULL_AUTH: + return 0; + case SRTP_HMAC_SHA1: + return SRTP_AES_ICM_128_KEY_LEN_WSALT; + default: + return 0; + } +} + static unsigned int srtp_validate_policy_master_keys( const srtp_policy_t *policy) { @@ -957,7 +971,7 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp, srtp_err_status_t stat; srtp_kdf_t kdf; uint8_t tmp_key[MAX_SRTP_KEY_LEN]; - int input_keylen, input_keylen_rtcp; + int input_keylen, full_keylen; int kdf_keylen = 30, rtp_keylen, rtcp_keylen; int rtp_base_key_len, rtp_salt_len; int rtcp_base_key_len, rtcp_salt_len; @@ -995,9 +1009,17 @@ srtp_err_status_t srtp_stream_init_keys(srtp_stream_ctx_t *srtp, session_keys->mki_size = master_key->mki_size; input_keylen = full_key_length(session_keys->rtp_cipher->type); - input_keylen_rtcp = full_key_length(session_keys->rtcp_cipher->type); - if (input_keylen_rtcp > input_keylen) { - input_keylen = input_keylen_rtcp; + full_keylen = full_auth_key_length(session_keys->rtp_auth->type); + if (full_keylen > input_keylen) { + input_keylen = full_keylen; + } + full_keylen = full_key_length(session_keys->rtcp_cipher->type); + if (full_keylen > input_keylen) { + input_keylen = full_keylen; + } + full_keylen = full_auth_key_length(session_keys->rtcp_auth->type); + if (full_keylen > input_keylen) { + input_keylen = full_keylen; } rtp_keylen = srtp_cipher_get_key_length(session_keys->rtp_cipher); @@ -3410,8 +3432,7 @@ void srtp_crypto_policy_set_null_cipher_hmac_null(srtp_crypto_policy_t *p) */ p->cipher_type = SRTP_NULL_CIPHER; - p->cipher_key_len = - SRTP_AES_ICM_128_KEY_LEN_WSALT; /* 128 bit key, 112 bit salt */ + p->cipher_key_len = 0; p->auth_type = SRTP_NULL_AUTH; p->auth_key_len = 0; p->auth_tag_len = 0; diff --git a/test/srtp_driver.c b/test/srtp_driver.c index ef2314776..8f313b470 100644 --- a/test/srtp_driver.c +++ b/test/srtp_driver.c @@ -62,7 +62,9 @@ srtp_err_status_t srtp_validate(void); -srtp_err_status_t srtp_validate_null(void); +srtp_err_status_t srtp_validate_null_sha1_80(void); + +srtp_err_status_t srtp_validate_null_null(void); #ifdef GCM srtp_err_status_t srtp_validate_gcm(void); @@ -458,8 +460,17 @@ int main(int argc, char *argv[]) } printf("testing srtp_protect and srtp_unprotect against " - "reference packet using null cipher and HMAC\n"); - if (srtp_validate_null() == srtp_err_status_ok) { + "reference packet using null cipher and SHA1-80 HMAC\n"); + if (srtp_validate_null_sha1_80() == srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + + printf("testing srtp_protect and srtp_unprotect against " + "reference packet using null cipher and null HMAC\n"); + if (srtp_validate_null_null() == srtp_err_status_ok) { printf("passed\n\n"); } else { printf("failed\n"); @@ -1901,13 +1912,13 @@ srtp_err_status_t srtp_validate(void) } /* - * srtp_validate_null() verifies the correctness of libsrtp by comparing + * srtp_validate_null_sha1_80() verifies the correctness of libsrtp by comparing * some computed packets against some pre-computed reference values. * These packets were made with a policy that applies null encryption * and HMAC authentication. */ -srtp_err_status_t srtp_validate_null(void) +srtp_err_status_t srtp_validate_null_sha1_80(void) { // clang-format off uint8_t srtp_plaintext_ref[28] = { @@ -1957,8 +1968,8 @@ srtp_err_status_t srtp_validate_null(void) srtp_policy_t policy; /* - * create a session with a single stream using the default srtp - * policy and with the SSRC value 0xcafebabe + * create a session with a single stream using the null cipher + * and sha1_80 policy and with the SSRC value 0xcafebabe */ memset(&policy, 0, sizeof(policy)); srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); @@ -2060,6 +2071,176 @@ srtp_err_status_t srtp_validate_null(void) return srtp_err_status_ok; } +/* + * srtp_validate_null_null() verifies the correctness of libsrtp by comparing + * some computed packets against some pre-computed reference values. + * These packets were made with a policy that applies null encryption + * and null authentication. + */ + +srtp_err_status_t srtp_validate_null_null(void) +{ + // clang-format off + uint8_t srtp_plaintext_ref[28] = { + 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, + 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab + }; + uint8_t srtp_plaintext[28] = { + 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, + 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, + }; + uint8_t srtp_ciphertext[28] = { + 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, + 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, + }; + uint8_t rtcp_plaintext_ref[24] = { + 0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + }; + uint8_t rtcp_plaintext[28] = { + 0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0x00, 0x00, 0x00, 0x00, + }; + uint8_t srtcp_ciphertext[28] = { + 0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0x00, 0x00, 0x00, 0x01, + }; + // clang-format on + + srtp_t srtp_snd, srtp_recv; + srtp_err_status_t status; + int len; + srtp_policy_t policy; + + /* + * create a session with a single stream using the null cipher + * and null hmac policy and with the SSRC value 0xcafebabe + */ + memset(&policy, 0, sizeof(policy)); + srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtp); + srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtcp); + policy.ssrc.type = ssrc_specific; + policy.ssrc.value = 0xcafebabe; + /* + * We need some non-zero value set here + */ + policy.key = (void *)(uintptr_t)-1; + policy.window_size = 128; + policy.allow_repeat_tx = 0; + policy.next = NULL; + + status = srtp_create(&srtp_snd, &policy); + if (status) { + return status; + } + + /* + * protect plaintext, then compare with ciphertext + */ + len = 28; + status = srtp_protect(srtp_snd, srtp_plaintext, &len); + if (status || (len != 28)) { + return srtp_err_status_fail; + } + if (status) { + return status; + } + + debug_print(mod_driver, "ciphertext:\n %s", + octet_string_hex_string(srtp_plaintext, len)); + debug_print(mod_driver, "ciphertext reference:\n %s", + octet_string_hex_string(srtp_ciphertext, len)); + + if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) { + return srtp_err_status_fail; + } + + /* + * protect plaintext rtcp, then compare with srtcp ciphertext + */ + len = 24; + status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len); + if (!status && (len != 28)) { + status = srtp_err_status_fail; + } + if (status) { + return status; + } + + debug_print(mod_driver, "srtcp ciphertext:\n %s", + octet_string_hex_string(rtcp_plaintext, len)); + debug_print(mod_driver, "srtcp ciphertext reference:\n %s", + octet_string_hex_string(srtcp_ciphertext, len)); + + if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) { + return srtp_err_status_fail; + } + + /* + * create a receiver session context comparable to the one created + * above - we need to do this so that the replay checking doesn't + * complain + */ + status = srtp_create(&srtp_recv, &policy); + if (status) { + return status; + } + + /* + * unprotect ciphertext, then compare with plaintext + */ + status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + if (!status && (len != 28)) { + status = srtp_err_status_fail; + } + if (status) { + return status; + } + + if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) { + return srtp_err_status_fail; + } + + /* + * unprotect srtcp ciphertext, then compare with rtcp plaintext + */ + len = 28; + status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); + if (!status && (len != 24)) { + status = srtp_err_status_fail; + } + if (status) { + return status; + } + + if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) { + return srtp_err_status_fail; + } + + status = srtp_dealloc(srtp_snd); + if (status) { + return status; + } + + status = srtp_dealloc(srtp_recv); + if (status) { + return status; + } + + return srtp_err_status_ok; +} + #ifdef GCM /* * srtp_validate_gcm() verifies the correctness of libsrtp by comparing