diff --git a/fuzzer/fuzzer.c b/fuzzer/fuzzer.c index 0e1494572..afa080a2e 100644 --- a/fuzzer/fuzzer.c +++ b/fuzzer/fuzzer.c @@ -187,7 +187,11 @@ static srtp_err_status_t fuzz_srtp_protect(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_protect(srtp_sender, hdr, len, mki); + size_t out_len = *len + SRTP_MAX_TRAILER_LEN; + srtp_err_status_t s = + srtp_protect(srtp_sender, hdr, *len, hdr, &out_len, mki); + *len = out_len; + return s; } static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender, @@ -195,7 +199,7 @@ static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_unprotect(srtp_sender, hdr, len); + return srtp_unprotect(srtp_sender, hdr, *len, hdr, len); } static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender, @@ -203,7 +207,11 @@ static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_protect_rtcp(srtp_sender, hdr, len, mki); + size_t out_len = *len + SRTP_MAX_SRTCP_TRAILER_LEN; + srtp_err_status_t s = + srtp_protect_rtcp(srtp_sender, hdr, *len, hdr, &out_len, mki); + *len = out_len; + return s; } static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender, @@ -211,7 +219,7 @@ static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_unprotect_rtcp(srtp_sender, hdr, len); + return srtp_unprotect_rtcp(srtp_sender, hdr, *len, hdr, len); } /* Get protect length functions */ diff --git a/include/srtp.h b/include/srtp.h index 7137b94ed..86b3ecfed 100644 --- a/include/srtp.h +++ b/include/srtp.h @@ -426,18 +426,13 @@ srtp_err_status_t srtp_shutdown(void); * - srtp_err_status_replay_fail rtp sequence number was non-increasing * - @e other failure in cryptographic mechanisms */ -srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, - uint8_t *rtp_hdr, - size_t *pkt_octet_len, +srtp_err_status_t srtp_protect(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, size_t mki_index); -srtp_err_status_t srtp_protect2(srtp_t ctx, - const uint8_t *rtp, - size_t rtp_len, - uint8_t *srtp, - size_t *srtp_len, - size_t mki_index); - /** * @brief srtp_unprotect() is the Secure RTP receiver-side packet * processing function. @@ -480,14 +475,10 @@ srtp_err_status_t srtp_protect2(srtp_t ctx, * */ srtp_err_status_t srtp_unprotect(srtp_t ctx, - uint8_t *srtp_hdr, - size_t *len_ptr); - -srtp_err_status_t srtp_unprotect2(srtp_t ctx, - const uint8_t *srtp, - size_t srtp_len, - uint8_t *rtp, - size_t *rtp_len); + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len); /** * @brief srtp_create() allocates and initializes an SRTP session. @@ -1161,17 +1152,12 @@ void srtp_append_salt_to_key(uint8_t *key, * the cryptographic mechanisms. */ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, - uint8_t *rtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, size_t mki_index); -srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, - const uint8_t *rtcp, - size_t rtcp_len, - uint8_t *srtcp, - size_t *srtcp_len, - size_t mki_index); - /** * @brief srtp_unprotect_rtcp() is the Secure RTCP receiver-side packet * processing function. @@ -1213,14 +1199,10 @@ srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, * */ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, - uint8_t *srtcp_hdr, - size_t *pkt_octet_len); - -srtp_err_status_t srtp_unprotect_rtcp2(srtp_t ctx, - const uint8_t *srtcp, - size_t srtcp_len, - uint8_t *rtcp, - size_t *rtcp_len); + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len); /** * @defgroup User data associated to a SRTP session. diff --git a/srtp/srtp.c b/srtp/srtp.c index c8ddd2962..87b909731 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -1744,12 +1744,14 @@ static srtp_err_status_t srtp_get_est_pkt_index(const srtp_hdr_t *hdr, */ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, - uint8_t *rtp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, srtp_session_keys_t *session_keys) { - srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)rtp; + size_t enc_start; /* offset to start of encrypted portion */ size_t enc_octet_len = 0; /* number of octets in encrypted portion */ srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ ssize_t delta; /* delta of local pkt idx and that in hdr */ @@ -1786,16 +1788,26 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, * extension, if present; otherwise, it starts after the last csrc, * if any are present */ - enc_start = rtp_hdr + srtp_get_rtp_hdr_len(hdr); + enc_start = srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp_hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp); } + /* note: the passed size is without the auth tag */ - if (!(enc_start <= rtp_hdr + *pkt_octet_len)) { + if (enc_start > rtp_len) { return srtp_err_status_parse_err; } + enc_octet_len = rtp_len - enc_start; - enc_octet_len = *pkt_octet_len - (enc_start - rtp_hdr); + /* check output length */ + if (*srtp_len < rtp_len + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtp header */ + if (rtp != srtp) { + memcpy(srtp, rtp, enc_start); + } /* * estimate the packet index using the start of the replay window @@ -1849,7 +1861,7 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, * extensions header encryption RFC 6904 */ status = srtp_process_header_encryption( - stream, srtp_get_rtp_xtn_hdr(hdr, rtp_hdr), session_keys); + stream, srtp_get_rtp_xtn_hdr(hdr, srtp), session_keys); if (status) { return status; } @@ -1858,15 +1870,17 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, /* * Set the AAD over the RTP header */ - aad_len = enc_start - rtp_hdr; - status = srtp_cipher_set_aad(session_keys->rtp_cipher, rtp_hdr, aad_len); + aad_len = enc_start; + status = srtp_cipher_set_aad(session_keys->rtp_cipher, srtp, aad_len); if (status) { return (srtp_err_status_cipher_fail); } /* Encrypt the payload */ - status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + size_t outlen = *srtp_len - enc_start; + status = srtp_cipher_encrypt(session_keys->rtp_cipher, rtp + enc_start, + enc_octet_len, srtp + enc_start, &outlen); + enc_octet_len = outlen; if (status) { return srtp_err_status_cipher_fail; } @@ -1875,21 +1889,23 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, * and append that to the output */ status = srtp_cipher_get_tag(session_keys->rtp_cipher, - enc_start + enc_octet_len, &tag_len); + srtp + enc_start + enc_octet_len, &tag_len); if (status) { return (srtp_err_status_cipher_fail); } if (stream->use_mki) { - srtp_inject_mki(rtp_hdr + *pkt_octet_len + tag_len, session_keys, - stream->mki_size); + srtp_inject_mki(srtp + enc_start + enc_octet_len + tag_len, + session_keys, stream->mki_size); } + *srtp_len = enc_start + enc_octet_len; + /* increase the packet length by the length of the auth tag */ - *pkt_octet_len += tag_len; + *srtp_len += tag_len; /* increase the packet length by the length of the mki_size */ - *pkt_octet_len += stream->mki_size; + *srtp_len += stream->mki_size; return srtp_err_status_ok; } @@ -1905,13 +1921,15 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, ssize_t delta, srtp_xtd_seq_num_t est, - uint8_t *srtp_hdr, - size_t *pkt_octet_len, + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len, srtp_session_keys_t *session_keys, bool advance_packet_index) { - srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)srtp; + size_t enc_start; /* offset to start of encrypted portion */ size_t enc_octet_len = 0; /* number of octets in encrypted portion */ v128_t iv; srtp_err_status_t status; @@ -1942,25 +1960,19 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, return srtp_err_status_cipher_fail; } - /* - * find starting point for decryption and length of data to be - * decrypted - the encrypted portion starts after the rtp header - * extension, if present; otherwise, it starts after the last csrc, - * if any are present - */ - enc_start = srtp_hdr + srtp_get_rtp_hdr_len(hdr); + enc_start = srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp_hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp); } - if (!(enc_start <= - srtp_hdr + (*pkt_octet_len - tag_len - stream->mki_size))) { + + if (enc_start > srtp_len - tag_len - stream->mki_size) { return srtp_err_status_parse_err; } /* * We pass the tag down to the cipher when doing GCM mode */ - enc_octet_len = *pkt_octet_len - stream->mki_size - (enc_start - srtp_hdr); + enc_octet_len = srtp_len - enc_start - stream->mki_size; /* * Sanity check the encrypted payload length against @@ -1971,6 +1983,16 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, return srtp_err_status_cipher_fail; } + /* check output length */ + if (*rtp_len < srtp_len - stream->mki_size - tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtp header */ + if (srtp != rtp) { + memcpy(rtp, srtp, enc_start); + } + /* * update the key usage limit, and check it to make sure that we * didn't just hit either the soft limit or the hard limit, and call @@ -1992,16 +2014,17 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, /* * Set the AAD for AES-GCM, which is the RTP header */ - aad_len = enc_start - srtp_hdr; - status = srtp_cipher_set_aad(session_keys->rtp_cipher, srtp_hdr, aad_len); + aad_len = enc_start; + status = srtp_cipher_set_aad(session_keys->rtp_cipher, srtp, aad_len); if (status) { - return (srtp_err_status_cipher_fail); + return srtp_err_status_cipher_fail; } /* Decrypt the ciphertext. This also checks the auth tag based * on the AAD we just specified above */ - status = srtp_cipher_decrypt(session_keys->rtp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + status = + srtp_cipher_decrypt(session_keys->rtp_cipher, srtp + enc_start, + enc_octet_len, rtp + enc_start, &enc_octet_len); if (status) { return status; } @@ -2011,7 +2034,7 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, * extensions header encryption RFC 6904 */ status = srtp_process_header_encryption( - stream, srtp_get_rtp_xtn_hdr(hdr, srtp_hdr), session_keys); + stream, srtp_get_rtp_xtn_hdr(hdr, rtp), session_keys); if (status) { return status; } @@ -2081,37 +2104,20 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, srtp_rdbx_add_index(&stream->rtp_rdbx, delta); } - /* decrease the packet length by the length of the auth tag */ - *pkt_octet_len -= tag_len; - - /* decrease the packet length by the length of the mki_size */ - *pkt_octet_len -= stream->mki_size; + *rtp_len = enc_start + enc_octet_len; return srtp_err_status_ok; } -srtp_err_status_t srtp_protect2(srtp_t ctx, - const uint8_t *rtp, - size_t rtp_len, - uint8_t *srtp, - size_t *srtp_len, - size_t mki_index) -{ - if (*srtp_len < rtp_len) { - return srtp_err_status_bad_param; - } - memcpy(srtp, rtp, rtp_len); - *srtp_len = rtp_len; - return srtp_protect(ctx, srtp, srtp_len, mki_index); -} - -srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, - uint8_t *rtp_hdr, - size_t *pkt_octet_len, +srtp_err_status_t srtp_protect(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, size_t mki_index) { - srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)rtp; + size_t enc_start; /* offset to start of encrypted portion */ uint8_t *auth_start; /* pointer to start of auth. portion */ size_t enc_octet_len = 0; /* number of octets in encrypted portion */ srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ @@ -2126,13 +2132,13 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, debug_print0(mod_srtp, "function srtp_protect"); /* Verify RTP header */ - status = srtp_validate_rtp_header(rtp_hdr, *pkt_octet_len); + status = srtp_validate_rtp_header(rtp, rtp_len); if (status) { return status; } /* check the packet length - it must at least contain a full header */ - if (*pkt_octet_len < octets_in_rtp_header) { + if (rtp_len < octets_in_rtp_header) { return srtp_err_status_bad_param; } @@ -2199,7 +2205,7 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, */ if (session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_128 || session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_256) { - return srtp_protect_aead(ctx, stream, rtp_hdr, pkt_octet_len, + return srtp_protect_aead(ctx, stream, rtp, rtp_len, srtp, srtp_len, session_keys); } @@ -2229,27 +2235,29 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, * encrypted - the encrypted portion starts after the rtp header * extension, if present; otherwise, it starts after the last csrc, * if any are present - * - * if we're not providing confidentiality, set enc_start to NULL */ - if (stream->rtp_services & sec_serv_conf) { - enc_start = rtp_hdr + srtp_get_rtp_hdr_len(hdr); - if (hdr->x == 1) { - enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp_hdr); - } - /* note: the passed size is without the auth tag */ - if (!(enc_start <= rtp_hdr + *pkt_octet_len)) { - return srtp_err_status_parse_err; - } + enc_start = srtp_get_rtp_hdr_len(hdr); + if (hdr->x == 1) { + enc_start += srtp_get_rtp_xtn_hdr_len(hdr, rtp); + } - enc_octet_len = *pkt_octet_len - (enc_start - rtp_hdr); - } else { - enc_start = NULL; + if (enc_start > rtp_len) { + return srtp_err_status_parse_err; + } + enc_octet_len = rtp_len - enc_start; + + /* check output length */ + if (*srtp_len < rtp_len + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtp header */ + if (rtp != srtp) { + memcpy(srtp, rtp, enc_start); } if (stream->use_mki) { - srtp_inject_mki(rtp_hdr + *pkt_octet_len, session_keys, - stream->mki_size); + srtp_inject_mki(srtp + rtp_len, session_keys, stream->mki_size); } /* @@ -2258,8 +2266,8 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { - auth_start = rtp_hdr; - auth_tag = rtp_hdr + *pkt_octet_len + stream->mki_size; + auth_start = srtp; + auth_tag = srtp + rtp_len + stream->mki_size; } else { auth_start = NULL; auth_tag = NULL; @@ -2351,19 +2359,23 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, * extensions header encryption RFC 6904 */ status = srtp_process_header_encryption( - stream, srtp_get_rtp_xtn_hdr(hdr, rtp_hdr), session_keys); + stream, srtp_get_rtp_xtn_hdr(hdr, srtp), session_keys); if (status) { return status; } } /* if we're encrypting, exor keystream into the message */ - if (enc_start) { - status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (stream->rtp_services & sec_serv_conf) { + status = srtp_cipher_encrypt(session_keys->rtp_cipher, rtp + enc_start, + enc_octet_len, srtp + enc_start, + &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } + } else if (rtp != srtp) { + /* if no encryption and not-inplace then need to copy rest of packet */ + memcpy(srtp + enc_start, rtp + enc_start, enc_octet_len); } /* @@ -2378,8 +2390,7 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, } /* run auth func over packet */ - status = srtp_auth_update(session_keys->rtp_auth, auth_start, - *pkt_octet_len); + status = srtp_auth_update(session_keys->rtp_auth, auth_start, rtp_len); if (status) { return status; } @@ -2395,43 +2406,30 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, } } - if (auth_tag) { - /* increase the packet length by the length of the auth tag */ - *pkt_octet_len += tag_len; - } + *srtp_len = enc_start + enc_octet_len; + + /* increase the packet length by the length of the auth tag */ + *srtp_len += tag_len; /* increate the packet length by the mki size if used */ - *pkt_octet_len += stream->mki_size; + *srtp_len += stream->mki_size; return srtp_err_status_ok; } -srtp_err_status_t srtp_unprotect2(srtp_t ctx, - const uint8_t *srtp, - size_t srtp_len, - uint8_t *rtp, - size_t *rtp_len) -{ - if (*rtp_len < srtp_len) { - // this is actually expected but for the tests this should not happen - return srtp_err_status_bad_param; - } - memcpy(rtp, srtp, srtp_len); - *rtp_len = srtp_len; - return srtp_unprotect(ctx, rtp, rtp_len); -} - -srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, - uint8_t *srtp_hdr, - size_t *pkt_octet_len) +srtp_err_status_t srtp_unprotect(srtp_t ctx, + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len) { - srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ - uint8_t *auth_start; /* pointer to start of auth. portion */ - size_t enc_octet_len = 0; /* number of octets in encrypted portion */ - uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ - srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ - ssize_t delta; /* delta of local pkt idx and that in hdr */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)srtp; + size_t enc_start; /* pointer to start of encrypted portion */ + const uint8_t *auth_start; /* pointer to start of auth. portion */ + size_t enc_octet_len = 0; /* number of octets in encrypted portion */ + const uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ + ssize_t delta; /* delta of local pkt idx and that in hdr */ v128_t iv; srtp_err_status_t status; srtp_stream_ctx_t *stream; @@ -2445,13 +2443,13 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, debug_print0(mod_srtp, "function srtp_unprotect"); /* Verify RTP header */ - status = srtp_validate_rtp_header(srtp_hdr, *pkt_octet_len); + status = srtp_validate_rtp_header(srtp, srtp_len); if (status) { return status; } /* check the packet length - it must at least contain a full header */ - if (*pkt_octet_len < octets_in_rtp_header) { + if (srtp_len < octets_in_rtp_header) { return srtp_err_status_bad_param; } @@ -2507,8 +2505,8 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, debug_print(mod_srtp, "estimated u_packet index: %016" PRIx64, est); /* Determine if MKI is being used and what session keys should be used */ - status = srtp_get_session_keys_for_packet(stream, srtp_hdr, *pkt_octet_len, - &session_keys); + status = + srtp_get_session_keys_for_packet(stream, srtp, srtp_len, &session_keys); if (status) { return status; } @@ -2519,9 +2517,8 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, */ if (session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_128 || session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_256) { - return srtp_unprotect_aead(ctx, stream, delta, est, srtp_hdr, - pkt_octet_len, session_keys, - advance_packet_index); + return srtp_unprotect_aead(ctx, stream, delta, est, srtp, srtp_len, rtp, + rtp_len, session_keys, advance_packet_index); } /* get tag length from stream */ @@ -2562,28 +2559,24 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, /* shift est, put into network byte order */ est = be64_to_cpu(est << 16); - /* - * find starting point for decryption and length of data to be - * decrypted - the encrypted portion starts after the rtp header - * extension, if present; otherwise, it starts after the last csrc, - * if any are present - * - * if we're not providing confidentiality, set enc_start to NULL - */ - if (stream->rtp_services & sec_serv_conf) { - enc_start = srtp_hdr + srtp_get_rtp_hdr_len(hdr); - if (hdr->x == 1) { - enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp_hdr); - } - if (!(enc_start <= - srtp_hdr + (*pkt_octet_len - tag_len - stream->mki_size))) { - return srtp_err_status_parse_err; - } + enc_start = srtp_get_rtp_hdr_len(hdr); + if (hdr->x == 1) { + enc_start += srtp_get_rtp_xtn_hdr_len(hdr, srtp); + } - enc_octet_len = *pkt_octet_len - tag_len - stream->mki_size - - (enc_start - srtp_hdr); - } else { - enc_start = NULL; + if (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; + + /* check output length */ + if (*rtp_len < srtp_len - stream->mki_size - tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtp header */ + if (srtp != rtp) { + memcpy(rtp, srtp, enc_start); } /* @@ -2592,8 +2585,8 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { - auth_start = srtp_hdr; - auth_tag = srtp_hdr + *pkt_octet_len - tag_len; + auth_start = srtp; + auth_tag = srtp + srtp_len - tag_len; } else { auth_start = NULL; auth_tag = NULL; @@ -2630,7 +2623,7 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, /* now compute auth function over packet */ status = srtp_auth_update(session_keys->rtp_auth, auth_start, - *pkt_octet_len - tag_len - stream->mki_size); + srtp_len - tag_len - stream->mki_size); if (status) { return status; } @@ -2673,19 +2666,23 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, if (hdr->x == 1 && session_keys->rtp_xtn_hdr_cipher) { /* extensions header encryption RFC 6904 */ status = srtp_process_header_encryption( - stream, srtp_get_rtp_xtn_hdr(hdr, srtp_hdr), session_keys); + stream, srtp_get_rtp_xtn_hdr(hdr, rtp), session_keys); if (status) { return status; } } /* if we're decrypting, add keystream into ciphertext */ - if (enc_start) { - status = srtp_cipher_decrypt(session_keys->rtp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (stream->rtp_services & sec_serv_conf) { + status = + srtp_cipher_decrypt(session_keys->rtp_cipher, srtp + enc_start, + enc_octet_len, rtp + enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } + } else if (rtp != srtp) { + /* if no encryption and not-inplace then need to copy rest of packet */ + memcpy(rtp + enc_start, srtp + enc_start, enc_octet_len); } /* @@ -2750,11 +2747,7 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, srtp_rdbx_add_index(&stream->rtp_rdbx, delta); } - /* decrease the packet length by the length of the auth tag */ - *pkt_octet_len -= tag_len; - - /* decrease the packet length by the mki size */ - *pkt_octet_len -= stream->mki_size; + *rtp_len = enc_start + enc_octet_len; return srtp_err_status_ok; } @@ -3527,12 +3520,14 @@ static srtp_err_status_t srtp_calc_aead_iv_srtcp( */ static srtp_err_status_t srtp_protect_rtcp_aead( srtp_stream_ctx_t *stream, - uint8_t *rtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, srtp_session_keys_t *session_keys) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)rtcp; + size_t enc_start; /* pointer to start of encrypted portion */ uint8_t *trailer_p; /* pointer to start of trailer */ uint32_t trailer; /* trailer value */ size_t enc_octet_len = 0; /* number of octets in encrypted portion */ @@ -3541,7 +3536,6 @@ static srtp_err_status_t srtp_protect_rtcp_aead( size_t tag_len; uint32_t seq_num; v128_t iv; - uint32_t tseq; /* get tag length from stream context */ tag_len = srtp_auth_get_tag_length(session_keys->rtcp_auth); @@ -3550,36 +3544,44 @@ static srtp_err_status_t srtp_protect_rtcp_aead( * set encryption start and encryption length - if we're not * providing confidentiality, set enc_start to NULL */ - enc_start = rtcp_hdr + octets_in_rtcp_header; - enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; + enc_start = octets_in_rtcp_header; + enc_octet_len = rtcp_len - enc_start; + + /* check output length */ + if (*srtcp_len < + rtcp_len + sizeof(srtcp_trailer_t) + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtcp header */ + if (rtcp != srtcp) { + memcpy(srtcp, rtcp, enc_start); + } /* NOTE: hdr->length is not usable - it refers to only the first * RTCP report in the compound packet! */ - trailer_p = enc_start + enc_octet_len + tag_len; + trailer_p = srtcp + enc_start + enc_octet_len + tag_len; if (stream->rtcp_services & sec_serv_conf) { trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */ } else { - enc_start = NULL; - enc_octet_len = 0; /* 0 is network-order independant */ trailer = 0x00000000; /* set encrypt bit */ } if (stream->use_mki) { - srtp_inject_mki(rtcp_hdr + *pkt_octet_len + tag_len + - sizeof(srtcp_trailer_t), + srtp_inject_mki(srtcp + rtcp_len + tag_len + sizeof(srtcp_trailer_t), session_keys, stream->mki_size); } /* * set the auth_tag pointer to the proper location, which is after * the payload, but before the trailer - * (note that srtpc *always* provides authentication, unlike srtp) + * (note that srtcp *always* provides authentication, unlike srtp) */ /* Note: This would need to change for optional mikey data */ - auth_tag = rtcp_hdr + *pkt_octet_len; + auth_tag = srtcp + rtcp_len; /* * check sequence number for overruns, and copy it into the packet @@ -3611,15 +3613,15 @@ static srtp_err_status_t srtp_protect_rtcp_aead( /* * Set the AAD for GCM mode */ - if (enc_start) { + if (stream->rtcp_services & sec_serv_conf) { /* * If payload encryption is enabled, then the AAD consist of * the RTCP header and the seq# at the end of the packet */ - status = srtp_cipher_set_aad(session_keys->rtcp_cipher, rtcp_hdr, + status = srtp_cipher_set_aad(session_keys->rtcp_cipher, rtcp, octets_in_rtcp_header); if (status) { - return (srtp_err_status_cipher_fail); + return srtp_err_status_cipher_fail; } } else { /* @@ -3627,8 +3629,7 @@ static srtp_err_status_t srtp_protect_rtcp_aead( * the entire packet as described in RFC 7714 (Section 9.3. Data * Types in Unencrypted SRTCP Compound Packets) */ - status = srtp_cipher_set_aad(session_keys->rtcp_cipher, rtcp_hdr, - *pkt_octet_len); + status = srtp_cipher_set_aad(session_keys->rtcp_cipher, rtcp, rtcp_len); if (status) { return (srtp_err_status_cipher_fail); } @@ -3636,17 +3637,19 @@ static srtp_err_status_t srtp_protect_rtcp_aead( /* * Process the sequence# as AAD */ - tseq = trailer; - status = srtp_cipher_set_aad(session_keys->rtcp_cipher, (uint8_t *)&tseq, - sizeof(srtcp_trailer_t)); + status = srtp_cipher_set_aad(session_keys->rtcp_cipher, (uint8_t *)&trailer, + sizeof(trailer)); if (status) { return (srtp_err_status_cipher_fail); } /* if we're encrypting, exor keystream into the message */ - if (enc_start) { - status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (stream->rtcp_services & sec_serv_conf) { + size_t outlen = *srtcp_len - enc_start; + status = + srtp_cipher_encrypt(session_keys->rtcp_cipher, rtcp + enc_start, + enc_octet_len, srtcp + enc_start, &outlen); + enc_octet_len = outlen; if (status) { return srtp_err_status_cipher_fail; } @@ -3658,15 +3661,19 @@ static srtp_err_status_t srtp_protect_rtcp_aead( if (status) { return (srtp_err_status_cipher_fail); } - enc_octet_len += tag_len; } else { + /* if no encryption and not-inplace then need to copy rest of packet */ + if (rtcp != srtcp) { + memcpy(srtcp + enc_start, rtcp + enc_start, enc_octet_len); + } + /* * Even though we're not encrypting the payload, we need * to run the cipher to get the auth tag. */ size_t nolen = 0; - status = srtp_cipher_encrypt(session_keys->rtcp_cipher, NULL, nolen, - NULL, &nolen); + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, NULL, 0, NULL, + &nolen); if (status) { return srtp_err_status_cipher_fail; } @@ -3678,14 +3685,15 @@ static srtp_err_status_t srtp_protect_rtcp_aead( if (status) { return (srtp_err_status_cipher_fail); } - enc_octet_len += tag_len; } + *srtcp_len = octets_in_rtcp_header + enc_octet_len; + /* increase the packet length by the length of the auth tag and seq_num*/ - *pkt_octet_len += (tag_len + sizeof(srtcp_trailer_t)); + *srtcp_len += (tag_len + sizeof(srtcp_trailer_t)); /* increase the packet by the mki_size */ - *pkt_octet_len += stream->mki_size; + *srtcp_len += stream->mki_size; return srtp_err_status_ok; } @@ -3699,26 +3707,29 @@ static srtp_err_status_t srtp_protect_rtcp_aead( static srtp_err_status_t srtp_unprotect_rtcp_aead( srtp_t ctx, srtp_stream_ctx_t *stream, - uint8_t *srtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len, srtp_session_keys_t *session_keys) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ - uint8_t *trailer_p; /* pointer to start of trailer */ - uint32_t trailer; /* trailer value */ - size_t enc_octet_len = 0; /* number of octets in encrypted portion */ - uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)srtcp; + size_t enc_start; /* pointer to start of encrypted portion */ + const uint8_t *trailer_p; /* pointer to start of trailer */ + uint32_t trailer; /* trailer value */ + size_t enc_octet_len = 0; /* number of octets in encrypted portion */ + const uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ srtp_err_status_t status; size_t tag_len; size_t tmp_len; uint32_t seq_num; v128_t iv; - uint32_t tseq; /* get tag length from stream context */ tag_len = srtp_auth_get_tag_length(session_keys->rtcp_auth); + enc_start = octets_in_rtcp_header; + /* * set encryption start, encryption length, and trailer */ @@ -3727,25 +3738,16 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( */ /* This should point trailer to the word past the end of the normal data. */ /* This would need to be modified for optional mikey data */ - trailer_p = - srtcp_hdr + *pkt_octet_len - sizeof(srtcp_trailer_t) - stream->mki_size; + trailer_p = srtcp + srtcp_len - sizeof(srtcp_trailer_t) - stream->mki_size; memcpy(&trailer, trailer_p, sizeof(trailer)); /* * We pass the tag down to the cipher when doing GCM mode */ - enc_octet_len = - *pkt_octet_len - - (octets_in_rtcp_header + sizeof(srtcp_trailer_t) + stream->mki_size); - auth_tag = srtcp_hdr + *pkt_octet_len - tag_len - stream->mki_size - - sizeof(srtcp_trailer_t); - - if (*trailer_p & SRTCP_E_BYTE_BIT) { - enc_start = srtcp_hdr + octets_in_rtcp_header; - } else { - enc_octet_len = 0; - enc_start = NULL; /* this indicates that there's no encryption */ - } + enc_octet_len = srtcp_len - (octets_in_rtcp_header + + sizeof(srtcp_trailer_t) + stream->mki_size); + auth_tag = srtcp + (srtcp_len - tag_len - stream->mki_size - + sizeof(srtcp_trailer_t)); /* * check the sequence number for replays @@ -3771,18 +3773,29 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( return srtp_err_status_cipher_fail; } + /* check output length */ + if (*rtcp_len < + srtcp_len - sizeof(srtcp_trailer_t) - stream->mki_size - tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not inplace need to copy rtcp header */ + if (srtcp != rtcp) { + memcpy(rtcp, srtcp, enc_start); + } + /* * Set the AAD for GCM mode */ - if (enc_start) { + if (*trailer_p & SRTCP_E_BYTE_BIT) { /* * If payload encryption is enabled, then the AAD consist of * the RTCP header and the seq# at the end of the packet */ - status = srtp_cipher_set_aad(session_keys->rtcp_cipher, srtcp_hdr, + status = srtp_cipher_set_aad(session_keys->rtcp_cipher, srtcp, octets_in_rtcp_header); if (status) { - return (srtp_err_status_cipher_fail); + return srtp_err_status_cipher_fail; } } else { /* @@ -3790,10 +3803,9 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( * the entire packet as described in RFC 7714 (Section 9.3. Data * Types in Unencrypted SRTCP Compound Packets) */ - status = - srtp_cipher_set_aad(session_keys->rtcp_cipher, srtcp_hdr, - (*pkt_octet_len - tag_len - - sizeof(srtcp_trailer_t) - stream->mki_size)); + status = srtp_cipher_set_aad( + session_keys->rtcp_cipher, srtcp, + (srtcp_len - tag_len - sizeof(srtcp_trailer_t) - stream->mki_size)); if (status) { return (srtp_err_status_cipher_fail); } @@ -3802,34 +3814,41 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( /* * Process the sequence# as AAD */ - tseq = trailer; - status = srtp_cipher_set_aad(session_keys->rtcp_cipher, (uint8_t *)&tseq, - sizeof(srtcp_trailer_t)); + status = srtp_cipher_set_aad(session_keys->rtcp_cipher, (uint8_t *)&trailer, + sizeof(trailer)); if (status) { return (srtp_err_status_cipher_fail); } /* if we're decrypting, exor keystream into the message */ - if (enc_start) { - status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (*trailer_p & SRTCP_E_BYTE_BIT) { + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, + srtcp + enc_start, enc_octet_len, + rtcp + enc_start, &enc_octet_len); if (status) { return status; } } else { + /* if no encryption and not-inplace then need to copy rest of packet */ + if (rtcp != srtcp) { + memcpy(rtcp + enc_start, srtcp + enc_start, enc_octet_len); + } + /* * Still need to run the cipher to check the tag */ - tmp_len = tag_len; + tmp_len = 0; status = srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, - tmp_len, auth_tag, &tmp_len); + tag_len, NULL, &tmp_len); if (status) { return status; } } + *rtcp_len = srtcp_len; + /* decrease the packet length by the length of the auth tag and seq_num*/ - *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t) + stream->mki_size); + *rtcp_len -= (tag_len + sizeof(srtcp_trailer_t) + stream->mki_size); /* * verify that stream is for received traffic - this check will @@ -3887,28 +3906,15 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( return srtp_err_status_ok; } -srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, - const uint8_t *rtcp, - size_t rtcp_len, - uint8_t *srtcp, - size_t *srtcp_len, - size_t mki_index) -{ - if (*srtcp_len < rtcp_len) { - return srtp_err_status_bad_param; - } - memcpy(srtcp, rtcp, rtcp_len); - *srtcp_len = rtcp_len; - return srtp_protect_rtcp(ctx, srtcp, srtcp_len, mki_index); -} - srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, - uint8_t *rtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, size_t mki_index) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)rtcp; + size_t enc_start; /* pointer to start of encrypted portion */ uint8_t *auth_start; /* pointer to start of auth. portion */ uint8_t *trailer_p; /* pointer to start of trailer */ uint32_t trailer; /* trailer value */ @@ -3922,7 +3928,7 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, srtp_session_keys_t *session_keys = NULL; /* check the packet length - it must at least contain a full header */ - if (*pkt_octet_len < octets_in_rtcp_header) { + if (rtcp_len < octets_in_rtcp_header) { return srtp_err_status_bad_param; } @@ -3985,7 +3991,7 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, */ if (session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_128 || session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_256) { - return srtp_protect_rtcp_aead(stream, rtcp_hdr, pkt_octet_len, + return srtp_protect_rtcp_aead(stream, rtcp, rtcp_len, srtcp, srtcp_len, session_keys); } @@ -3993,30 +3999,38 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, tag_len = srtp_auth_get_tag_length(session_keys->rtcp_auth); /* - * set encryption start and encryption length - if we're not - * providing confidentiality, set enc_start to NULL + * set encryption start and encryption length */ - enc_start = rtcp_hdr + octets_in_rtcp_header; - enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; + enc_start = octets_in_rtcp_header; + enc_octet_len = rtcp_len - enc_start; + + /* check output length */ + if (*srtcp_len < + rtcp_len + sizeof(srtcp_trailer_t) + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not in place then need to copy rtcp header */ + if (rtcp != srtcp) { + memcpy(srtcp, rtcp, enc_start); + } /* all of the packet, except the header, gets encrypted */ /* * NOTE: hdr->length is not usable - it refers to only the first RTCP report * in the compound packet! */ - trailer_p = enc_start + enc_octet_len; + trailer_p = srtcp + enc_start + enc_octet_len; if (stream->rtcp_services & sec_serv_conf) { trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */ } else { - enc_start = NULL; - enc_octet_len = 0; /* 0 is network-order independant */ trailer = 0x00000000; /* set encrypt bit */ } if (stream->use_mki) { - srtp_inject_mki(rtcp_hdr + *pkt_octet_len + sizeof(srtcp_trailer_t), + srtp_inject_mki(srtcp + rtcp_len + sizeof(srtcp_trailer_t), session_keys, stream->mki_size); } @@ -4025,9 +4039,8 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, * (note that srtpc *always* provides authentication, unlike srtp) */ /* Note: This would need to change for optional mikey data */ - auth_start = rtcp_hdr; - auth_tag = - rtcp_hdr + *pkt_octet_len + sizeof(srtcp_trailer_t) + stream->mki_size; + auth_start = srtcp; + auth_tag = srtcp + rtcp_len + sizeof(srtcp_trailer_t) + stream->mki_size; /* * check sequence number for overruns, and copy it into the packet @@ -4094,12 +4107,16 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, } /* if we're encrypting, exor keystream into the message */ - if (enc_start) { - status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (stream->rtcp_services & sec_serv_conf) { + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, + rtcp + enc_start, enc_octet_len, + srtcp + enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } + } else if (rtcp != srtcp) { + /* if no encryption and not-inplace then need to copy rest of packet */ + memcpy(srtcp + enc_start, rtcp + enc_start, enc_octet_len); } /* initialize auth func context */ @@ -4112,50 +4129,38 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, * run auth func over packet (including trailer), and write the * result at auth_tag */ - status = - srtp_auth_compute(session_keys->rtcp_auth, auth_start, - (*pkt_octet_len) + sizeof(srtcp_trailer_t), auth_tag); + status = srtp_auth_compute(session_keys->rtcp_auth, auth_start, + rtcp_len + sizeof(srtcp_trailer_t), auth_tag); debug_print(mod_srtp, "srtcp auth tag: %s", srtp_octet_string_hex_string(auth_tag, tag_len)); if (status) { return srtp_err_status_auth_fail; } + *srtcp_len = enc_start + enc_octet_len; + /* increase the packet length by the length of the auth tag and seq_num*/ - *pkt_octet_len += (tag_len + sizeof(srtcp_trailer_t)); + *srtcp_len += (tag_len + sizeof(srtcp_trailer_t)); /* increase the packet by the mki_size */ - *pkt_octet_len += stream->mki_size; + *srtcp_len += stream->mki_size; return srtp_err_status_ok; } -srtp_err_status_t srtp_unprotect_rtcp2(srtp_t ctx, - const uint8_t *srtcp, - size_t srtcp_len, - uint8_t *rtcp, - size_t *rtcp_len) -{ - if (*rtcp_len < srtcp_len) { - // this is actually expected but for the tests this should not happen - return srtp_err_status_bad_param; - } - memcpy(rtcp, srtcp, srtcp_len); - *rtcp_len = srtcp_len; - return srtp_unprotect_rtcp(ctx, rtcp, rtcp_len); -} - srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, - uint8_t *srtcp_hdr, - size_t *pkt_octet_len) + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ - uint8_t *auth_start; /* pointer to start of auth. portion */ - uint8_t *trailer_p; /* pointer to start of trailer */ - uint32_t trailer; /* trailer value */ - size_t enc_octet_len = 0; /* number of octets in encrypted portion */ - uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)srtcp; + size_t enc_start; /* pointer to start of encrypted portion */ + const uint8_t *auth_start; /* pointer to start of auth. portion */ + const uint8_t *trailer_p; /* pointer to start of trailer */ + uint32_t trailer; /* trailer value */ + size_t enc_octet_len = 0; /* number of octets in encrypted portion */ + const uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ uint8_t tmp_tag[SRTP_MAX_TAG_LEN]; srtp_err_status_t status; size_t auth_len; @@ -4172,7 +4177,7 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, * know the tag length, but we at least want to know that it is * a positive value */ - if (*pkt_octet_len < octets_in_rtcp_header + sizeof(srtcp_trailer_t)) { + if (srtcp_len < octets_in_rtcp_header + sizeof(srtcp_trailer_t)) { return srtp_err_status_bad_param; } @@ -4200,7 +4205,7 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, /* * Determine if MKI is being used and what session keys should be used */ - status = srtp_get_session_keys_for_packet(stream, srtcp_hdr, *pkt_octet_len, + status = srtp_get_session_keys_for_packet(stream, srtcp, srtcp_len, &session_keys); if (status) { return status; @@ -4212,8 +4217,8 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, /* check the packet length - it must contain at least a full RTCP header, an auth tag (if applicable), and the SRTCP encrypted flag and 31-bit index value */ - if (*pkt_octet_len < octets_in_rtcp_header + tag_len + stream->mki_size + - sizeof(srtcp_trailer_t)) { + if (srtcp_len < octets_in_rtcp_header + sizeof(srtcp_trailer_t) + + stream->mki_size + tag_len) { return srtp_err_status_bad_param; } @@ -4223,8 +4228,8 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, */ if (session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_128 || session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_256) { - return srtp_unprotect_rtcp_aead(ctx, stream, srtcp_hdr, pkt_octet_len, - session_keys); + return srtp_unprotect_rtcp_aead(ctx, stream, srtcp, srtcp_len, rtcp, + rtcp_len, session_keys); } sec_serv_confidentiality = stream->rtcp_services == sec_serv_conf || @@ -4233,43 +4238,37 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, /* * set encryption start, encryption length, and trailer */ - enc_octet_len = - *pkt_octet_len - (octets_in_rtcp_header + tag_len + stream->mki_size + - sizeof(srtcp_trailer_t)); + enc_start = octets_in_rtcp_header; + enc_octet_len = srtcp_len - (octets_in_rtcp_header + tag_len + + stream->mki_size + sizeof(srtcp_trailer_t)); /* *index & E (encryption) bit follow normal data. hdr->len is the number of * words (32-bit) in the normal packet minus 1 */ /* This should point trailer to the word past the end of the normal data. */ /* This would need to be modified for optional mikey data */ - trailer_p = srtcp_hdr + *pkt_octet_len - + trailer_p = srtcp + srtcp_len - (tag_len + stream->mki_size + sizeof(srtcp_trailer_t)); memcpy(&trailer, trailer_p, sizeof(trailer)); - e_bit_in_packet = (*(trailer_p)&SRTCP_E_BYTE_BIT) == SRTCP_E_BYTE_BIT; + e_bit_in_packet = (*trailer_p & SRTCP_E_BYTE_BIT) == SRTCP_E_BYTE_BIT; if (e_bit_in_packet != sec_serv_confidentiality) { return srtp_err_status_cant_check; } - if (sec_serv_confidentiality) { - enc_start = srtcp_hdr + octets_in_rtcp_header; - } else { - enc_octet_len = 0; - enc_start = NULL; /* this indicates that there's no encryption */ - } /* * set the auth_start and auth_tag pointers to the proper locations * (note that srtcp *always* uses authentication, unlike srtp) */ - auth_start = srtcp_hdr; + auth_start = srtcp; /* * The location of the auth tag in the packet needs to know MKI * could be present. The data needed to calculate the Auth tag * must not include the MKI */ - auth_len = *pkt_octet_len - tag_len - stream->mki_size; - auth_tag = srtcp_hdr + auth_len + stream->mki_size; + auth_len = srtcp_len - tag_len - stream->mki_size; + auth_tag = srtcp + auth_len + stream->mki_size; /* * check the sequence number for replays @@ -4349,20 +4348,37 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, return srtp_err_status_auth_fail; } + /* check output length */ + if (*rtcp_len < + srtcp_len - sizeof(srtcp_trailer_t) - stream->mki_size - tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not inplace need to copy rtcp header */ + if (srtcp != rtcp) { + memcpy(rtcp, srtcp, enc_start); + } + /* if we're decrypting, exor keystream into the message */ - if (enc_start) { - status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, - enc_octet_len, enc_start, &enc_octet_len); + if (sec_serv_confidentiality) { + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, + srtcp + enc_start, enc_octet_len, + rtcp + enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } + } else if (srtcp != rtcp) { + /* if no encryption and not-inplace then need to copy rest of packet */ + memcpy(rtcp + enc_start, srtcp + enc_start, enc_octet_len); } + *rtcp_len = srtcp_len; + /* decrease the packet length by the length of the auth tag and seq_num */ - *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t)); + *rtcp_len -= (tag_len + sizeof(srtcp_trailer_t)); /* decrease the packet length by the length of the mki_size */ - *pkt_octet_len -= stream->mki_size; + *rtcp_len -= stream->mki_size; /* * verify that stream is for received traffic - this check will diff --git a/test/rtp.c b/test/rtp.c index ca8f6f879..0c965b0f8 100644 --- a/test/rtp.c +++ b/test/rtp.c @@ -62,7 +62,8 @@ ssize_t rtp_sendto(rtp_sender_t sender, const void *msg, size_t len) { size_t octets_sent; srtp_err_status_t stat; - size_t pkt_len = len + RTP_HEADER_LEN; + size_t msg_len = len + RTP_HEADER_LEN; + size_t pkt_len = RTP_HEADER_LEN + RTP_MAX_BUF_LEN; /* marshal data */ strncpy(sender->message.body, msg, len); @@ -74,8 +75,9 @@ ssize_t rtp_sendto(rtp_sender_t sender, const void *msg, size_t len) sender->message.header.ts = htonl(sender->message.header.ts); /* apply srtp */ - stat = srtp_protect(sender->srtp_ctx, (uint8_t *)&sender->message.header, - &pkt_len, 0); + stat = + srtp_protect(sender->srtp_ctx, (uint8_t *)&sender->message.header, + msg_len, (uint8_t *)&sender->message.header, &pkt_len, 0); if (stat) { #if PRINT_DEBUG fprintf(stderr, "error: srtp protection failed with code %d\n", stat); @@ -131,6 +133,7 @@ ssize_t rtp_recvfrom(rtp_receiver_t receiver, void *msg, size_t *len) /* apply srtp */ stat = srtp_unprotect(receiver->srtp_ctx, + (uint8_t *)&receiver->message.header, octets_recvd, (uint8_t *)&receiver->message.header, &octets_recvd); if (stat) { fprintf(stderr, "error: srtp unprotection failed with code %d%s\n", diff --git a/test/rtp_decoder.c b/test/rtp_decoder.c index 6a413b8b9..9e01966a4 100644 --- a/test/rtp_decoder.c +++ b/test/rtp_decoder.c @@ -776,7 +776,8 @@ void rtp_decoder_handle_pkt(u_char *arg, } status = - srtp_unprotect(dcdr->srtp_ctx, (uint8_t *)&message, &octets_recvd); + srtp_unprotect(dcdr->srtp_ctx, (uint8_t *)&message, octets_recvd, + (uint8_t *)&message, &octets_recvd); if (status) { dcdr->error_cnt++; return; @@ -784,6 +785,7 @@ void rtp_decoder_handle_pkt(u_char *arg, dcdr->rtp_cnt++; } else { status = srtp_unprotect_rtcp(dcdr->srtp_ctx, (uint8_t *)&message, + octets_recvd, (uint8_t *)&message, &octets_recvd); if (status) { dcdr->error_cnt++; diff --git a/test/srtp_driver.c b/test/srtp_driver.c index 5fc2d1d83..e1884b6af 100644 --- a/test/srtp_driver.c +++ b/test/srtp_driver.c @@ -120,10 +120,19 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, bool use_mki, size_t mki_index); +srtp_err_status_t srtp_test_io_lengths(const srtp_policy_t *policy, + bool test_extension_headers, + bool use_mki, + size_t mki_index); + srtp_err_status_t srtcp_test(const srtp_policy_t *policy, bool use_mki, size_t mki_index); +srtp_err_status_t srtcp_test_io_lengths(const srtp_policy_t *policy, + bool use_mki, + size_t mki_index); + srtp_err_status_t srtp_session_print_policy(srtp_t srtp); srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy); @@ -135,6 +144,25 @@ double mips_estimate(size_t num_trials, size_t *ignore); srtp_err_status_t srtp_stream_list_test(void); +const uint8_t rtp_test_packet_extension_header[12] = { + /* one-byte header */ + 0xbe, 0xde, + /* size */ + 0x00, 0x02, + /* id 1, length 1 (i.e. 2 bytes) */ + 0x11, + /* payload */ + 0xca, 0xfe, + /* padding */ + 0x00, + /* id 2, length 0 (i.e. 1 byte) */ + 0x20, + /* payload */ + 0xba, + /* padding */ + 0x00, 0x00 +}; + #define TEST_MKI_ID_SIZE 4 extern uint8_t test_key[46]; @@ -162,26 +190,61 @@ srtp_master_key_t *test_keys[2] = { bool use_srtp_not_in_place_io_api = false; +void overrun_check_prepare(uint8_t *buffer, size_t offset, size_t buffer_len) +{ + memset(buffer + offset, 0xff, buffer_len - offset); +} + +srtp_err_status_t call_srtp_protect2(srtp_ctx_t *ctx, + uint8_t *rtp, + size_t rtp_len, + size_t *srtp_len, + size_t mki_index) +{ + srtp_err_status_t status = srtp_err_status_fail; + if (use_srtp_not_in_place_io_api) { + uint8_t in_buf[4048]; + if (rtp_len > sizeof(in_buf)) { + printf("rtp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, rtp, rtp_len); + status = srtp_protect(ctx, in_buf, rtp_len, rtp, srtp_len, mki_index); + } else { + status = srtp_protect(ctx, rtp, rtp_len, rtp, srtp_len, mki_index); + } + return status; +} + srtp_err_status_t call_srtp_protect(srtp_ctx_t *ctx, uint8_t *rtp, size_t *rtp_len, size_t mki_index) +{ + // an assumption + size_t srtp_len = *rtp_len + SRTP_MAX_TRAILER_LEN; + srtp_err_status_t status = + call_srtp_protect2(ctx, rtp, *rtp_len, &srtp_len, mki_index); + *rtp_len = srtp_len; + return status; +} + +srtp_err_status_t call_srtp_unprotect2(srtp_ctx_t *ctx, + uint8_t *srtp, + size_t srtp_len, + size_t *rtp_len) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*rtp_len > sizeof(in_buf)) { - printf("rtp_len greater than in_buf"); + if (srtp_len > sizeof(in_buf)) { + printf("srtp_len greater than in_buf"); exit(1); } - memcpy(in_buf, rtp, *rtp_len); - // an assumption - size_t srtp_len = *rtp_len + SRTP_MAX_TRAILER_LEN; - status = - srtp_protect2(ctx, in_buf, *rtp_len, rtp, &srtp_len, mki_index); - *rtp_len = srtp_len; + memcpy(in_buf, srtp, srtp_len); + status = srtp_unprotect(ctx, in_buf, srtp_len, srtp, rtp_len); } else { - status = srtp_protect(ctx, rtp, rtp_len, mki_index); + status = srtp_unprotect(ctx, srtp, srtp_len, srtp, rtp_len); } return status; } @@ -189,18 +252,29 @@ srtp_err_status_t call_srtp_protect(srtp_ctx_t *ctx, srtp_err_status_t call_srtp_unprotect(srtp_ctx_t *ctx, uint8_t *srtp, size_t *srtp_len) +{ + return call_srtp_unprotect2(ctx, srtp, *srtp_len, srtp_len); +} + +srtp_err_status_t call_srtp_protect_rtcp2(srtp_ctx_t *ctx, + uint8_t *rtcp, + size_t rtcp_len, + size_t *srtcp_len, + size_t mki_index) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*srtp_len > sizeof(in_buf)) { - printf("srtp_len greater than in_buf"); + if (rtcp_len > sizeof(in_buf)) { + printf("rtcp_len greater than in_buf"); exit(1); } - memcpy(in_buf, srtp, *srtp_len); - status = srtp_unprotect2(ctx, in_buf, *srtp_len, srtp, srtp_len); + memcpy(in_buf, rtcp, rtcp_len); + status = srtp_protect_rtcp(ctx, in_buf, rtcp_len, rtcp, srtcp_len, + mki_index); } else { - status = srtp_unprotect(ctx, srtp, srtp_len); + status = + srtp_protect_rtcp(ctx, rtcp, rtcp_len, rtcp, srtcp_len, mki_index); } return status; } @@ -209,22 +283,31 @@ srtp_err_status_t call_srtp_protect_rtcp(srtp_ctx_t *ctx, uint8_t *rtcp, size_t *rtcp_len, size_t mki_index) +{ + // an assumption + size_t srtcp_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN; + srtp_err_status_t status = + call_srtp_protect_rtcp2(ctx, rtcp, *rtcp_len, &srtcp_len, mki_index); + *rtcp_len = srtcp_len; + return status; +} + +srtp_err_status_t call_srtp_unprotect_rtcp2(srtp_ctx_t *ctx, + uint8_t *srtcp, + size_t srtcp_len, + size_t *rtcp_len) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*rtcp_len > sizeof(in_buf)) { - printf("rtcp_len greater than in_buf"); + if (srtcp_len > sizeof(in_buf)) { + printf("srtcp_len greater than in_buf"); exit(1); } - memcpy(in_buf, rtcp, *rtcp_len); - // an assumption - size_t srtcp_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN; - status = srtp_protect_rtcp2(ctx, in_buf, *rtcp_len, rtcp, &srtcp_len, - mki_index); - *rtcp_len = srtcp_len; + memcpy(in_buf, srtcp, srtcp_len); + status = srtp_unprotect_rtcp(ctx, in_buf, srtcp_len, srtcp, rtcp_len); } else { - status = srtp_protect_rtcp(ctx, rtcp, rtcp_len, mki_index); + status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len, srtcp, rtcp_len); } return status; } @@ -233,20 +316,7 @@ srtp_err_status_t call_srtp_unprotect_rtcp(srtp_ctx_t *ctx, uint8_t *srtcp, size_t *srtcp_len) { - srtp_err_status_t status = srtp_err_status_fail; - if (use_srtp_not_in_place_io_api) { - uint8_t in_buf[4048]; - if (*srtcp_len > sizeof(in_buf)) { - printf("srtcp_len greater than in_buf"); - exit(1); - } - memcpy(in_buf, srtcp, *srtcp_len); - status = - srtp_unprotect_rtcp2(ctx, in_buf, *srtcp_len, srtcp, srtcp_len); - } else { - status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len); - } - return status; + return call_srtp_unprotect_rtcp2(ctx, srtcp, *srtcp_len, srtcp_len); } void usage(char *prog_name) @@ -432,6 +502,15 @@ int main(int argc, char *argv[]) exit(1); } + printf("testing srtp_protect and srtp_unprotect io lengths\n"); + if (srtp_test_io_lengths(*policy, false, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect and srtp_unprotect with encrypted " "extensions headers\n"); if (srtp_test(*policy, true, false, 0) == srtp_err_status_ok) { @@ -440,6 +519,17 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect and srtp_unprotect io lengths with " + "encrypted extension headers\n"); + if (srtp_test_io_lengths(*policy, true, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n"); if (srtcp_test(*policy, false, 0) == srtp_err_status_ok) { printf("passed\n\n"); @@ -447,6 +537,17 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp io " + "lengths\n"); + if (srtcp_test_io_lengths(*policy, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtp and srtp_unprotect_rtp with MKI " "index set to 0\n"); if (srtp_test(*policy, false, true, 0) == srtp_err_status_ok) { @@ -464,6 +565,16 @@ int main(int argc, char *argv[]) exit(1); } + printf("testing srtp_protect and srtp_unprotect io lengths with " + "MKI\n"); + if (srtp_test_io_lengths(*policy, false, true, 1) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI " "index set to 0\n"); if (srtcp_test(*policy, true, 0) == srtp_err_status_ok) { @@ -472,6 +583,7 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI " "index set to 1\n"); if (srtcp_test(*policy, true, 1) == srtp_err_status_ok) { @@ -480,6 +592,16 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp io " + "lengths with MKI\n"); + if (srtcp_test_io_lengths(*policy, true, 1) == srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + policy++; } @@ -819,6 +941,60 @@ int main(int argc, char *argv[]) return 0; } +uint8_t *create_rtp_test_packet(size_t payload_len, + uint32_t ssrc, + uint16_t seq, + uint32_t ts, + bool add_hdr_xtn, + size_t *rtp_len, + size_t *buffer_len) +{ + uint8_t *buffer; + srtp_hdr_t *hdr; + size_t bytes_in_hdr = 12; + + *rtp_len = payload_len + bytes_in_hdr; + + if (add_hdr_xtn) { + *rtp_len += sizeof(rtp_test_packet_extension_header); + } + + // allocate enough for max trailer and 4 byte overrun detection + *buffer_len = *rtp_len + SRTP_MAX_TRAILER_LEN + 4; + + buffer = (uint8_t *)malloc(*buffer_len); + if (!buffer) { + printf("rtp test packet allocation failed\n"); + exit(1); + } + + overrun_check_prepare(buffer, 0, *buffer_len); + + hdr = (srtp_hdr_t *)buffer; + hdr->version = 2; + hdr->p = 0; + hdr->x = add_hdr_xtn ? 1 : 0; + hdr->cc = 0; + hdr->m = 0; + hdr->pt = 0xf; + hdr->seq = htons(seq); + hdr->ts = htonl(ts); + hdr->ssrc = htonl(ssrc); + buffer += bytes_in_hdr; + + if (add_hdr_xtn) { + memcpy(buffer, rtp_test_packet_extension_header, + sizeof(rtp_test_packet_extension_header)); + buffer += sizeof(rtp_test_packet_extension_header); + } + + /* set RTP data to 0xab */ + memset(buffer, 0xab, payload_len); + buffer += payload_len; + + return buffer - *rtp_len; +} + /* * srtp_create_test_packet(len, ssrc) returns a pointer to a * (malloced) example RTP packet whose data field has the length given @@ -836,168 +1012,75 @@ uint8_t *srtp_create_test_packet(size_t pkt_octet_len, uint32_t ssrc, size_t *pkt_len) { - size_t i; - uint8_t *buffer; - srtp_hdr_t *hdr; - size_t bytes_in_hdr = 12; - - /* allocate memory for test packet */ - hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - SRTP_MAX_TRAILER_LEN + 4); - if (!hdr) { - return NULL; - } - - hdr->version = 2; /* RTP version two */ - hdr->p = 0; /* no padding needed */ - hdr->x = 0; /* no header extension */ - hdr->cc = 0; /* no CSRCs */ - hdr->m = 0; /* marker bit */ - hdr->pt = 0xf; /* payload type */ - hdr->seq = htons(0x1234); /* sequence number */ - hdr->ts = htonl(0xdecafbad); /* timestamp */ - hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; - buffer += bytes_in_hdr; - - /* set RTP data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } - - *pkt_len = bytes_in_hdr + pkt_octet_len; - - return (uint8_t *)hdr; + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, 0x1234, 0x87654321, + false, pkt_len, &buffer_len); } -uint8_t *srtp_create_rtcp_test_packet(size_t pkt_octet_len, - uint32_t ssrc, - size_t *pkt_len) +uint8_t *create_rtcp_test_packet(size_t payload_len, + uint32_t ssrc, + size_t *rtcp_len, + size_t *buffer_len) { - size_t i; uint8_t *buffer; srtcp_hdr_t *hdr; size_t bytes_in_hdr = 8; - /* allocate memory for test packet */ - hdr = (srtcp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - SRTP_MAX_SRTCP_TRAILER_LEN + 4); - if (!hdr) { - return NULL; + *rtcp_len = payload_len + bytes_in_hdr; + + // allocate enough for max trailer and 4 byte overrun detection + *buffer_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN + 4; + + buffer = (uint8_t *)malloc(*buffer_len); + if (!buffer) { + printf("rtcp test packet allocation failed\n"); + exit(1); } + overrun_check_prepare(buffer, 0, *buffer_len); + + hdr = (srtcp_hdr_t *)buffer; hdr->version = 2; /* RTP version two */ hdr->p = 0; /* no padding needed */ hdr->rc = 0; /* no reports */ hdr->pt = 0xc8; /* sender report (200) */ - hdr->len = ((bytes_in_hdr + pkt_octet_len) % 4) - 1; + hdr->len = ((bytes_in_hdr + payload_len) % 4) - 1; hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; buffer += bytes_in_hdr; /* set data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_SRTCP_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } + memset(buffer, 0xab, payload_len); + buffer += payload_len; - *pkt_len = bytes_in_hdr + pkt_octet_len; - - return (uint8_t *)hdr; + return buffer - *rtcp_len; } -static uint8_t *srtp_create_test_packet_extended(size_t pkt_octet_len, - uint32_t ssrc, - uint16_t seq, - uint32_t ts, - size_t *pkt_len) +uint8_t *srtp_create_rtcp_test_packet(size_t pkt_octet_len, + uint32_t ssrc, + size_t *pkt_len) { - srtp_hdr_t *hdr; - - hdr = (srtp_hdr_t *)srtp_create_test_packet(pkt_octet_len, ssrc, pkt_len); - if (hdr == NULL) { - return NULL; - } + size_t buffer_len; + return create_rtcp_test_packet(pkt_octet_len, ssrc, pkt_len, &buffer_len); +} - hdr->seq = htons(seq); - hdr->ts = htonl(ts); - return (uint8_t *)hdr; +uint8_t *srtp_create_test_packet_extended(size_t pkt_octet_len, + uint32_t ssrc, + uint16_t seq, + uint32_t ts, + size_t *pkt_len) +{ + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, seq, ts, false, pkt_len, + &buffer_len); } uint8_t *srtp_create_test_packet_ext_hdr(size_t pkt_octet_len, uint32_t ssrc, size_t *pkt_len) { - size_t i; - uint8_t *buffer; - srtp_hdr_t *hdr; - size_t bytes_in_hdr = 12; - uint8_t extension_header[12] = { /* one-byte header */ - 0xbe, 0xde, - /* size */ - 0x00, 0x02, - /* id 1, length 1 (i.e. 2 bytes) */ - 0x11, - /* payload */ - 0xca, 0xfe, - /* padding */ - 0x00, - /* id 2, length 0 (i.e. 1 byte) */ - 0x20, - /* payload */ - 0xba, - /* padding */ - 0x00, 0x00 - }; - - /* allocate memory for test packet */ - hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - sizeof(extension_header) + SRTP_MAX_TRAILER_LEN + - 4); - if (!hdr) { - return NULL; - } - - hdr->version = 2; /* RTP version two */ - hdr->p = 0; /* no padding needed */ - hdr->x = 1; /* no header extension */ - hdr->cc = 0; /* no CSRCs */ - hdr->m = 0; /* marker bit */ - hdr->pt = 0xf; /* payload type */ - hdr->seq = htons(0x1234); /* sequence number */ - hdr->ts = htonl(0xdecafbad); /* timestamp */ - hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; - buffer += bytes_in_hdr; - - memcpy(buffer, extension_header, sizeof(extension_header)); - buffer += sizeof(extension_header); - - /* set RTP data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } - - *pkt_len = bytes_in_hdr + sizeof(extension_header) + pkt_octet_len; - - return (uint8_t *)hdr; + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, 0x1234, 0x87654321, true, + pkt_len, &buffer_len); } void srtp_do_timing(const srtp_policy_t *policy) @@ -1164,6 +1247,82 @@ void err_check(srtp_err_status_t s) } } +void check_ok(srtp_err_status_t s, const char *msg) +{ + if (s != srtp_err_status_ok) { + fprintf(stderr, "error: unexpected srtp failure (code %d) - %s\n", s, + msg); + exit(1); + } +} + +void check_return(srtp_err_status_t actual, + srtp_err_status_t expected, + const char *msg) +{ + if (actual != expected) { + fprintf(stderr, "error: unexpected srtp status (code %d != %d) - %s\n", + actual, expected, msg); + exit(1); + } +} + +void check_ok_impl(srtp_err_status_t status, const char *file, int line) +{ + if (status != srtp_err_status_ok) { + fprintf(stderr, "error at %s:%d, unexpected srtp failure (code %d)\n", + file, line, status); + exit(1); + } +} + +void check_return_impl(srtp_err_status_t status, + srtp_err_status_t expected, + const char *file, + int line) +{ + if (status != expected) { + fprintf(stderr, + "error at %s:%d, unexpected srtp status (code %d != %d)\n", + file, line, status, expected); + exit(1); + } +} + +void check_impl(bool condition, + const char *file, + int line, + const char *condition_str) +{ + if (!condition) { + fprintf(stderr, "error at %s:%d, %s)\n", file, line, condition_str); + exit(1); + } +} + +void check_overrun_impl(const uint8_t *buffer, + size_t offset, + size_t buffer_length, + const char *file, + int line) +{ + for (size_t i = offset; i < buffer_length; i++) { + if (buffer[i] != 0xff) { + printf("error at %s:%d, overrun detected in buffer at index %zu " + "(expected %x, found %x)\n", + file, line, i, 0xff, buffer[i]); + exit(1); + } + } +} + +#define CHECK_OK(status) check_ok_impl((status), __FILE__, __LINE__) +#define CHECK_RETURN(status, expected) \ + check_return_impl((status), (expected), __FILE__, __LINE__) +#define CHECK(condition) check_impl((condition), __FILE__, __LINE__, #condition) +#define CHECK_OVERRUN(buffer, offset, length) \ + check_overrun_impl((buffer), (offset), (length), __FILE__, __LINE__) + srtp_err_status_t srtp_test(const srtp_policy_t *policy, bool test_extension_headers, bool use_mki, @@ -1374,6 +1533,211 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, return srtp_err_status_ok; } +srtp_err_status_t srtp_test_io_lengths(const srtp_policy_t *policy, + bool test_extension_headers, + bool use_mki, + size_t mki_index) +{ + srtp_t srtp_sender; + srtp_policy_t send_policy; + uint32_t ssrc; + uint16_t seq = 1; + uint32_t ts = 1234; + uint8_t *rtp; + size_t rtp_len, buffer_len, srtp_len; + size_t rtp_header_len = 12; + uint8_t xtn_header_id = 1; + + memcpy(&send_policy, policy, sizeof(srtp_policy_t)); + + send_policy.use_mki = use_mki; + if (!use_mki) { + send_policy.mki_size = 0; + } + + if (test_extension_headers) { + send_policy.enc_xtn_hdr = &xtn_header_id; + send_policy.enc_xtn_hdr_count = 1; + rtp_header_len += sizeof(rtp_test_packet_extension_header); + } + + CHECK_OK(srtp_create(&srtp_sender, &send_policy)); + + // get required trailer length + size_t trailer_len; + CHECK_OK( + srtp_get_protect_trailer_length(srtp_sender, mki_index, &trailer_len)); + + CHECK_OK(srtp_session_print_policy(srtp_sender)); + + if (policy->ssrc.type != ssrc_specific) { + ssrc = 0xdecafbad; + } else { + ssrc = policy->ssrc.value; + } + + // 0 byte input + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, 0, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, 0, &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, 0, buffer_len); + free(rtp); + + // 1 byte input + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, 1, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, 1, &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, 1, buffer_len); + free(rtp); + + // too short header + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len - 1, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, rtp_header_len - 1, + &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, rtp_header_len - 1, buffer_len); + free(rtp); + + // zero payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len, buffer_len); + CHECK_OK(call_srtp_protect2(srtp_sender, rtp, rtp_header_len, &srtp_len, + mki_index)); + CHECK(srtp_len == rtp_header_len + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + free(rtp); + + // 1 byte payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len + 1, buffer_len); + CHECK_OK(call_srtp_protect2(srtp_sender, rtp, rtp_header_len + 1, &srtp_len, + mki_index)); + CHECK(srtp_len == rtp_header_len + 1 + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + free(rtp); + + // 0 byte output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = 0; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + // 1 byte output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = 1; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + if (trailer_len != 0) { + // no space for trailer output + rtp = create_rtp_test_packet( + 28, ssrc, seq++, ts, test_extension_headers, &rtp_len, &buffer_len); + srtp_len = rtp_len; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + } + + // 1 byte too small output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = rtp_len + trailer_len - 1; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + // full payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + CHECK_OK( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index)); + CHECK(srtp_len == rtp_len + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + + CHECK_OK(srtp_dealloc(srtp_sender)); + + // unprotect + srtp_t srtp_receiver; + srtp_policy_t receive_policy; + + memcpy(&receive_policy, &send_policy, sizeof(srtp_policy_t)); + receive_policy.ssrc.type = ssrc_any_inbound; + + CHECK_OK(srtp_create(&srtp_receiver, &receive_policy)); + + // unprotect zero byte input + rtp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, 0, &rtp_len), + srtp_err_status_bad_param); + + // unprotect 1 byte input + rtp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, 1, &rtp_len), + srtp_err_status_bad_param); + + // unprotect short header + rtp_len = buffer_len; + CHECK_RETURN( + call_srtp_unprotect2(srtp_receiver, rtp, rtp_header_len - 1, &rtp_len), + srtp_err_status_bad_param); + + // 0 byte output + rtp_len = 0; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // 1 byte output + rtp_len = 1; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // 1 byte too small output + rtp_len = srtp_len - trailer_len - 1; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // full unprotect + rtp_len = buffer_len; + CHECK_OK(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len)); + CHECK(rtp_len == srtp_len - trailer_len); + + free(rtp); + + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} + srtp_err_status_t srtcp_test(const srtp_policy_t *policy, bool use_mki, size_t mki_index) @@ -1567,6 +1931,197 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, return srtp_err_status_ok; } +srtp_err_status_t srtcp_test_io_lengths(const srtp_policy_t *policy, + bool use_mki, + size_t mki_index) +{ + srtp_t srtp_sender; + srtp_policy_t send_policy; + uint32_t ssrc; + uint8_t *rtcp; + size_t rtcp_len, buffer_len, srtcp_len; + size_t rtcp_header_len = 8; + + memcpy(&send_policy, policy, sizeof(srtp_policy_t)); + + send_policy.use_mki = use_mki; + if (!use_mki) { + send_policy.mki_size = 0; + } + + CHECK_OK(srtp_create(&srtp_sender, &send_policy)); + + // get required trailer length + size_t trailer_len; + CHECK_OK(srtp_get_protect_rtcp_trailer_length(srtp_sender, mki_index, + &trailer_len)); + + CHECK_OK(srtp_session_print_policy(srtp_sender)); + + if (policy->ssrc.type != ssrc_specific) { + ssrc = 0xdecafbad; + } else { + ssrc = policy->ssrc.value; + } + + // 0 byte input + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, 0, buffer_len); + CHECK_RETURN( + call_srtp_protect_rtcp2(srtp_sender, rtcp, 0, &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, 0, buffer_len); + free(rtcp); + + // 1 byte input + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, 1, buffer_len); + CHECK_RETURN( + call_srtp_protect_rtcp2(srtp_sender, rtcp, 1, &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, 1, buffer_len); + free(rtcp); + + // too short header + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len - 1, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len - 1, + &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, rtcp_header_len - 1, buffer_len); + free(rtcp); + + // zero payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len, buffer_len); + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len, + &srtcp_len, mki_index)); + CHECK(srtcp_len == rtcp_header_len + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + free(rtcp); + + // 1 byte payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len + 1, buffer_len); + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len + 1, + &srtcp_len, mki_index)); + CHECK(srtcp_len == rtcp_header_len + 1 + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + free(rtcp); + + // 0 byte output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = 0; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + // 1 byte output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = 1; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + if (trailer_len != 0) { + // no space for trailer output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = rtcp_len; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + } + + // 1 byte too small output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = rtcp_len + trailer_len - 1; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + // full payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, &srtcp_len, + mki_index)); + CHECK(srtcp_len == rtcp_len + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + + CHECK_OK(srtp_dealloc(srtp_sender)); + + // unprotect + srtp_t srtp_receiver; + srtp_policy_t receive_policy; + + memcpy(&receive_policy, &send_policy, sizeof(srtp_policy_t)); + receive_policy.ssrc.type = ssrc_any_inbound; + + CHECK_OK(srtp_create(&srtp_receiver, &receive_policy)); + + // unprotect zero byte input + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, 0, &rtcp_len), + srtp_err_status_bad_param); + + // unprotect 1 byte input + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, 1, &rtcp_len), + srtp_err_status_bad_param); + + // unprotect short header + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, + rtcp_header_len - 1, &rtcp_len), + srtp_err_status_bad_param); + + // 0 byte output + rtcp_len = 0; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // 1 byte output + rtcp_len = 1; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // 1 byte too small output + rtcp_len = srtcp_len - trailer_len - 1; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // full unprotect + rtcp_len = buffer_len; + CHECK_OK( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len)); + CHECK(rtcp_len == srtcp_len - trailer_len); + + free(rtcp); + + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} + struct srtp_session_print_stream_data { // set by callback to indicate failure srtp_err_status_t status;