diff --git a/CMakeLists.txt b/CMakeLists.txt index fdf98c26c..696262f65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,6 +458,7 @@ if(LIBSRTP_TEST_APPS) ${ENABLE_WARNINGS_AS_ERRORS}) target_link_libraries(srtp_driver srtp2) add_test(srtp_driver srtp_driver -v) + add_test(srtp_driver_not_in_place_io srtp_driver -v -n) if(NOT (BUILD_SHARED_LIBS AND WIN32)) add_executable(test_srtp test/test_srtp.c) diff --git a/README.md b/README.md index e33693516..f770ec5e8 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ described in [RFC 7714](https://tools.ietf.org/html/rfc7714) supports AES-128 & AES-256, so to use AES-192 or the AES-GCM group of ciphers a 3rd party crypto backend must be configured. For this and performance reasons it is highly recommended to use a 3rd party crypto backend. - + * The `srtp_protect()` function assumes that the buffer holding the rtp packet has enough storage allocated that the authentication tag can be written to the end of that packet. If this assumption @@ -503,11 +503,13 @@ srtp_create(&session, &policy); // main loop: get rtp packets, send srtp packets while (1) { char rtp_buffer[2048]; - size_t len; + size_t rtp_len; + char srtp_buffer[2048]; + size_t srtp_len = sizeof(srtp_buffer); len = get_rtp_packet(rtp_buffer); - srtp_protect(session, rtp_buffer, &len); - send_srtp_packet(rtp_buffer, len); + srtp_protect(session, rtp_buffer, rtp_len, srtp_buffer, &srtp_len); + send_srtp_packet(srtp_buffer, srtp_len); } ~~~ diff --git a/crypto/cipher/aes_gcm_mbedtls.c b/crypto/cipher/aes_gcm_mbedtls.c index 2965d202e..5b190963b 100644 --- a/crypto/cipher/aes_gcm_mbedtls.c +++ b/crypto/cipher/aes_gcm_mbedtls.c @@ -281,8 +281,10 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_set_aad(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_mbedtls_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { FUNC_ENTRY(); srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; @@ -292,9 +294,13 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_encrypt(void *cv, return (srtp_err_status_bad_param); } - errCode = mbedtls_gcm_crypt_and_tag(c->ctx, MBEDTLS_GCM_ENCRYPT, *enc_len, + if (*dst_len < src_len) { + return srtp_err_status_buffer_small; + } + + errCode = mbedtls_gcm_crypt_and_tag(c->ctx, MBEDTLS_GCM_ENCRYPT, src_len, c->iv, c->iv_len, c->aad, c->aad_size, - buf, buf, c->tag_len, c->tag); + src, dst, c->tag_len, c->tag); c->aad_size = 0; if (errCode != 0) { @@ -302,6 +308,8 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_encrypt(void *cv, return srtp_err_status_bad_param; } + *dst_len = src_len; + return (srtp_err_status_ok); } @@ -337,8 +345,10 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_get_tag(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_mbedtls_decrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { FUNC_ENTRY(); srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; @@ -348,12 +358,16 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_decrypt(void *cv, return (srtp_err_status_bad_param); } + if (*dst_len < (src_len - c->tag_len)) { + return srtp_err_status_buffer_small; + } + debug_print(srtp_mod_aes_gcm, "AAD: %s", srtp_octet_string_hex_string(c->aad, c->aad_size)); errCode = mbedtls_gcm_auth_decrypt( - c->ctx, (*enc_len - c->tag_len), c->iv, c->iv_len, c->aad, c->aad_size, - buf + (*enc_len - c->tag_len), c->tag_len, buf, buf); + c->ctx, (src_len - c->tag_len), c->iv, c->iv_len, c->aad, c->aad_size, + src + (src_len - c->tag_len), c->tag_len, src, dst); c->aad_size = 0; if (errCode != 0) { return (srtp_err_status_auth_fail); @@ -363,7 +377,7 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_decrypt(void *cv, * Reduce the buffer size by the tag length since the tag * is not part of the original payload */ - *enc_len -= c->tag_len; + *dst_len = (src_len - c->tag_len); return (srtp_err_status_ok); } diff --git a/crypto/cipher/aes_gcm_nss.c b/crypto/cipher/aes_gcm_nss.c index 7f514f54d..db17b918b 100644 --- a/crypto/cipher/aes_gcm_nss.c +++ b/crypto/cipher/aes_gcm_nss.c @@ -281,8 +281,10 @@ static srtp_err_status_t srtp_aes_gcm_nss_set_aad(void *cv, static srtp_err_status_t srtp_aes_gcm_nss_do_crypto(void *cv, bool encrypt, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; @@ -299,13 +301,13 @@ static srtp_err_status_t srtp_aes_gcm_nss_do_crypto(void *cv, SECItem param = { siBuffer, (unsigned char *)&c->params, sizeof(CK_GCM_PARAMS) }; if (encrypt) { - rv = PK11_Encrypt(c->key, CKM_AES_GCM, ¶m, buf, &out_len, - *enc_len + 16, buf, *enc_len); + rv = PK11_Encrypt(c->key, CKM_AES_GCM, ¶m, dst, &out_len, *dst_len, + src, src_len); } else { - rv = PK11_Decrypt(c->key, CKM_AES_GCM, ¶m, buf, &out_len, *enc_len, - buf, *enc_len); + rv = PK11_Decrypt(c->key, CKM_AES_GCM, ¶m, dst, &out_len, *dst_len, + src, src_len); } - *enc_len = out_len; + *dst_len = out_len; srtp_err_status_t status = (srtp_err_status_ok); if (rv != SECSuccess) { status = (srtp_err_status_cipher_fail); @@ -328,32 +330,41 @@ static srtp_err_status_t srtp_aes_gcm_nss_do_crypto(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_nss_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; - // When we get a non-NULL buffer, we know that the caller is - // prepared to also take the tag. When we get a NULL buffer, + // When we get a non-NULL src buffer, we know that the caller is + // prepared to also take the tag. When we get a NULL src buffer, // even though there's no data, we need to give NSS a buffer // where it can write the tag. We can't just use c->tag because // memcpy has undefined behavior on overlapping ranges. uint8_t tagbuf[16]; - uint8_t *non_null_buf = buf; - if (!non_null_buf && (*enc_len == 0)) { + const uint8_t *non_null_buf = src; + uint8_t *non_null_dst_buf = dst; + if (!non_null_buf && (src_len == 0)) { non_null_buf = tagbuf; + non_null_dst_buf = tagbuf; + *dst_len = sizeof(tagbuf); } else if (!non_null_buf) { return srtp_err_status_bad_param; } - srtp_err_status_t status = - srtp_aes_gcm_nss_do_crypto(cv, true, non_null_buf, enc_len); + srtp_err_status_t status = srtp_aes_gcm_nss_do_crypto( + cv, true, non_null_buf, src_len, non_null_dst_buf, dst_len); if (status != srtp_err_status_ok) { return status; } - memcpy(c->tag, non_null_buf + (*enc_len - c->tag_size), c->tag_size); - *enc_len -= c->tag_size; + if (*dst_len < c->tag_size) { + return srtp_err_status_bad_param; + } + + memcpy(c->tag, non_null_dst_buf + (*dst_len - c->tag_size), c->tag_size); + *dst_len -= c->tag_size; return srtp_err_status_ok; } @@ -387,11 +398,22 @@ static srtp_err_status_t srtp_aes_gcm_nss_get_tag(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_nss_decrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { - srtp_err_status_t status = - srtp_aes_gcm_nss_do_crypto(cv, false, buf, enc_len); + uint8_t tagbuf[16]; + uint8_t *non_null_dst_buf = dst; + if (!non_null_dst_buf && (*dst_len == 0)) { + non_null_dst_buf = tagbuf; + *dst_len = sizeof(tagbuf); + } else if (!non_null_dst_buf) { + return srtp_err_status_bad_param; + } + + srtp_err_status_t status = srtp_aes_gcm_nss_do_crypto( + cv, false, src, src_len, non_null_dst_buf, dst_len); if (status != srtp_err_status_ok) { int err = PR_GetError(); if (err == SEC_ERROR_BAD_DATA) { diff --git a/crypto/cipher/aes_gcm_ossl.c b/crypto/cipher/aes_gcm_ossl.c index 6a56450db..692ab8957 100644 --- a/crypto/cipher/aes_gcm_ossl.c +++ b/crypto/cipher/aes_gcm_ossl.c @@ -293,8 +293,10 @@ static srtp_err_status_t srtp_aes_gcm_openssl_set_aad(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_openssl_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; if (c->dir != srtp_direction_encrypt && c->dir != srtp_direction_decrypt) { @@ -304,7 +306,8 @@ static srtp_err_status_t srtp_aes_gcm_openssl_encrypt(void *cv, /* * Encrypt the data */ - EVP_Cipher(c->ctx, buf, buf, *enc_len); + EVP_Cipher(c->ctx, dst, src, src_len); + *dst_len = src_len; return (srtp_err_status_ok); } @@ -354,8 +357,10 @@ static srtp_err_status_t srtp_aes_gcm_openssl_get_tag(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_openssl_decrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; if (c->dir != srtp_direction_encrypt && c->dir != srtp_direction_decrypt) { @@ -364,12 +369,15 @@ static srtp_err_status_t srtp_aes_gcm_openssl_decrypt(void *cv, /* * Set the tag before decrypting + * + * explicitly cast away const of src */ - if (!EVP_CIPHER_CTX_ctrl(c->ctx, EVP_CTRL_GCM_SET_TAG, c->tag_len, - buf + (*enc_len - c->tag_len))) { + if (!EVP_CIPHER_CTX_ctrl( + c->ctx, EVP_CTRL_GCM_SET_TAG, c->tag_len, + (void *)(uintptr_t)(src + (src_len - c->tag_len)))) { return (srtp_err_status_auth_fail); } - EVP_Cipher(c->ctx, buf, buf, *enc_len - c->tag_len); + EVP_Cipher(c->ctx, dst, src, src_len - c->tag_len); /* * Check the tag @@ -382,7 +390,7 @@ static srtp_err_status_t srtp_aes_gcm_openssl_decrypt(void *cv, * Reduce the buffer size by the tag length since the tag * is not part of the original payload */ - *enc_len -= c->tag_len; + *dst_len = src_len -= c->tag_len; return (srtp_err_status_ok); } diff --git a/crypto/cipher/aes_gcm_wssl.c b/crypto/cipher/aes_gcm_wssl.c index fcb857f57..85819791e 100644 --- a/crypto/cipher/aes_gcm_wssl.c +++ b/crypto/cipher/aes_gcm_wssl.c @@ -321,8 +321,10 @@ static srtp_err_status_t srtp_aes_gcm_wolfssl_set_aad(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_wolfssl_encrypt(void *cv, - unsigned char *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { FUNC_ENTRY(); srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; @@ -333,17 +335,18 @@ static srtp_err_status_t srtp_aes_gcm_wolfssl_encrypt(void *cv, } #ifndef WOLFSSL_AESGCM_STREAM - err = wc_AesGcmEncrypt(c->ctx, buf, buf, *enc_len, c->iv, c->iv_len, c->tag, + err = wc_AesGcmEncrypt(c->ctx, dst, src, src_len, c->iv, c->iv_len, c->tag, c->tag_len, c->aad, c->aad_size); c->aad_size = 0; #else - err = wc_AesGcmEncryptUpdate(c->ctx, buf, buf, *enc_len, NULL, 0); + err = wc_AesGcmEncryptUpdate(c->ctx, dst, src, src_len, NULL, 0); #endif if (err < 0) { debug_print(srtp_mod_aes_gcm, "wolfSSL error code: %d", err); return srtp_err_status_bad_param; } + *dst_len = src_len; return (srtp_err_status_ok); } @@ -392,8 +395,10 @@ static srtp_err_status_t srtp_aes_gcm_wolfssl_get_tag(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_gcm_wolfssl_decrypt(void *cv, - unsigned char *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { FUNC_ENTRY(); srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; @@ -407,19 +412,19 @@ static srtp_err_status_t srtp_aes_gcm_wolfssl_decrypt(void *cv, debug_print(srtp_mod_aes_gcm, "AAD: %s", srtp_octet_string_hex_string(c->aad, c->aad_size)); - err = wc_AesGcmDecrypt(c->ctx, buf, buf, (*enc_len - c->tag_len), c->iv, - c->iv_len, buf + (*enc_len - c->tag_len), c->tag_len, + err = wc_AesGcmDecrypt(c->ctx, dst, src, (src_len - c->tag_len), c->iv, + c->iv_len, src + (src_len - c->tag_len), c->tag_len, c->aad, c->aad_size); c->aad_size = 0; #else - err = wc_AesGcmDecryptUpdate(c->ctx, buf, buf, (*enc_len - c->tag_len), - NULL, 0); + err = wc_AesGcmDecryptUpdate(c->ctx, dst, src, (src_len - c->tag_len), NULL, + 0); if (err < 0) { debug_print(srtp_mod_aes_gcm, "wolfSSL error code: %d", err); return (srtp_err_status_algo_fail); } - err = wc_AesGcmDecryptFinal(c->ctx, buf + (*enc_len - c->tag_len), - c->tag_len); + err = + wc_AesGcmDecryptFinal(c->ctx, src + (src_len - c->tag_len), c->tag_len); #endif if (err < 0) { debug_print(srtp_mod_aes_gcm, "wolfSSL error code: %d", err); @@ -430,7 +435,7 @@ static srtp_err_status_t srtp_aes_gcm_wolfssl_decrypt(void *cv, * Reduce the buffer size by the tag length since the tag * is not part of the original payload */ - *enc_len -= c->tag_len; + *dst_len = src_len -= c->tag_len; return (srtp_err_status_ok); } diff --git a/crypto/cipher/aes_icm.c b/crypto/cipher/aes_icm.c index 744df6aae..fea79f019 100644 --- a/crypto/cipher/aes_icm.c +++ b/crypto/cipher/aes_icm.c @@ -295,12 +295,23 @@ static void srtp_aes_icm_advance(srtp_aes_icm_ctx_t *c) */ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; - size_t bytes_to_encr = *enc_len; + size_t bytes_to_encr = src_len; uint32_t *b; + const uint32_t *s; + + if (*dst_len < src_len) { + return srtp_err_status_buffer_small; + } + + *dst_len = src_len; + + unsigned char *buf = dst; /* check that there's enough segment left*/ size_t bytes_of_new_keystream = bytes_to_encr - c->bytes_in_buffer; @@ -314,7 +325,7 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, /* deal with odd case of small bytes_to_encr */ for (size_t i = (sizeof(v128_t) - c->bytes_in_buffer); i < (sizeof(v128_t) - c->bytes_in_buffer + bytes_to_encr); i++) { - *buf++ ^= c->keystream_buffer.v8[i]; + *buf++ = *src++ ^ c->keystream_buffer.v8[i]; } c->bytes_in_buffer -= bytes_to_encr; @@ -326,7 +337,7 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, /* encrypt bytes until the remaining data is 16-byte aligned */ for (size_t i = (sizeof(v128_t) - c->bytes_in_buffer); i < sizeof(v128_t); i++) { - *buf++ ^= c->keystream_buffer.v8[i]; + *buf++ = *src++ ^ c->keystream_buffer.v8[i]; } bytes_to_encr -= c->bytes_in_buffer; @@ -345,36 +356,40 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, #if ALIGN_32 b = (uint32_t *)buf; - *b++ ^= c->keystream_buffer.v32[0]; - *b++ ^= c->keystream_buffer.v32[1]; - *b++ ^= c->keystream_buffer.v32[2]; - *b++ ^= c->keystream_buffer.v32[3]; + s = (const uint32_t *)src; + *b++ = *s++ ^ c->keystream_buffer.v32[0]; + *b++ = *s++ ^ c->keystream_buffer.v32[1]; + *b++ = *s++ ^ c->keystream_buffer.v32[2]; + *b++ = *s++ ^ c->keystream_buffer.v32[3]; buf = (uint8_t *)b; + src = (const uint8_t *)s; #else if ((((uintptr_t)buf) & 0x03) != 0) { - *buf++ ^= c->keystream_buffer.v8[0]; - *buf++ ^= c->keystream_buffer.v8[1]; - *buf++ ^= c->keystream_buffer.v8[2]; - *buf++ ^= c->keystream_buffer.v8[3]; - *buf++ ^= c->keystream_buffer.v8[4]; - *buf++ ^= c->keystream_buffer.v8[5]; - *buf++ ^= c->keystream_buffer.v8[6]; - *buf++ ^= c->keystream_buffer.v8[7]; - *buf++ ^= c->keystream_buffer.v8[8]; - *buf++ ^= c->keystream_buffer.v8[9]; - *buf++ ^= c->keystream_buffer.v8[10]; - *buf++ ^= c->keystream_buffer.v8[11]; - *buf++ ^= c->keystream_buffer.v8[12]; - *buf++ ^= c->keystream_buffer.v8[13]; - *buf++ ^= c->keystream_buffer.v8[14]; - *buf++ ^= c->keystream_buffer.v8[15]; + *buf++ = *src++ ^ c->keystream_buffer.v8[0]; + *buf++ = *src++ ^ c->keystream_buffer.v8[1]; + *buf++ = *src++ ^ c->keystream_buffer.v8[2]; + *buf++ = *src++ ^ c->keystream_buffer.v8[3]; + *buf++ = *src++ ^ c->keystream_buffer.v8[4]; + *buf++ = *src++ ^ c->keystream_buffer.v8[5]; + *buf++ = *src++ ^ c->keystream_buffer.v8[6]; + *buf++ = *src++ ^ c->keystream_buffer.v8[7]; + *buf++ = *src++ ^ c->keystream_buffer.v8[8]; + *buf++ = *src++ ^ c->keystream_buffer.v8[9]; + *buf++ = *src++ ^ c->keystream_buffer.v8[10]; + *buf++ = *src++ ^ c->keystream_buffer.v8[11]; + *buf++ = *src++ ^ c->keystream_buffer.v8[12]; + *buf++ = *src++ ^ c->keystream_buffer.v8[13]; + *buf++ = *src++ ^ c->keystream_buffer.v8[14]; + *buf++ = *src++ ^ c->keystream_buffer.v8[15]; } else { b = (uint32_t *)buf; - *b++ ^= c->keystream_buffer.v32[0]; - *b++ ^= c->keystream_buffer.v32[1]; - *b++ ^= c->keystream_buffer.v32[2]; - *b++ ^= c->keystream_buffer.v32[3]; + s = (const uint32_t *)src; + *b++ = *s++ ^ c->keystream_buffer.v32[0]; + *b++ = *s++ ^ c->keystream_buffer.v32[1]; + *b++ = *s++ ^ c->keystream_buffer.v32[2]; + *b++ = *s++ ^ c->keystream_buffer.v32[3]; buf = (uint8_t *)b; + src = (const uint8_t *)s; } #endif /* #if ALIGN_32 */ } @@ -385,7 +400,7 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, srtp_aes_icm_advance(c); for (size_t i = 0; i < (bytes_to_encr & 0xf); i++) { - *buf++ ^= c->keystream_buffer.v8[i]; + *buf++ = *src++ ^ c->keystream_buffer.v8[i]; } /* reset the keystream buffer size to right value */ diff --git a/crypto/cipher/aes_icm_mbedtls.c b/crypto/cipher/aes_icm_mbedtls.c index 7cbde4d03..e2aa98968 100644 --- a/crypto/cipher/aes_icm_mbedtls.c +++ b/crypto/cipher/aes_icm_mbedtls.c @@ -290,22 +290,30 @@ static srtp_err_status_t srtp_aes_icm_mbedtls_set_iv( * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_icm_mbedtls_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; int errCode = 0; debug_print(srtp_mod_aes_icm, "rs0: %s", v128_hex_string(&c->counter)); + if (*dst_len < src_len) { + return srtp_err_status_buffer_small; + } + errCode = - mbedtls_aes_crypt_ctr(c->ctx, *enc_len, &(c->nc_off), c->counter.v8, - c->stream_block.v8, buf, buf); + mbedtls_aes_crypt_ctr(c->ctx, src_len, &(c->nc_off), c->counter.v8, + c->stream_block.v8, src, dst); if (errCode != 0) { debug_print(srtp_mod_aes_icm, "encrypt error: %d", errCode); return srtp_err_status_cipher_fail; } + *dst_len = src_len; + return srtp_err_status_ok; } diff --git a/crypto/cipher/aes_icm_nss.c b/crypto/cipher/aes_icm_nss.c index 0f9c883fd..25611bea9 100644 --- a/crypto/cipher/aes_icm_nss.c +++ b/crypto/cipher/aes_icm_nss.c @@ -323,8 +323,10 @@ static srtp_err_status_t srtp_aes_icm_nss_set_iv(void *cv, * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_icm_nss_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; @@ -333,8 +335,8 @@ static srtp_err_status_t srtp_aes_icm_nss_encrypt(void *cv, } int out_len = 0; - int rv = PK11_CipherOp(c->ctx, buf, &out_len, *enc_len, buf, *enc_len); - *enc_len = out_len; + int rv = PK11_CipherOp(c->ctx, dst, &out_len, *dst_len, src, src_len); + *dst_len = out_len; srtp_err_status_t status = (srtp_err_status_ok); if (rv != SECSuccess) { status = (srtp_err_status_cipher_fail); diff --git a/crypto/cipher/aes_icm_ossl.c b/crypto/cipher/aes_icm_ossl.c index 4319de5c6..287642d7a 100644 --- a/crypto/cipher/aes_icm_ossl.c +++ b/crypto/cipher/aes_icm_ossl.c @@ -298,23 +298,25 @@ static srtp_err_status_t srtp_aes_icm_openssl_set_iv( * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_icm_openssl_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; int len = 0; debug_print(srtp_mod_aes_icm, "rs0: %s", v128_hex_string(&c->counter)); - if (!EVP_EncryptUpdate(c->ctx, buf, &len, buf, *enc_len)) { + if (!EVP_EncryptUpdate(c->ctx, dst, &len, src, src_len)) { return srtp_err_status_cipher_fail; } - *enc_len = len; + *dst_len = len; - if (!EVP_EncryptFinal_ex(c->ctx, buf + len, &len)) { + if (!EVP_EncryptFinal_ex(c->ctx, dst + len, &len)) { return srtp_err_status_cipher_fail; } - *enc_len += len; + *dst_len += len; return srtp_err_status_ok; } diff --git a/crypto/cipher/aes_icm_wssl.c b/crypto/cipher/aes_icm_wssl.c index 11cd6f41c..4ccd3512e 100644 --- a/crypto/cipher/aes_icm_wssl.c +++ b/crypto/cipher/aes_icm_wssl.c @@ -308,19 +308,22 @@ static srtp_err_status_t srtp_aes_icm_wolfssl_set_iv( * enc_len length of encrypt buffer */ static srtp_err_status_t srtp_aes_icm_wolfssl_encrypt(void *cv, - uint8_t *buf, - size_t *enc_len) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; int err; debug_print(srtp_mod_aes_icm, "rs0: %s", v128_hex_string(&c->counter)); - err = wc_AesCtrEncrypt(c->ctx, buf, buf, *enc_len); + err = wc_AesCtrEncrypt(c->ctx, dst, src, src_len); if (err < 0) { debug_print(srtp_mod_aes_icm, "wolfSSL encrypt error: %d", err); return srtp_err_status_cipher_fail; } + *dst_len = src_len; return srtp_err_status_ok; } diff --git a/crypto/cipher/cipher.c b/crypto/cipher/cipher.c index 4458c276b..80776b14c 100644 --- a/crypto/cipher/cipher.c +++ b/crypto/cipher/cipher.c @@ -107,29 +107,34 @@ srtp_err_status_t srtp_cipher_output(srtp_cipher_t *c, octet_string_set_to_zero(buffer, *num_octets_to_output); /* exor keystream into buffer */ - return (((c)->type)->encrypt(((c)->state), buffer, num_octets_to_output)); + return (((c)->type)->encrypt(((c)->state), buffer, *num_octets_to_output, + buffer, num_octets_to_output)); } srtp_err_status_t srtp_cipher_encrypt(srtp_cipher_t *c, - uint8_t *buffer, - size_t *num_octets_to_output) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { if (!c || !c->type || !c->state) { return (srtp_err_status_bad_param); } - return (((c)->type)->encrypt(((c)->state), buffer, num_octets_to_output)); + return (((c)->type)->encrypt(((c)->state), src, src_len, dst, dst_len)); } srtp_err_status_t srtp_cipher_decrypt(srtp_cipher_t *c, - uint8_t *buffer, - size_t *num_octets_to_output) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { if (!c || !c->type || !c->state) { return (srtp_err_status_bad_param); } - return (((c)->type)->decrypt(((c)->state), buffer, num_octets_to_output)); + return (((c)->type)->decrypt(((c)->state), src, src_len, dst, dst_len)); } srtp_err_status_t srtp_cipher_get_tag(srtp_cipher_t *c, @@ -292,8 +297,9 @@ srtp_err_status_t srtp_cipher_type_test( } /* encrypt */ - len = test_case->plaintext_length_octets; - status = srtp_cipher_encrypt(c, buffer, &len); + len = sizeof(buffer); + status = srtp_cipher_encrypt( + c, buffer, test_case->plaintext_length_octets, buffer, &len); if (status) { srtp_cipher_dealloc(c); return status; @@ -392,8 +398,9 @@ srtp_err_status_t srtp_cipher_type_test( } /* decrypt */ - len = test_case->ciphertext_length_octets; - status = srtp_cipher_decrypt(c, buffer, &len); + len = sizeof(buffer); + status = srtp_cipher_decrypt( + c, buffer, test_case->ciphertext_length_octets, buffer, &len); if (status) { srtp_cipher_dealloc(c); return status; @@ -454,21 +461,24 @@ srtp_err_status_t srtp_cipher_type_test( } for (size_t j = 0; j < NUM_RAND_TESTS; j++) { - size_t length; size_t plaintext_len; + size_t encrypted_len; + size_t decrypted_len; uint8_t key[MAX_KEY_LEN]; uint8_t iv[MAX_KEY_LEN]; /* choose a length at random (leaving room for IV and padding) */ - length = srtp_cipher_rand_u32_for_tests() % (SELF_TEST_BUF_OCTETS - 64); - debug_print(srtp_mod_cipher, "random plaintext length %zu\n", length); - srtp_cipher_rand_for_tests(buffer, length); + plaintext_len = + srtp_cipher_rand_u32_for_tests() % (SELF_TEST_BUF_OCTETS - 64); + debug_print(srtp_mod_cipher, "random plaintext length %zu\n", + plaintext_len); + srtp_cipher_rand_for_tests(buffer, plaintext_len); debug_print(srtp_mod_cipher, "plaintext: %s", - srtp_octet_string_hex_string(buffer, length)); + srtp_octet_string_hex_string(buffer, plaintext_len)); /* copy plaintext into second buffer */ - for (size_t i = 0; i < length; i++) { + for (size_t i = 0; i < plaintext_len; i++) { buffer2[i] = buffer[i]; } @@ -513,8 +523,9 @@ srtp_err_status_t srtp_cipher_type_test( } /* encrypt buffer with cipher */ - plaintext_len = length; - status = srtp_cipher_encrypt(c, buffer, &length); + encrypted_len = sizeof(buffer); + status = srtp_cipher_encrypt(c, buffer, plaintext_len, buffer, + &encrypted_len); if (status) { srtp_cipher_dealloc(c); return status; @@ -524,15 +535,15 @@ srtp_err_status_t srtp_cipher_type_test( /* * Get the GCM tag */ - status = srtp_cipher_get_tag(c, buffer + length, &tag_len); + status = srtp_cipher_get_tag(c, buffer + encrypted_len, &tag_len); if (status) { srtp_cipher_dealloc(c); return status; } - length += tag_len; + encrypted_len += tag_len; } debug_print(srtp_mod_cipher, "ciphertext: %s", - srtp_octet_string_hex_string(buffer, length)); + srtp_octet_string_hex_string(buffer, encrypted_len)); /* * re-initialize cipher for decryption, re-set the iv, then @@ -564,17 +575,19 @@ srtp_err_status_t srtp_cipher_type_test( srtp_octet_string_hex_string( test_case->aad, test_case->aad_length_octets)); } - status = srtp_cipher_decrypt(c, buffer, &length); + decrypted_len = sizeof(buffer); + status = srtp_cipher_decrypt(c, buffer, encrypted_len, buffer, + &decrypted_len); if (status) { srtp_cipher_dealloc(c); return status; } debug_print(srtp_mod_cipher, "plaintext[2]: %s", - srtp_octet_string_hex_string(buffer, length)); + srtp_octet_string_hex_string(buffer, decrypted_len)); /* compare the resulting plaintext with the original one */ - if (length != plaintext_len) { + if (decrypted_len != plaintext_len) { srtp_cipher_dealloc(c); return srtp_err_status_algo_fail; } @@ -656,7 +669,8 @@ uint64_t srtp_cipher_bits_per_second(srtp_cipher_t *c, } // Encrypt the buffer - if (srtp_cipher_encrypt(c, enc_buf, &len) != srtp_err_status_ok) { + if (srtp_cipher_encrypt(c, enc_buf, len, enc_buf, &len) != + srtp_err_status_ok) { srtp_crypto_free(enc_buf); return 0; } diff --git a/crypto/cipher/null_cipher.c b/crypto/cipher/null_cipher.c index a507f4758..58870e8a4 100644 --- a/crypto/cipher/null_cipher.c +++ b/crypto/cipher/null_cipher.c @@ -116,13 +116,19 @@ static srtp_err_status_t srtp_null_cipher_set_iv(void *cv, } static srtp_err_status_t srtp_null_cipher_encrypt(void *cv, - uint8_t *buf, - size_t *bytes_to_encr) + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len) { - /* srtp_null_cipher_ctx_t *c = (srtp_null_cipher_ctx_t *)cv; */ (void)cv; - (void)buf; - (void)bytes_to_encr; + if (src != dst) { + if (*dst_len < src_len) { + return srtp_err_status_buffer_small; + } + memcpy(dst, src, src_len); + } + *dst_len = src_len; return srtp_err_status_ok; } @@ -143,7 +149,7 @@ static const srtp_cipher_test_case_t srtp_null_cipher_test_0 = { }; /* - * note: the decrypt function is idential to the encrypt function + * note: the decrypt function is identical to the encrypt function */ const srtp_cipher_type_t srtp_null_cipher = { diff --git a/crypto/include/cipher.h b/crypto/include/cipher.h index 4c5b7b716..995cfcb0a 100644 --- a/crypto/include/cipher.h +++ b/crypto/include/cipher.h @@ -97,16 +97,18 @@ typedef srtp_err_status_t (*srtp_cipher_set_aad_func_t)(void *state, size_t aad_len); /* a srtp_cipher_encrypt_func_t encrypts data in-place */ -typedef srtp_err_status_t (*srtp_cipher_encrypt_func_t)( - void *state, - uint8_t *buffer, - size_t *octets_to_encrypt); +typedef srtp_err_status_t (*srtp_cipher_encrypt_func_t)(void *state, + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len); /* a srtp_cipher_decrypt_func_t decrypts data in-place */ -typedef srtp_err_status_t (*srtp_cipher_decrypt_func_t)( - void *state, - uint8_t *buffer, - size_t *octets_to_decrypt); +typedef srtp_err_status_t (*srtp_cipher_decrypt_func_t)(void *state, + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len); /* * a srtp_cipher_set_iv_func_t function sets the current initialization vector @@ -219,11 +221,15 @@ srtp_err_status_t srtp_cipher_output(srtp_cipher_t *c, uint8_t *buffer, size_t *num_octets_to_output); srtp_err_status_t srtp_cipher_encrypt(srtp_cipher_t *c, - uint8_t *buffer, - size_t *num_octets_to_output); + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len); srtp_err_status_t srtp_cipher_decrypt(srtp_cipher_t *c, - uint8_t *buffer, - size_t *num_octets_to_output); + const uint8_t *src, + size_t src_len, + uint8_t *dst, + size_t *dst_len); srtp_err_status_t srtp_cipher_get_tag(srtp_cipher_t *c, uint8_t *buffer, size_t *tag_len); diff --git a/crypto/test/cipher_driver.c b/crypto/test/cipher_driver.c index f15073efb..de648c0a3 100644 --- a/crypto/test/cipher_driver.c +++ b/crypto/test/cipher_driver.c @@ -62,6 +62,8 @@ void cipher_driver_test_throughput(srtp_cipher_t *c); srtp_err_status_t cipher_driver_self_test(srtp_cipher_type_t *ct); +srtp_err_status_t cipher_driver_test_api(srtp_cipher_type_t *ct, int key_len); + /* * cipher_driver_test_buffering(ct) tests the cipher's output * buffering for correctness by checking the consistency of successive @@ -217,6 +219,8 @@ int main(int argc, char *argv[]) cipher_driver_self_test(&srtp_aes_gcm_128); cipher_driver_self_test(&srtp_aes_gcm_256); #endif + cipher_driver_test_api(&srtp_aes_icm_128, + SRTP_AES_ICM_128_KEY_LEN_WSALT); } /* do timing and/or buffer_test on srtp_null_cipher */ @@ -353,6 +357,56 @@ srtp_err_status_t cipher_driver_self_test(srtp_cipher_type_t *ct) return srtp_err_status_ok; } +srtp_err_status_t cipher_driver_test_api(srtp_cipher_type_t *ct, int key_len) +{ + srtp_err_status_t status; + srtp_cipher_t *c = NULL; + + /* clang-format off */ + uint8_t test_key[48] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + }; + uint8_t iv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + /* clang-format on */ + + printf("testing cipher api for %s...", ct->description); + + if (key_len > (int)sizeof(test_key)) { + return srtp_err_status_bad_param; + } + + status = srtp_cipher_type_alloc(&srtp_aes_icm_256, &c, key_len, 0); + if (status) { + return status; + } + + status = srtp_cipher_init(c, test_key); + if (status) { + return status; + } + + status = srtp_cipher_set_iv(c, iv, srtp_direction_encrypt); + if (status) { + return status; + } + + status = srtp_cipher_dealloc(c); + if (status) { + return status; + } + + printf("passed\n"); + + return srtp_err_status_ok; +} + /* * cipher_driver_test_buffering(ct) tests the cipher's output * buffering for correctness by checking the consistency of succesive @@ -384,7 +438,7 @@ srtp_err_status_t cipher_driver_test_buffering(srtp_cipher_t *c) } /* generate 'reference' value by encrypting all at once */ - status = srtp_cipher_encrypt(c, buffer0, &buflen); + status = srtp_cipher_encrypt(c, buffer0, buflen, buffer0, &buflen); if (status) { return status; } @@ -407,7 +461,7 @@ srtp_err_status_t cipher_driver_test_buffering(srtp_cipher_t *c) len = end - current; } - status = srtp_cipher_encrypt(c, current, &len); + status = srtp_cipher_encrypt(c, current, len, current, &len); if (status) { return status; } @@ -569,7 +623,7 @@ uint64_t cipher_array_bits_per_second(srtp_cipher_t *cipher_array[], srtp_cipher_set_iv(cipher_array[cipher_index], (uint8_t *)&nonce, srtp_direction_encrypt); srtp_cipher_encrypt(cipher_array[cipher_index], enc_buf, - &octets_to_encrypt); + octets_to_encrypt, enc_buf, &octets_to_encrypt); /* choose a cipher at random from the array*/ cipher_index = (*((size_t *)enc_buf)) % num_cipher; 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 d013c5a03..f5d872f08 100644 --- a/include/srtp.h +++ b/include/srtp.h @@ -213,8 +213,9 @@ typedef enum { /**< invalid */ srtp_err_status_pkt_idx_old = 26, /**< packet index is too old to */ /**< consider */ - srtp_err_status_pkt_idx_adv = 27 /**< packet index advanced, reset */ + srtp_err_status_pkt_idx_adv = 27, /**< packet index advanced, reset */ /**< needed */ + srtp_err_status_buffer_small = 28, /**< out buffer is too small */ } srtp_err_status_t; typedef struct srtp_ctx_t_ srtp_ctx_t; @@ -386,10 +387,10 @@ srtp_err_status_t srtp_shutdown(void); * @brief srtp_protect() is the Secure RTP sender-side packet processing * function. * - * The function call srtp_protect(ctx, rtp_hdr, len_ptr) applies SRTP - * protection to the RTP packet rtp_hdr (which has length *len_ptr) using - * the SRTP context ctx. If srtp_err_status_ok is returned, then rtp_hdr - * points to the resulting SRTP packet and *len_ptr is the number of + * The function call srtp_protect(ctx, rtp, rtp_len, srtp, srtp_len, mki_index) + * applies SRTP protection to the RTP packet rtp (which has length rtp_len) + * using the SRTP context ctx. If srtp_err_status_ok is returned, then srtp + * points to the resulting SRTP packet and *srtp_len is the number of * octets in that packet; otherwise, no assumptions should be made * about the value of either data elements. * @@ -397,25 +398,24 @@ srtp_err_status_t srtp_shutdown(void); * need not be consecutive, but they @b must be out of order by less * than 2^15 = 32,768 packets. * - * @warning This function assumes that it can write the authentication - * tag into the location in memory immediately following the RTP - * packet, and assumes that the RTP packet is aligned on a 32-bit + * @warning This function assumes that the RTP packet is aligned on a 32-bit * boundary. * - * @warning This function assumes that it can write SRTP_MAX_TRAILER_LEN - * into the location in memory immediately following the RTP packet. - * Callers MUST ensure that this much writable memory is available in - * the buffer that holds the RTP packet. - * * @param ctx is the SRTP context to use in processing the packet. * - * @param rtp_hdr is a pointer to the RTP packet (before the call); after - * the function returns, it points to the srtp packet. + * @param rtp is a pointer to the RTP packet. + * + * @param rtp_len is the length in octets of the complete RTP + * packet (header and body). * - * @param len_ptr is a pointer to the length in octets of the complete - * RTP packet (header and body) before the function call, and of the - * complete SRTP packet after the call, if srtp_err_status_ok was returned. - * Otherwise, the value of the data to which it points is undefined. + * @param srtp is a pointer to a buffer that after the function returns will + * contain the complete SRTP packet. The value of srtp can be the same as rtp to + * support in-place io. + * + * @param srtp_len is a pointer to the length in octets of the srtp buffer + * before the function call, and of the complete SRTP packet after the call, if + * srtp_err_status_ok was returned. Otherwise, the value of the data to which it + * points is undefined. * * @param mki_index integer value specifying which set of session keys should be * used if use_mki in the policy was set to true. Otherwise ignored. @@ -423,22 +423,26 @@ srtp_err_status_t srtp_shutdown(void); * @return * - srtp_err_status_ok no problems * - srtp_err_status_replay_fail rtp sequence number was non-increasing + * - srtp_err_status_buffer_small the srtp buffer is too small for the SRTP + * packet * - @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); /** * @brief srtp_unprotect() is the Secure RTP receiver-side packet * processing function. * - * The function call srtp_unprotect(ctx, srtp_hdr, len_ptr) verifies - * the Secure RTP protection of the SRTP packet pointed to by srtp_hdr - * (which has length *len_ptr), using the SRTP context ctx. If - * srtp_err_status_ok is returned, then srtp_hdr points to the resulting - * RTP packet and *len_ptr is the number of octets in that packet; + * The function call srtp_unprotect(ctx, srtp, srtp_len, rtp, rtp_len) verifies + * the Secure RTP protection of the SRTP packet pointed to by srtp + * (which has length srtp_len), using the SRTP context ctx. If + * srtp_err_status_ok is returned, then rtp points to the resulting + * RTP packet and *rtp_len is the number of octets in that packet; * otherwise, no assumptions should be made about the value of either * data elements. * @@ -451,15 +455,19 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, * * @param ctx is the SRTP session which applies to the particular packet. * - * @param srtp_hdr is a pointer to the header of the SRTP packet - * (before the call). after the function returns, it points to the - * rtp packet if srtp_err_status_ok was returned; otherwise, the value of - * the data to which it points is undefined. + * @param srtp is a pointer to the header of the SRTP packet. + * + * @param srtp_len is the length in octets of the complete + * srtp packet (header and body). * - * @param len_ptr is a pointer to the length in octets of the complete - * srtp packet (header and body) before the function call, and of the - * complete rtp packet after the call, if srtp_err_status_ok was returned. - * Otherwise, the value of the data to which it points is undefined. + * @param rtp is a pointer to a buffer that after the function returns will + * contain the complete RTP packet. The value of rtp can be the same as srtp + * to support in-place io. + * + * @param srtp_len is a pointer to the length of the rtp buffer before the + * function call, and of the complete RTP packet after the call, if + * srtp_err_status_ok was returned. Otherwise, the value of the data to which + * it points is undefined. * * @return * - srtp_err_status_ok if the RTP packet is valid. @@ -472,12 +480,14 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, * */ srtp_err_status_t srtp_unprotect(srtp_t ctx, - uint8_t *srtp_hdr, - size_t *len_ptr); + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len); /** * @brief srtp_create() allocates and initializes an SRTP session. - + * * The function call srtp_create(session, policy) allocates and * initializes an SRTP session context, applying the given policy. * @@ -1110,56 +1120,58 @@ void srtp_append_salt_to_key(uint8_t *key, * @brief srtp_protect_rtcp() is the Secure RTCP sender-side packet * processing function. * - * The function call srtp_protect_rtcp(ctx, rtp_hdr, len_ptr) applies - * SRTCP protection to the RTCP packet rtcp_hdr (which has length - * *len_ptr) using the SRTP session context ctx. If srtp_err_status_ok is - * returned, then rtp_hdr points to the resulting SRTCP packet and - * *len_ptr is the number of octets in that packet; otherwise, no + * The function call srtp_protect_rtcp(ctx, rtcp, rtcp_len, srtcp, srtcp_len, + * mki_index) applies SRTCP protection to the RTCP packet rtcp (which has length + * rtcp_len) using the SRTP session context ctx. If srtp_err_status_ok is + * returned, then srtcp points to the resulting SRTCP packet and + * *srtcp_len is the number of octets in that packet; otherwise, no * assumptions should be made about the value of either data elements. * - * @warning This function assumes that it can write the authentication - * tag into the location in memory immediately following the RTCP - * packet, and assumes that the RTCP packet is aligned on a 32-bit + * @warning This function assumes that the RTCP packet is aligned on a 32-bit * boundary. * - * @warning This function assumes that it can write SRTP_MAX_SRTCP_TRAILER_LEN - * into the location in memory immediately following the RTCP packet. - * Callers MUST ensure that this much writable memory is available in - * the buffer that holds the RTCP packet. - * * @param ctx is the SRTP context to use in processing the packet. * - * @param rtcp_hdr is a pointer to the RTCP packet (before the call); after - * the function returns, it points to the srtp packet. + * @param rtcp is a pointer to the RTCP packet (before the call). * - * @param pkt_octet_len is a pointer to the length in octets of the - * complete RTCP packet (header and body) before the function call, - * and of the complete SRTCP packet after the call, if srtp_err_status_ok - * was returned. Otherwise, the value of the data to which it points - * is undefined. + * @param rtcp_len is the length in octets of the complete RTCP packet (header + * and body). + * + * @param srtcp is a pointer to a buffer that after the function returns will + * contain the complete SRTCP packet. The value of srtcp can be the same as rtcp + * to support in-place io. + * + * @param srtcp_len is a pointer to the length in octets of the srtcp buffer + * before the function call, and of the complete SRTCP packet after the call, if + * srtp_err_status_ok was returned. Otherwise, the value of the data to which it + * points is undefined. * * @param mki_index integer value specifying which set of session keys should be * used if use_mki was set to true. Otherwise ignored. * * @return * - srtp_err_status_ok if there were no problems. + * - srtp_err_status_buffer_small the srtcp buffer is too small for the + * SRTCP packet * - [other] if there was a failure in * 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); /** * @brief srtp_unprotect_rtcp() is the Secure RTCP receiver-side packet * processing function. * - * The function call srtp_unprotect_rtcp(ctx, srtp_hdr, len_ptr) + * The function call srtp_unprotect_rtcp(ctx, srtcp, srtcp_len, rtcp, rtcp_len) * verifies the Secure RTCP protection of the SRTCP packet pointed to - * by srtcp_hdr (which has length *len_ptr), using the SRTP session - * context ctx. If srtp_err_status_ok is returned, then srtcp_hdr points - * to the resulting RTCP packet and *len_ptr is the number of octets + * by srtcp (which has length srtcp_len), using the SRTP session + * context ctx. If srtp_err_status_ok is returned, then rtcp points + * to the resulting RTCP packet and *rtcp_len is the number of octets * in that packet; otherwise, no assumptions should be made about the * value of either data elements. * @@ -1169,16 +1181,19 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, * @param ctx is a pointer to the srtp_t which applies to the * particular packet. * - * @param srtcp_hdr is a pointer to the header of the SRTCP packet - * (before the call). After the function returns, it points to the - * rtp packet if srtp_err_status_ok was returned; otherwise, the value of - * the data to which it points is undefined. + * @param srtcp is a pointer to the header of the SRTCP packet. + * + * @param srtcp_len is the length in octets of the complete SRTCP packet (header + * and body). + * + * @param rtcp is a pointer to a buffer that after the function returns will + * contain the complete RTCP packet. The value of rtcp can be the same as srtcp + * to support in-place io. * - * @param pkt_octet_len is a pointer to the length in octets of the - * complete SRTCP packet (header and body) before the function call, - * and of the complete rtp packet after the call, if srtp_err_status_ok was - * returned. Otherwise, the value of the data to which it points is - * undefined. + * @param rtcp_len is a pointer to the length of the rtcp buffer before the + * function call, and of the complete RTCP packet after the call, if + * srtp_err_status_ok was returned. Otherwise, the value of the data to which + * it points is undefined. * * @return * - srtp_err_status_ok if the RTCP packet is valid. @@ -1192,12 +1207,10 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, * */ 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); /** * @defgroup User data associated to a SRTP session. diff --git a/srtp/srtp.c b/srtp/srtp.c index bf91ce89a..da5e6e7d2 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -936,7 +936,7 @@ static srtp_err_status_t srtp_kdf_generate(srtp_kdf_t *kdf, /* generate keystream output */ octet_string_set_to_zero(key, length); - status = srtp_cipher_encrypt(kdf->cipher, key, &length); + status = srtp_cipher_encrypt(kdf->cipher, key, length, key, &length); if (status) { return status; } @@ -1839,12 +1839,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 */ @@ -1881,16 +1883,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; + + /* check output length */ + if (*srtp_len < rtp_len + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } - enc_octet_len = *pkt_octet_len - (enc_start - rtp_hdr); + /* 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 @@ -1944,7 +1956,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; } @@ -1953,15 +1965,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); + 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; } @@ -1970,21 +1984,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; } @@ -2000,13 +2016,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; @@ -2037,25 +2055,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 @@ -2066,6 +2078,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 @@ -2087,16 +2109,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); + status = + srtp_cipher_decrypt(session_keys->rtp_cipher, srtp + enc_start, + enc_octet_len, rtp + enc_start, &enc_octet_len); if (status) { return status; } @@ -2106,7 +2129,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; } @@ -2176,22 +2199,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_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 */ @@ -2206,13 +2227,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; } @@ -2279,7 +2300,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); } @@ -2309,27 +2330,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); } /* @@ -2338,8 +2361,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; @@ -2431,19 +2454,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, + 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); } /* @@ -2458,8 +2485,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; } @@ -2475,28 +2501,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_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; @@ -2510,13 +2538,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; } @@ -2572,8 +2600,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; } @@ -2584,9 +2612,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 */ @@ -2627,28 +2654,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); } /* @@ -2657,8 +2680,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; @@ -2695,7 +2718,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; } @@ -2738,19 +2761,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); + 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); } /* @@ -2815,11 +2842,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; } @@ -3592,12 +3615,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 */ @@ -3606,7 +3631,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); @@ -3615,36 +3639,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 @@ -3676,15 +3708,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 { /* @@ -3692,8 +3724,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); } @@ -3701,17 +3732,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); + 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; } @@ -3723,14 +3756,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); + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, NULL, 0, NULL, + &nolen); if (status) { return srtp_err_status_cipher_fail; } @@ -3742,14 +3780,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; } @@ -3763,26 +3802,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 */ @@ -3791,25 +3833,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 @@ -3835,18 +3868,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 { /* @@ -3854,10 +3898,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); } @@ -3866,34 +3909,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); + 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; - status = - srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, &tmp_len); + tmp_len = 0; + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, + 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 @@ -3952,12 +4002,14 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( } 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 */ @@ -3971,7 +4023,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; } @@ -4034,7 +4086,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); } @@ -4042,30 +4094,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); } @@ -4074,9 +4134,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 @@ -4143,12 +4202,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); + 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 */ @@ -4161,35 +4224,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_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; @@ -4206,7 +4272,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; } @@ -4234,7 +4300,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; @@ -4246,8 +4312,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; } @@ -4257,8 +4323,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 || @@ -4267,43 +4333,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 @@ -4383,20 +4443,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); + 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 a40953bb7..f9d4664dc 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]; @@ -160,19 +188,151 @@ srtp_master_key_t *test_keys[2] = { }; // clang-format on +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 (srtp_len > sizeof(in_buf)) { + printf("srtp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, srtp, srtp_len); + status = srtp_unprotect(ctx, in_buf, srtp_len, srtp, rtp_len); + } else { + status = srtp_unprotect(ctx, srtp, srtp_len, srtp, rtp_len); + } + return status; +} + +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 (rtcp_len > sizeof(in_buf)) { + printf("rtcp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, rtcp, rtcp_len); + status = srtp_protect_rtcp(ctx, in_buf, rtcp_len, rtcp, srtcp_len, + mki_index); + } else { + status = + srtp_protect_rtcp(ctx, rtcp, rtcp_len, rtcp, srtcp_len, mki_index); + } + return status; +} + +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 (srtcp_len > sizeof(in_buf)) { + printf("srtcp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, srtcp, srtcp_len); + status = srtp_unprotect_rtcp(ctx, in_buf, srtcp_len, srtcp, rtcp_len); + } else { + status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len, srtcp, rtcp_len); + } + return status; +} + +srtp_err_status_t call_srtp_unprotect_rtcp(srtp_ctx_t *ctx, + uint8_t *srtcp, + size_t *srtcp_len) +{ + return call_srtp_unprotect_rtcp2(ctx, srtcp, *srtcp_len, srtcp_len); +} + void usage(char *prog_name) { - printf( - "usage: %s [ -t ][ -c ][ -v ][ -s ][ -o ][-d ]* [ -l ]\n" - " -t run timing test\n" - " -r run rejection timing test\n" - " -c run codec timing test\n" - " -v run validation tests\n" - " -s run stream list tests only\n" - " -o output logging to stdout\n" - " -d turn on debugging module \n" - " -l list debugging modules\n", - prog_name); + printf("usage: %s [ -t ][ -c ][ -v ][ -s ][ -o ][-d ]* [ -l " + "][ -n ]\n" + " -t run timing test\n" + " -r run rejection timing test\n" + " -c run codec timing test\n" + " -v run validation tests\n" + " -s run stream list tests only\n" + " -o output logging to stdout\n" + " -d turn on debugging module \n" + " -l list debugging modules\n" + " -n run with not-in-place io api\n", + prog_name); exit(1); } @@ -263,7 +423,7 @@ int main(int argc, char *argv[]) /* process input arguments */ while (1) { - q = getopt_s(argc, argv, "trcvsold:"); + q = getopt_s(argc, argv, "trcvsold:n"); if (q == -1) { break; } @@ -297,6 +457,10 @@ int main(int argc, char *argv[]) exit(1); } break; + case 'n': + printf("using srtp not-in-place io api\n"); + use_srtp_not_in_place_io_api = true; + break; default: usage(argv[0]); } @@ -338,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) { @@ -346,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"); @@ -353,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) { @@ -370,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) { @@ -378,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) { @@ -386,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++; } @@ -725,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 @@ -742,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; - } + memset(buffer, 0xab, payload_len); + buffer += payload_len; - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_SRTCP_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } - - *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) @@ -990,7 +1167,7 @@ double srtp_bits_per_second(size_t msg_len_octets, const srtp_policy_t *policy) for (size_t i = 0; i < num_trials; i++) { len = input_len; /* srtp protect message */ - status = srtp_protect(srtp, mesg, &len, 0); + status = call_srtp_protect(srtp, mesg, &len, 0); if (status) { printf("error: srtp_protect() failed with error code %d\n", status); exit(1); @@ -1042,12 +1219,12 @@ double srtp_rejections_per_second(size_t msg_len_octets, if (mesg == NULL) { return 0.0; /* indicate failure by returning zero */ } - srtp_protect(srtp, mesg, &len, 0); + call_srtp_protect(srtp, mesg, &len, 0); timer = clock(); for (size_t i = 0; i < num_trials; i++) { len = msg_len_octets; - srtp_unprotect(srtp, mesg, &len); + call_srtp_unprotect(srtp, mesg, &len); } timer = clock() - timer; @@ -1070,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, @@ -1145,7 +1398,7 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, debug_print(mod_driver, "reference packet before protection:\n%s", octet_string_hex_string(hdr, len)); #endif - err_check(srtp_protect(srtp_sender, hdr, &len, mki_index)); + err_check(call_srtp_protect(srtp_sender, hdr, &len, mki_index)); debug_print(mod_driver, "after protection:\n%s", srtp_packet_to_string(hdr, len)); @@ -1211,12 +1464,12 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, err_check(srtp_create(&srtp_rcvr, &rcvr_policy)); - err_check(srtp_unprotect(srtp_rcvr, hdr, &len)); + err_check(call_srtp_unprotect(srtp_rcvr, hdr, &len)); debug_print(mod_driver, "after unprotection:\n%s", srtp_packet_to_string(hdr, len)); - /* verify that the unprotected packet matches the origial one */ + /* verify that the unprotected packet matches the original one */ for (i = 0; i < len; i++) { if (hdr[i] != hdr2[i]) { fprintf(stdout, "mismatch at octet %zu\n", i); @@ -1238,7 +1491,7 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, printf("testing for false positives in replay check..."); /* unprotect a second time - should fail with a replay error */ - status = srtp_unprotect(srtp_rcvr, hdr, &msg_len_enc); + status = call_srtp_unprotect(srtp_rcvr, hdr, &msg_len_enc); if (status != srtp_err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); @@ -1254,13 +1507,13 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, ((srtp_hdr_t *)hdr)->seq++; /* apply protection */ - err_check(srtp_protect(srtp_sender, hdr, &len, mki_index)); + err_check(call_srtp_protect(srtp_sender, hdr, &len, mki_index)); /* flip bits in packet */ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ - status = srtp_unprotect(srtp_rcvr, hdr, &len); + status = call_srtp_unprotect(srtp_rcvr, hdr, &len); if (status != srtp_err_status_auth_fail) { printf("failed with error code %d\n", status); printf("failed\n"); @@ -1280,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) @@ -1340,7 +1798,7 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, debug_print(mod_driver, "reference packet before protection:\n%s", octet_string_hex_string(hdr, len)); #endif - err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); + err_check(call_srtp_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); debug_print(mod_driver, "after protection:\n%s", srtp_rtcp_packet_to_string(hdr, len)); @@ -1407,7 +1865,7 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, err_check(srtp_create(&srtcp_rcvr, &rcvr_policy)); - err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len)); + err_check(call_srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len)); debug_print(mod_driver, "after unprotection:\n%s", srtp_rtcp_packet_to_string(hdr, len)); @@ -1434,7 +1892,7 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, printf("testing for false positives in replay check..."); /* unprotect a second time - should fail with a replay error */ - status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &msg_len_enc); + status = call_srtp_unprotect_rtcp(srtcp_rcvr, hdr, &msg_len_enc); if (status != srtp_err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); @@ -1447,13 +1905,13 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, printf("testing for false positives in auth check..."); /* apply protection */ - err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); + err_check(call_srtp_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); /* flip bits in packet */ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ - status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len); + status = call_srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len); if (status != srtp_err_status_auth_fail) { printf("failed with error code %d\n", status); printf("failed\n"); @@ -1473,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; @@ -1770,7 +2419,7 @@ srtp_err_status_t srtp_validate(void) * protect plaintext, then compare with ciphertext */ len = 28; - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status || (len != 38)) { return srtp_err_status_fail; } @@ -1788,7 +2437,7 @@ srtp_err_status_t srtp_validate(void) * protect plaintext rtcp, then compare with srtcp ciphertext */ len = 24; - status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); + status = call_srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); if (status || (len != 38)) { return srtp_err_status_fail; } @@ -1815,7 +2464,7 @@ srtp_err_status_t srtp_validate(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) { return status; } @@ -1828,7 +2477,7 @@ srtp_err_status_t srtp_validate(void) * unprotect srtcp ciphertext, then compare with rtcp plaintext */ len = 38; - status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); + status = call_srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); if (status || (len != 24)) { return status; } @@ -1935,7 +2584,7 @@ srtp_err_status_t srtp_validate_mki(void) * protect plaintext, then compare with ciphertext */ len = 28; - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status) { return status; } @@ -1958,7 +2607,7 @@ srtp_err_status_t srtp_validate_mki(void) * protect plaintext rtcp, then compare with srtcp ciphertext */ len = 24; - status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); + status = call_srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); if (status) { return status; } @@ -1991,7 +2640,7 @@ srtp_err_status_t srtp_validate_mki(void) * unprotect ciphertext, then compare with plaintext */ len = 42; - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) { return status; } @@ -2004,7 +2653,7 @@ srtp_err_status_t srtp_validate_mki(void) * unprotect srtcp ciphertext, then compare with rtcp plaintext */ len = 42; - status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); + status = call_srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); if (status || (len != 24)) { return status; } @@ -2105,7 +2754,7 @@ srtp_err_status_t srtp_validate_null(void) * protect plaintext, then compare with ciphertext */ len = 28; - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status || (len != 38)) { return srtp_err_status_fail; } @@ -2123,7 +2772,7 @@ srtp_err_status_t srtp_validate_null(void) * protect plaintext rtcp, then compare with srtcp ciphertext */ len = 24; - status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); + status = call_srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); if (status || (len != 38)) { return srtp_err_status_fail; } @@ -2150,7 +2799,7 @@ srtp_err_status_t srtp_validate_null(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) { return status; } @@ -2163,7 +2812,7 @@ srtp_err_status_t srtp_validate_null(void) * unprotect srtcp ciphertext, then compare with rtcp plaintext */ len = 38; - status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); + status = call_srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); if (status || (len != 24)) { return status; } @@ -2266,7 +2915,7 @@ srtp_err_status_t srtp_validate_gcm(void) * protect plaintext rtp, then compare with srtp ciphertext */ len = 28; - status = srtp_protect(srtp_snd, rtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, rtp_plaintext, &len, 0); if (status || (len != 44)) { return srtp_err_status_fail; } @@ -2284,7 +2933,7 @@ srtp_err_status_t srtp_validate_gcm(void) * protect plaintext rtcp, then compare with srtcp ciphertext */ len = 24; - status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); + status = call_srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len, 0); if (status || (len != 44)) { return srtp_err_status_fail; } @@ -2312,7 +2961,7 @@ srtp_err_status_t srtp_validate_gcm(void) * unprotect srtp ciphertext, then compare with rtp plaintext */ len = 44; - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) { return status; } @@ -2325,7 +2974,7 @@ srtp_err_status_t srtp_validate_gcm(void) * unprotect srtcp ciphertext, then compare with rtcp plaintext */ len = 44; - status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); + status = call_srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); if (status || (len != 24)) { return status; } @@ -2430,7 +3079,7 @@ srtp_err_status_t srtp_validate_encrypted_extensions_headers(void) * protect plaintext, then compare with ciphertext */ len = sizeof(srtp_plaintext_ref); - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status || (len != sizeof(srtp_plaintext))) { return srtp_err_status_fail; } @@ -2457,7 +3106,7 @@ srtp_err_status_t srtp_validate_encrypted_extensions_headers(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status) { return status; } else if (len != sizeof(srtp_plaintext_ref)) { @@ -2558,7 +3207,7 @@ srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm(void) * protect plaintext, then compare with ciphertext */ len = sizeof(srtp_plaintext_ref); - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status || (len != sizeof(srtp_plaintext))) { return srtp_err_status_fail; } @@ -2585,7 +3234,7 @@ srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status) { return status; } else if (len != sizeof(srtp_plaintext_ref)) { @@ -2678,7 +3327,7 @@ srtp_err_status_t srtp_validate_aes_256(void) * protect plaintext, then compare with ciphertext */ len = 28; - status = srtp_protect(srtp_snd, srtp_plaintext, &len, 0); + status = call_srtp_protect(srtp_snd, srtp_plaintext, &len, 0); if (status || (len != 38)) { return srtp_err_status_fail; } @@ -2705,7 +3354,7 @@ srtp_err_status_t srtp_validate_aes_256(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len); + status = call_srtp_unprotect(srtp_recv, srtp_ciphertext, &len); if (status || (len != 28)) { return status; } @@ -2806,7 +3455,7 @@ srtp_err_status_t srtp_test_empty_payload(void) return srtp_err_status_fail; } - status = srtp_protect(srtp_snd, mesg, &len, 0); + status = call_srtp_protect(srtp_snd, mesg, &len, 0); if (status) { return status; } else if (len != 12 + 10) { @@ -2826,7 +3475,7 @@ srtp_err_status_t srtp_test_empty_payload(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, mesg, &len); + status = call_srtp_unprotect(srtp_recv, mesg, &len); if (status) { return status; } else if (len != 12) { @@ -2881,7 +3530,7 @@ srtp_err_status_t srtp_test_empty_payload_gcm(void) return srtp_err_status_fail; } - status = srtp_protect(srtp_snd, mesg, &len, 0); + status = call_srtp_protect(srtp_snd, mesg, &len, 0); if (status) { return status; } else if (len != 12 + 16) { @@ -2901,7 +3550,7 @@ srtp_err_status_t srtp_test_empty_payload_gcm(void) /* * unprotect ciphertext, then compare with plaintext */ - status = srtp_unprotect(srtp_recv, mesg, &len); + status = call_srtp_unprotect(srtp_recv, mesg, &len); if (status) { return status; } else if (len != 12) { @@ -3076,12 +3725,12 @@ srtp_err_status_t srtp_test_update(void) } ((srtp_hdr_t *)msg)->seq = htons(65535); - status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); + status = call_srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); if (status) { return srtp_err_status_fail; } - status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); if (status) { return status; } @@ -3095,12 +3744,12 @@ srtp_err_status_t srtp_test_update(void) } ((srtp_hdr_t *)msg)->seq = htons(1); - status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); + status = call_srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); if (status) { return srtp_err_status_fail; } - status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); if (status) { return status; } @@ -3122,12 +3771,12 @@ srtp_err_status_t srtp_test_update(void) } ((srtp_hdr_t *)msg)->seq = htons(2); - status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); + status = call_srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); if (status) { return srtp_err_status_fail; } - status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); if (status) { return status; } @@ -3150,14 +3799,14 @@ srtp_err_status_t srtp_test_update(void) } ((srtp_hdr_t *)msg)->seq = htons(3); - status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); + status = call_srtp_protect(srtp_snd, msg, &protected_msg_len_octets, 0); if (status) { return srtp_err_status_fail; } /* verify that receive ctx will fail to unprotect as it still uses test_key */ - status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); if (status == srtp_err_status_ok) { return srtp_err_status_fail; } @@ -3175,8 +3824,8 @@ srtp_err_status_t srtp_test_update(void) return status; } - status = - srtp_unprotect(srtp_recv_roc_0, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv_roc_0, msg, + &protected_msg_len_octets); if (status == srtp_err_status_ok) { return srtp_err_status_fail; } @@ -3197,7 +3846,7 @@ srtp_err_status_t srtp_test_update(void) /* verify that can still unprotect, therfore key is updated and ROC value is * preserved */ - status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); + status = call_srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets); if (status) { return status; } @@ -3552,7 +4201,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) /* Create and protect packets to get to get roc == 1 */ pkts[0] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 65534, 0, &pkt_len_octets[0]); - status = srtp_protect(sender_session, pkts[0], &pkt_len_octets[0], 0); + status = call_srtp_protect(sender_session, pkts[0], &pkt_len_octets[0], 0); if (status) { return status; } @@ -3567,7 +4216,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) pkts[1] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 65535, 1, &pkt_len_octets[1]); - status = srtp_protect(sender_session, pkts[1], &pkt_len_octets[1], 0); + status = call_srtp_protect(sender_session, pkts[1], &pkt_len_octets[1], 0); if (status) { return status; } @@ -3582,7 +4231,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) pkts[2] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 0, 2, &pkt_len_octets[2]); - status = srtp_protect(sender_session, pkts[2], &pkt_len_octets[2], 0); + status = call_srtp_protect(sender_session, pkts[2], &pkt_len_octets[2], 0); if (status) { return status; } @@ -3597,7 +4246,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) pkts[3] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 1, 3, &pkt_len_octets[3]); - status = srtp_protect(sender_session, pkts[3], &pkt_len_octets[3], 0); + status = call_srtp_protect(sender_session, pkts[3], &pkt_len_octets[3], 0); if (status) { return status; } @@ -3612,7 +4261,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) pkts[4] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 2, 4, &pkt_len_octets[4]); - status = srtp_protect(sender_session, pkts[4], &pkt_len_octets[4], 0); + status = call_srtp_protect(sender_session, pkts[4], &pkt_len_octets[4], 0); if (status) { return status; } @@ -3627,7 +4276,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) /* Unprotect packets in this seq order 65534, 0, 2, 1, 65535 which is * equivalent to index 0, 2, 4, 3, 1*/ - status = srtp_unprotect(receiver_session, pkts[0], &pkt_len_octets[0]); + status = call_srtp_unprotect(receiver_session, pkts[0], &pkt_len_octets[0]); if (status) { return status; } @@ -3640,7 +4289,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) return srtp_err_status_fail; } - status = srtp_unprotect(receiver_session, pkts[2], &pkt_len_octets[2]); + status = call_srtp_unprotect(receiver_session, pkts[2], &pkt_len_octets[2]); if (status) { return status; } @@ -3653,7 +4302,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) return srtp_err_status_fail; } - status = srtp_unprotect(receiver_session, pkts[4], &pkt_len_octets[4]); + status = call_srtp_unprotect(receiver_session, pkts[4], &pkt_len_octets[4]); if (status) { return status; } @@ -3666,7 +4315,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) return srtp_err_status_fail; } - status = srtp_unprotect(receiver_session, pkts[3], &pkt_len_octets[3]); + status = call_srtp_unprotect(receiver_session, pkts[3], &pkt_len_octets[3]); if (status) { return status; } @@ -3679,7 +4328,7 @@ srtp_err_status_t srtp_test_out_of_order_after_rollover(void) return srtp_err_status_fail; } - status = srtp_unprotect(receiver_session, pkts[1], &pkt_len_octets[1]); + status = call_srtp_unprotect(receiver_session, pkts[1], &pkt_len_octets[1]); if (status) { return status; } @@ -3746,7 +4395,7 @@ srtp_err_status_t srtp_test_get_roc(void) pkt = srtp_create_test_packet_extended(msg_len_octets, policy.ssrc.value, seq, ts, &protected_msg_len_octets); - status = srtp_protect(session, pkt, &protected_msg_len_octets, 0); + status = call_srtp_protect(session, pkt, &protected_msg_len_octets, 0); free(pkt); if (status) { return status; @@ -3831,7 +4480,7 @@ static srtp_err_status_t test_set_receiver_roc(uint32_t packets, tmp_pkt = srtp_create_test_packet_extended( msg_len_octets, sender_policy.ssrc.value, seq, ts, &tmp_len); - status = srtp_protect(sender_session, tmp_pkt, &tmp_len, 0); + status = call_srtp_protect(sender_session, tmp_pkt, &tmp_len, 0); free(tmp_pkt); if (status) { return status; @@ -3850,8 +4499,8 @@ static srtp_err_status_t test_set_receiver_roc(uint32_t packets, pkt_1 = srtp_create_test_packet_extended(msg_len_octets, sender_policy.ssrc.value, seq, ts, &protected_msg_len_octets_1); - status = - srtp_protect(sender_session, pkt_1, &protected_msg_len_octets_1, 0); + status = call_srtp_protect(sender_session, pkt_1, + &protected_msg_len_octets_1, 0); if (status) { return status; } @@ -3862,8 +4511,8 @@ static srtp_err_status_t test_set_receiver_roc(uint32_t packets, pkt_2 = srtp_create_test_packet_extended(msg_len_octets, sender_policy.ssrc.value, seq, ts, &protected_msg_len_octets_2); - status = - srtp_protect(sender_session, pkt_2, &protected_msg_len_octets_2, 0); + status = call_srtp_protect(sender_session, pkt_2, + &protected_msg_len_octets_2, 0); if (status) { return status; } @@ -3910,15 +4559,15 @@ static srtp_err_status_t test_set_receiver_roc(uint32_t packets, } /* Unprotect the first packet */ - status = srtp_unprotect(receiver_session, recv_pkt_1, - &protected_msg_len_octets_1); + status = call_srtp_unprotect(receiver_session, recv_pkt_1, + &protected_msg_len_octets_1); if (status) { return status; } /* Unprotect the second packet */ - status = srtp_unprotect(receiver_session, recv_pkt_2, - &protected_msg_len_octets_2); + status = call_srtp_unprotect(receiver_session, recv_pkt_2, + &protected_msg_len_octets_2); if (status) { return status; } @@ -3992,7 +4641,8 @@ static srtp_err_status_t test_set_sender_roc(uint16_t seq, uint32_t roc_to_set) pkt = srtp_create_test_packet_extended(msg_len_octets, sender_policy.ssrc.value, seq, ts, &protected_msg_len_octets); - status = srtp_protect(sender_session, pkt, &protected_msg_len_octets, 0); + status = + call_srtp_protect(sender_session, pkt, &protected_msg_len_octets, 0); if (status) { return status; } @@ -4031,8 +4681,8 @@ static srtp_err_status_t test_set_sender_roc(uint16_t seq, uint32_t roc_to_set) return status; } - status = - srtp_unprotect(receiver_session, recv_pkt, &protected_msg_len_octets); + status = call_srtp_unprotect(receiver_session, recv_pkt, + &protected_msg_len_octets); if (status) { return status; }