diff --git a/crypto/cipher/aes_icm.c b/crypto/cipher/aes_icm.c index f56fd76ac..74b06ff8a 100644 --- a/crypto/cipher/aes_icm.c +++ b/crypto/cipher/aes_icm.c @@ -217,6 +217,7 @@ static srtp_err_status_t srtp_aes_icm_context_init(void *cv, const uint8_t *key) status = srtp_aes_expand_encryption_key(key, base_key_len, &c->expanded_key); if (status) { + octet_string_set_to_zero(&c->expanded_key, sizeof(c->expanded_key)); v128_set_to_zero(&c->counter); v128_set_to_zero(&c->offset); return status; @@ -316,7 +317,7 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, /* check that there's enough segment left*/ size_t bytes_of_new_keystream = bytes_to_encr - c->bytes_in_buffer; size_t blocks_of_new_keystream = (bytes_of_new_keystream + 15) >> 4; - if ((blocks_of_new_keystream + htons(c->counter.v16[7])) > 0xffff) { + if (blocks_of_new_keystream > (size_t)0xffff - htons(c->counter.v16[7])) { return srtp_err_status_terminus; } diff --git a/srtp/srtp.c b/srtp/srtp.c index 7174975e2..41a34e23c 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -1965,6 +1965,10 @@ static srtp_err_status_t srtp_get_session_keys_for_packet( size_t tag_len, srtp_session_keys_t **session_keys) { + if (stream->num_master_keys == 0 || stream->session_keys == NULL) { + return srtp_err_status_no_ctx; + } + if (!stream->use_mki) { *session_keys = &stream->session_keys[0]; return srtp_err_status_ok; @@ -2003,6 +2007,10 @@ static srtp_err_status_t srtp_get_session_keys_for_rtp_packet( { size_t tag_len = 0; + if (stream->num_master_keys == 0 || stream->session_keys == NULL) { + return srtp_err_status_no_ctx; + } + // Determine the authentication tag size if (stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_128 || stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_256) { @@ -2023,6 +2031,10 @@ static srtp_err_status_t srtp_get_session_keys_for_rtcp_packet( { size_t tag_len = 0; + if (stream->num_master_keys == 0 || stream->session_keys == NULL) { + return srtp_err_status_no_ctx; + } + // Determine the authentication tag size if (stream->session_keys[0].rtcp_cipher->algorithm == SRTP_AES_GCM_128 || stream->session_keys[0].rtcp_cipher->algorithm == SRTP_AES_GCM_256) { @@ -2334,7 +2346,8 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, return srtp_err_status_cryptex_err; } - if (enc_start > srtp_len - tag_len - stream->mki_size) { + if (tag_len + stream->mki_size > srtp_len || + enc_start > srtp_len - tag_len - stream->mki_size) { return srtp_err_status_parse_err; } @@ -2971,7 +2984,8 @@ srtp_err_status_t srtp_unprotect(srtp_t ctx, return status; } - if (enc_start > srtp_len - tag_len - stream->mki_size) { + if (tag_len + stream->mki_size > srtp_len || + enc_start > srtp_len - tag_len - stream->mki_size) { return srtp_err_status_parse_err; } enc_octet_len = srtp_len - enc_start - stream->mki_size - tag_len; diff --git a/test/rdbx_driver.c b/test/rdbx_driver.c index f420134a7..cbccbc1bf 100644 --- a/test/rdbx_driver.c +++ b/test/rdbx_driver.c @@ -61,6 +61,8 @@ srtp_err_status_t test_replay_dbx(size_t num_trials, size_t ws); +srtp_err_status_t test_replay_dbx_boundaries(size_t ws); + double rdbx_check_adds_per_second(size_t num_trials, size_t ws); void usage(char *prog_name) @@ -321,6 +323,65 @@ srtp_err_status_t test_replay_dbx(size_t num_trials, size_t ws) srtp_rdbx_dealloc(&rdbx); + status = test_replay_dbx_boundaries(ws); + if (status) { + return status; + } + + return srtp_err_status_ok; +} + +srtp_err_status_t test_replay_dbx_boundaries(size_t ws) +{ + srtp_rdbx_t rdbx; + ssize_t oldest_delta = -((ssize_t)ws - 1); + + if (srtp_rdbx_init(&rdbx, ws) != srtp_err_status_ok) { + printf("replay_init failed\n"); + return srtp_err_status_init_fail; + } + + if (srtp_rdbx_add_index(&rdbx, 0) != srtp_err_status_ok) { + printf("rdbx_add_index failed at delta 0\n"); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_check(&rdbx, oldest_delta) != srtp_err_status_ok) { + printf("rdbx_check failed at oldest in-window delta %zd\n", + oldest_delta); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_add_index(&rdbx, oldest_delta) != srtp_err_status_ok) { + printf("rdbx_add_index failed at oldest in-window delta %zd\n", + oldest_delta); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_check(&rdbx, oldest_delta) != srtp_err_status_replay_fail) { + printf("rdbx_check failed to reject oldest in-window delta %zd\n", + oldest_delta); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_check(&rdbx, -((ssize_t)ws)) != srtp_err_status_replay_old) { + printf("rdbx_check failed to reject out-of-window delta %zd\n", + -((ssize_t)ws)); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_add_index(&rdbx, (ssize_t)ws) != srtp_err_status_ok) { + printf("rdbx_add_index failed at window-size delta %zu\n", ws); + return srtp_err_status_algo_fail; + } + if (rdbx.index != ws) { + printf("rdbx index was %llu, expected %zu\n", + (unsigned long long)rdbx.index, ws); + return srtp_err_status_algo_fail; + } + if (srtp_rdbx_check(&rdbx, -((ssize_t)ws)) != srtp_err_status_replay_old) { + printf("rdbx_check failed to age out window-size delta %zd\n", + -((ssize_t)ws)); + return srtp_err_status_algo_fail; + } + + srtp_rdbx_dealloc(&rdbx); + return srtp_err_status_ok; } diff --git a/test/replay_driver.c b/test/replay_driver.c index d751e7f9c..50859256f 100644 --- a/test/replay_driver.c +++ b/test/replay_driver.c @@ -63,6 +63,8 @@ size_t num_trials = 1 << 16; srtp_err_status_t test_rdb_db(void); +srtp_err_status_t test_rdb_boundaries(void); + double rdb_check_adds_per_second(void); int main(void) @@ -247,6 +249,75 @@ srtp_err_status_t test_rdb_db(void) return srtp_err_status_fail; } + err = test_rdb_boundaries(); + if (err) { + return err; + } + + return srtp_err_status_ok; +} + +srtp_err_status_t test_rdb_boundaries(void) +{ + srtp_rdb_t rdb; + + if (srtp_rdb_init(&rdb) != srtp_err_status_ok) { + printf("rdb_init failed\n"); + return srtp_err_status_fail; + } + + if (srtp_rdb_add_index(&rdb, 0) != srtp_err_status_ok) { + printf("rdb_add_index failed at index 0\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 127) != srtp_err_status_ok) { + printf("rdb_check failed at index 127\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_add_index(&rdb, 127) != srtp_err_status_ok) { + printf("rdb_add_index failed at index 127\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 127) != srtp_err_status_replay_fail) { + printf("rdb_check failed to reject index 127\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 128) != srtp_err_status_ok) { + printf("rdb_check failed at index 128\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_add_index(&rdb, 128) != srtp_err_status_ok) { + printf("rdb_add_index failed at index 128\n"); + return srtp_err_status_fail; + } + if (rdb.window_start != 1) { + printf("rdb window_start was %u, expected 1\n", rdb.window_start); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 0) != srtp_err_status_replay_old) { + printf("rdb_check failed to age out index 0\n"); + return srtp_err_status_fail; + } + + if (srtp_rdb_init(&rdb) != srtp_err_status_ok) { + printf("rdb_init failed\n"); + return srtp_err_status_fail; + } + + rdb.window_start = 0x7fffffff - 127; + if (srtp_rdb_add_index(&rdb, 0x7fffffff) != srtp_err_status_ok) { + printf("rdb_add_index failed at 31-bit boundary\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 0x7fffffff) != srtp_err_status_replay_fail) { + printf("rdb_check failed to retain 31-bit boundary packet\n"); + return srtp_err_status_fail; + } + if (srtp_rdb_check(&rdb, 0x7fffffff - 128) != srtp_err_status_replay_old) { + printf("rdb_check failed to age packets before 31-bit boundary\n"); + return srtp_err_status_fail; + } + return srtp_err_status_ok; } diff --git a/test/roc_driver.c b/test/roc_driver.c index 1010fd0e3..bd068d9a6 100644 --- a/test/roc_driver.c +++ b/test/roc_driver.c @@ -64,6 +64,8 @@ srtp_err_status_t roc_test(size_t num_trials); +srtp_err_status_t roc_boundary_test(void); + int main(void) { srtp_err_status_t status; @@ -78,6 +80,11 @@ int main(void) printf("failed\n"); exit(status); } + status = roc_boundary_test(); + if (status) { + printf("failed\n"); + exit(status); + } printf("passed\n"); return 0; } @@ -173,3 +180,26 @@ srtp_err_status_t roc_test(size_t num_trials) return srtp_err_status_ok; } + +srtp_err_status_t roc_boundary_test(void) +{ + srtp_xtd_seq_num_t local; + srtp_xtd_seq_num_t est; + ssize_t delta; + + local = (((uint64_t)1) << 16) | 0x0010; + delta = srtp_index_guess(&local, &est, 0x9001); + if (est != 0x9001 || delta != -28687) { + printf("index_guess failed low-seq boundary test\n"); + return srtp_err_status_algo_fail; + } + + local = (((uint64_t)1) << 16) | 0x8001; + delta = srtp_index_guess(&local, &est, 0x0000); + if (est != ((((uint64_t)2) << 16)) || delta != 32767) { + printf("index_guess failed high-seq boundary test\n"); + return srtp_err_status_algo_fail; + } + + return srtp_err_status_ok; +} diff --git a/test/srtp_driver.c b/test/srtp_driver.c index 6967cece7..bd1f411f7 100644 --- a/test/srtp_driver.c +++ b/test/srtp_driver.c @@ -96,6 +96,8 @@ srtp_err_status_t srtp_test_empty_payload(void); #ifdef GCM srtp_err_status_t srtp_test_empty_payload_gcm(void); + +srtp_err_status_t srtp_test_short_packet_gcm_mki(void); #endif srtp_err_status_t srtp_test_remove_stream(void); @@ -122,6 +124,8 @@ srtp_err_status_t srtp_test_cryptex_csrc_but_no_extension_header(void); srtp_err_status_t srtp_test_cryptex_disable(void); +srtp_err_status_t srtp_test_missing_session_keys(void); + double srtp_bits_per_second(size_t msg_len_octets, const srtp_policy_t *policy); double srtp_rejections_per_second(size_t msg_len_octets, @@ -826,6 +830,14 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_unprotect on short packet with GCM and MKI\n"); + if (srtp_test_short_packet_gcm_mki() == srtp_err_status_ok) { + printf("passed\n"); + } else { + printf("failed\n"); + exit(1); + } #endif /* @@ -937,6 +949,14 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing missing session keys handling()..."); + if (srtp_test_missing_session_keys() == srtp_err_status_ok) { + printf("passed\n"); + } else { + printf("failed\n"); + exit(1); + } } if (do_stream_list) { @@ -3378,6 +3398,50 @@ srtp_err_status_t srtp_test_cryptex_disable(void) return srtp_err_status_ok; } +srtp_err_status_t srtp_test_missing_session_keys(void) +{ + srtp_t srtp_receiver; + srtp_policy_t policy; + srtp_stream_ctx_t *stream; + srtp_session_keys_t *session_keys; + size_t num_master_keys; + uint8_t *packet; + size_t packet_len; + size_t buffer_len; + + memset(&policy, 0, sizeof(policy)); + srtp_crypto_policy_set_rtp_default(&policy.rtp); + srtp_crypto_policy_set_rtcp_default(&policy.rtcp); + policy.ssrc.type = ssrc_any_inbound; + policy.key = test_key; + policy.window_size = 128; + policy.allow_repeat_tx = false; + + CHECK_OK(srtp_create(&srtp_receiver, &policy)); + CHECK(srtp_receiver->stream_template != NULL); + + stream = srtp_receiver->stream_template; + session_keys = stream->session_keys; + num_master_keys = stream->num_master_keys; + stream->session_keys = NULL; + stream->num_master_keys = 0; + + packet = create_rtp_test_packet(0, 0xcafebabe, 1, 1, false, &packet_len, + &buffer_len); + packet_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, packet, sizeof(srtp_hdr_t), + &packet_len), + srtp_err_status_no_ctx); + + stream->session_keys = session_keys; + stream->num_master_keys = num_master_keys; + + free(packet); + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} + #ifdef GCM /* * srtp_validate_gcm() verifies the correctness of libsrtp by comparing @@ -4511,6 +4575,42 @@ srtp_err_status_t srtp_test_empty_payload_gcm(void) return srtp_err_status_ok; } + +srtp_err_status_t srtp_test_short_packet_gcm_mki(void) +{ + srtp_t srtp_receiver; + srtp_policy_t policy; + uint8_t *packet; + size_t packet_len; + size_t buffer_len; + + memset(&policy, 0, sizeof(policy)); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp); + policy.ssrc.type = ssrc_any_inbound; + policy.keys = test_keys; + policy.num_master_keys = 2; + policy.use_mki = true; + policy.mki_size = TEST_MKI_ID_SIZE; + + CHECK_OK(srtp_create(&srtp_receiver, &policy)); + + packet = + create_rtp_test_packet(0, 0, 1, 1, false, &packet_len, &buffer_len); + CHECK(packet_len == sizeof(srtp_hdr_t)); + memcpy(packet + packet_len - TEST_MKI_ID_SIZE, test_mki_id, + TEST_MKI_ID_SIZE); + + packet_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, packet, sizeof(srtp_hdr_t), + &packet_len), + srtp_err_status_parse_err); + + free(packet); + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} #endif // GCM srtp_err_status_t srtp_test_remove_stream(void)