From 4b84591a56894ba2fd388064312f240e01efc376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Tue, 5 Mar 2024 20:33:25 +0100 Subject: [PATCH 1/8] change cipher api to support not-in-place io --- crypto/cipher/aes_gcm_mbedtls.c | 32 ++++++++++----- crypto/cipher/aes_gcm_nss.c | 62 +++++++++++++++++++--------- crypto/cipher/aes_gcm_ossl.c | 26 +++++++----- crypto/cipher/aes_icm.c | 72 +++++++++++++++++++-------------- crypto/cipher/aes_icm_mbedtls.c | 16 ++++++-- crypto/cipher/aes_icm_nss.c | 10 +++-- crypto/cipher/aes_icm_ossl.c | 14 ++++--- crypto/cipher/cipher.c | 66 ++++++++++++++++++------------ crypto/cipher/null_cipher.c | 18 ++++++--- crypto/include/cipher.h | 30 ++++++++------ crypto/test/cipher_driver.c | 60 +++++++++++++++++++++++++-- include/srtp.h | 3 +- srtp/srtp.c | 25 ++++++------ 13 files changed, 293 insertions(+), 141 deletions(-) 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..68e8685c9 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,43 @@ 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; + //#todo, this might need som looking at + // nss requires space for tag, currently we assume that ther is space, this + // should change, the best would be to merge the cipher encrypt and get_tag + // api + *dst_len += 16; + // 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, // 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; + 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 +400,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_icm.c b/crypto/cipher/aes_icm.c index 744df6aae..a612edc2d 100644 --- a/crypto/cipher/aes_icm.c +++ b/crypto/cipher/aes_icm.c @@ -295,12 +295,20 @@ 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; + + // check out length if not equal or greater bail! + *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 +322,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 +334,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 +353,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 +397,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/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/include/srtp.h b/include/srtp.h index d013c5a03..e7b553b88 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; diff --git a/srtp/srtp.c b/srtp/srtp.c index bf91ce89a..51e81731b 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; } @@ -1961,7 +1961,7 @@ static srtp_err_status_t srtp_protect_aead(srtp_ctx_t *ctx, /* Encrypt the payload */ status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } @@ -2096,7 +2096,7 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, /* Decrypt the ciphertext. This also checks the auth tag based * on the AAD we just specified above */ status = srtp_cipher_decrypt(session_keys->rtp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return status; } @@ -2440,7 +2440,7 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, /* if we're encrypting, exor keystream into the message */ if (enc_start) { status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } @@ -2747,7 +2747,7 @@ srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, /* if we're decrypting, add keystream into ciphertext */ if (enc_start) { status = srtp_cipher_decrypt(session_keys->rtp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } @@ -3711,7 +3711,7 @@ static srtp_err_status_t srtp_protect_rtcp_aead( /* if we're encrypting, exor keystream into the message */ if (enc_start) { status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } @@ -3730,7 +3730,8 @@ static srtp_err_status_t srtp_protect_rtcp_aead( * 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, nolen, + NULL, &nolen); if (status) { return srtp_err_status_cipher_fail; } @@ -3876,7 +3877,7 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( /* if we're decrypting, exor keystream into the message */ if (enc_start) { status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return status; } @@ -3885,8 +3886,8 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( * 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); + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, + tmp_len, auth_tag, &tmp_len); if (status) { return status; } @@ -4145,7 +4146,7 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, /* if we're encrypting, exor keystream into the message */ if (enc_start) { status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } @@ -4386,7 +4387,7 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, /* if we're decrypting, exor keystream into the message */ if (enc_start) { status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, - &enc_octet_len); + enc_octet_len, enc_start, &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } From 8c13ee88e58062fea3ebd2ca96b66b0fc40ff14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Tue, 5 Mar 2024 20:41:05 +0100 Subject: [PATCH 2/8] introduce not-in-place io api A layer to the srtp driver test is added to be able to run the tests both in-place & not-in-place without duplicating the test. The not-in-place functions are currently a minimal implementation using a memcpy. --- CMakeLists.txt | 1 + include/srtp.h | 30 ++++- srtp/srtp.c | 60 ++++++++++ test/srtp_driver.c | 267 ++++++++++++++++++++++++++++++--------------- 4 files changed, 268 insertions(+), 90 deletions(-) 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/include/srtp.h b/include/srtp.h index e7b553b88..7137b94ed 100644 --- a/include/srtp.h +++ b/include/srtp.h @@ -431,6 +431,13 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, size_t *pkt_octet_len, size_t mki_index); +srtp_err_status_t srtp_protect2(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, + size_t mki_index); + /** * @brief srtp_unprotect() is the Secure RTP receiver-side packet * processing function. @@ -476,9 +483,15 @@ srtp_err_status_t srtp_unprotect(srtp_t ctx, uint8_t *srtp_hdr, size_t *len_ptr); +srtp_err_status_t srtp_unprotect2(srtp_t ctx, + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len); + /** * @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. * @@ -1152,6 +1165,13 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, size_t *pkt_octet_len, size_t mki_index); +srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, + size_t mki_index); + /** * @brief srtp_unprotect_rtcp() is the Secure RTCP receiver-side packet * processing function. @@ -1196,9 +1216,11 @@ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, uint8_t *srtcp_hdr, size_t *pkt_octet_len); -/** - * @} - */ +srtp_err_status_t srtp_unprotect_rtcp2(srtp_t ctx, + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len); /** * @defgroup User data associated to a SRTP session. diff --git a/srtp/srtp.c b/srtp/srtp.c index 51e81731b..8f440305d 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -2185,6 +2185,21 @@ static srtp_err_status_t srtp_unprotect_aead(srtp_ctx_t *ctx, return srtp_err_status_ok; } +srtp_err_status_t srtp_protect2(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, + size_t mki_index) +{ + if (*srtp_len < rtp_len) { + return srtp_err_status_bad_param; + } + memcpy(srtp, rtp, rtp_len); + *srtp_len = rtp_len; + return srtp_protect(ctx, srtp, srtp_len, mki_index); +} + srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, uint8_t *rtp_hdr, size_t *pkt_octet_len, @@ -2486,6 +2501,21 @@ srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, return srtp_err_status_ok; } +srtp_err_status_t srtp_unprotect2(srtp_t ctx, + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len) +{ + if (*rtp_len < srtp_len) { + // this is actually expected but for the tests this should not happen + return srtp_err_status_bad_param; + } + memcpy(rtp, srtp, srtp_len); + *rtp_len = srtp_len; + return srtp_unprotect(ctx, rtp, rtp_len); +} + srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, uint8_t *srtp_hdr, size_t *pkt_octet_len) @@ -3952,6 +3982,21 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( return srtp_err_status_ok; } +srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, + size_t mki_index) +{ + if (*srtcp_len < rtcp_len) { + return srtp_err_status_bad_param; + } + memcpy(srtcp, rtcp, rtcp_len); + *srtcp_len = rtcp_len; + return srtp_protect_rtcp(ctx, srtcp, srtcp_len, mki_index); +} + srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, uint8_t *rtcp_hdr, size_t *pkt_octet_len, @@ -4180,6 +4225,21 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, return srtp_err_status_ok; } +srtp_err_status_t srtp_unprotect_rtcp2(srtp_t ctx, + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len) +{ + if (*rtcp_len < srtcp_len) { + // this is actually expected but for the tests this should not happen + return srtp_err_status_bad_param; + } + memcpy(rtcp, srtcp, srtcp_len); + *rtcp_len = srtcp_len; + return srtp_unprotect_rtcp(ctx, rtcp, rtcp_len); +} + srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, uint8_t *srtcp_hdr, size_t *pkt_octet_len) diff --git a/test/srtp_driver.c b/test/srtp_driver.c index a40953bb7..7adcb23b2 100644 --- a/test/srtp_driver.c +++ b/test/srtp_driver.c @@ -160,19 +160,109 @@ srtp_master_key_t *test_keys[2] = { }; // clang-format on +bool use_srtp_not_in_place_io_api = false; + +srtp_err_status_t call_srtp_protect(srtp_ctx_t *ctx, + uint8_t *rtp, + size_t *rtp_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); + // an assumption + size_t srtp_len = *rtp_len + SRTP_MAX_TRAILER_LEN; + status = + srtp_protect2(ctx, in_buf, *rtp_len, rtp, &srtp_len, mki_index); + *rtp_len = srtp_len; + } else { + status = srtp_protect(ctx, rtp, rtp_len, mki_index); + } + return status; +} + +srtp_err_status_t call_srtp_unprotect(srtp_ctx_t *ctx, + uint8_t *srtp, + size_t *srtp_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_unprotect2(ctx, in_buf, *srtp_len, srtp, srtp_len); + } else { + status = srtp_unprotect(ctx, srtp, srtp_len); + } + 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) +{ + 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); + // an assumption + size_t srtcp_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN; + status = srtp_protect_rtcp2(ctx, in_buf, *rtcp_len, rtcp, &srtcp_len, + mki_index); + *rtcp_len = srtcp_len; + } else { + status = srtp_protect_rtcp(ctx, rtcp, rtcp_len, mki_index); + } + return status; +} + +srtp_err_status_t call_srtp_unprotect_rtcp(srtp_ctx_t *ctx, + uint8_t *srtcp, + size_t *srtcp_len) +{ + srtp_err_status_t status = srtp_err_status_fail; + if (use_srtp_not_in_place_io_api) { + uint8_t in_buf[4048]; + if (*srtcp_len > sizeof(in_buf)) { + printf("srtcp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, srtcp, *srtcp_len); + status = + srtp_unprotect_rtcp2(ctx, in_buf, *srtcp_len, srtcp, srtcp_len); + } else { + status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len); + } + return status; +} + 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 +353,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 +387,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]); } @@ -990,7 +1084,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 +1136,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; @@ -1145,7 +1239,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 +1305,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 +1332,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 +1348,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"); @@ -1340,7 +1434,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 +1501,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 +1528,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 +1541,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"); @@ -1770,7 +1864,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 +1882,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 +1909,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 +1922,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 +2029,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 +2052,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 +2085,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 +2098,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 +2199,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 +2217,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 +2244,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 +2257,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 +2360,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 +2378,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 +2406,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 +2419,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 +2524,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 +2551,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 +2652,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 +2679,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 +2772,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 +2799,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 +2900,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 +2920,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 +2975,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 +2995,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 +3170,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 +3189,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 +3216,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 +3244,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 +3269,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 +3291,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 +3646,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 +3661,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 +3676,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 +3691,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 +3706,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 +3721,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 +3734,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 +3747,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 +3760,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 +3773,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 +3840,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 +3925,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 +3944,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 +3956,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 +4004,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 +4086,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 +4126,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; } From 7bb4e3a837678b2e52f29b1cd658a2e49bbf3cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Mon, 25 Mar 2024 09:08:12 +0100 Subject: [PATCH 3/8] implement not in-place api's for protect/unprotect The protect/unprotect api's can now operate both in-place or not in-place, depending on the requirements of the caller. The length of the out buffer can now be checked to ensure there is sufficient space. Tests are add to verify validation of the output buffer length. --- fuzzer/fuzzer.c | 16 +- include/srtp.h | 52 +-- srtp/srtp.c | 656 +++++++++++++++++---------------- test/rtp.c | 9 +- test/rtp_decoder.c | 4 +- test/srtp_driver.c | 897 ++++++++++++++++++++++++++++++++++++--------- 6 files changed, 1100 insertions(+), 534 deletions(-) diff --git a/fuzzer/fuzzer.c b/fuzzer/fuzzer.c index 0e1494572..afa080a2e 100644 --- a/fuzzer/fuzzer.c +++ b/fuzzer/fuzzer.c @@ -187,7 +187,11 @@ static srtp_err_status_t fuzz_srtp_protect(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_protect(srtp_sender, hdr, len, mki); + size_t out_len = *len + SRTP_MAX_TRAILER_LEN; + srtp_err_status_t s = + srtp_protect(srtp_sender, hdr, *len, hdr, &out_len, mki); + *len = out_len; + return s; } static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender, @@ -195,7 +199,7 @@ static srtp_err_status_t fuzz_srtp_unprotect(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_unprotect(srtp_sender, hdr, len); + return srtp_unprotect(srtp_sender, hdr, *len, hdr, len); } static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender, @@ -203,7 +207,11 @@ static srtp_err_status_t fuzz_srtp_protect_rtcp(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_protect_rtcp(srtp_sender, hdr, len, mki); + size_t out_len = *len + SRTP_MAX_SRTCP_TRAILER_LEN; + srtp_err_status_t s = + srtp_protect_rtcp(srtp_sender, hdr, *len, hdr, &out_len, mki); + *len = out_len; + return s; } static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender, @@ -211,7 +219,7 @@ static srtp_err_status_t fuzz_srtp_unprotect_rtcp(srtp_t srtp_sender, size_t *len, size_t mki) { - return srtp_unprotect_rtcp(srtp_sender, hdr, len); + return srtp_unprotect_rtcp(srtp_sender, hdr, *len, hdr, len); } /* Get protect length functions */ diff --git a/include/srtp.h b/include/srtp.h index 7137b94ed..86b3ecfed 100644 --- a/include/srtp.h +++ b/include/srtp.h @@ -426,18 +426,13 @@ srtp_err_status_t srtp_shutdown(void); * - srtp_err_status_replay_fail rtp sequence number was non-increasing * - @e other failure in cryptographic mechanisms */ -srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, - uint8_t *rtp_hdr, - size_t *pkt_octet_len, +srtp_err_status_t srtp_protect(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, size_t mki_index); -srtp_err_status_t srtp_protect2(srtp_t ctx, - const uint8_t *rtp, - size_t rtp_len, - uint8_t *srtp, - size_t *srtp_len, - size_t mki_index); - /** * @brief srtp_unprotect() is the Secure RTP receiver-side packet * processing function. @@ -480,14 +475,10 @@ srtp_err_status_t srtp_protect2(srtp_t ctx, * */ srtp_err_status_t srtp_unprotect(srtp_t ctx, - uint8_t *srtp_hdr, - size_t *len_ptr); - -srtp_err_status_t srtp_unprotect2(srtp_t ctx, - const uint8_t *srtp, - size_t srtp_len, - uint8_t *rtp, - size_t *rtp_len); + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len); /** * @brief srtp_create() allocates and initializes an SRTP session. @@ -1161,17 +1152,12 @@ void srtp_append_salt_to_key(uint8_t *key, * the cryptographic mechanisms. */ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, - uint8_t *rtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, size_t mki_index); -srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, - const uint8_t *rtcp, - size_t rtcp_len, - uint8_t *srtcp, - size_t *srtcp_len, - size_t mki_index); - /** * @brief srtp_unprotect_rtcp() is the Secure RTCP receiver-side packet * processing function. @@ -1213,14 +1199,10 @@ srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, * */ srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, - uint8_t *srtcp_hdr, - size_t *pkt_octet_len); - -srtp_err_status_t srtp_unprotect_rtcp2(srtp_t ctx, - const uint8_t *srtcp, - size_t srtcp_len, - uint8_t *rtcp, - size_t *rtcp_len); + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len); /** * @defgroup User data associated to a SRTP session. diff --git a/srtp/srtp.c b/srtp/srtp.c index 8f440305d..da5e6e7d2 100644 --- a/srtp/srtp.c +++ b/srtp/srtp.c @@ -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; - enc_octet_len = *pkt_octet_len - (enc_start - rtp_hdr); + /* check output length */ + if (*srtp_len < rtp_len + stream->mki_size + tag_len) { + return srtp_err_status_buffer_small; + } + + /* if not-inplace then need to copy full rtp header */ + if (rtp != srtp) { + memcpy(srtp, rtp, enc_start); + } /* * estimate the packet index using the start of the replay window @@ -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, 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, 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,37 +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_protect2(srtp_t ctx, - const uint8_t *rtp, - size_t rtp_len, - uint8_t *srtp, - size_t *srtp_len, - size_t mki_index) -{ - if (*srtp_len < rtp_len) { - return srtp_err_status_bad_param; - } - memcpy(srtp, rtp, rtp_len); - *srtp_len = rtp_len; - return srtp_protect(ctx, srtp, srtp_len, mki_index); -} - -srtp_err_status_t srtp_protect(srtp_ctx_t *ctx, - uint8_t *rtp_hdr, - size_t *pkt_octet_len, +srtp_err_status_t srtp_protect(srtp_t ctx, + const uint8_t *rtp, + size_t rtp_len, + uint8_t *srtp, + size_t *srtp_len, size_t mki_index) { - srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)rtp; + size_t enc_start; /* offset to start of encrypted portion */ uint8_t *auth_start; /* pointer to start of auth. portion */ size_t enc_octet_len = 0; /* number of octets in encrypted portion */ srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ @@ -2221,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; } @@ -2294,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); } @@ -2324,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); } /* @@ -2353,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; @@ -2446,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, - enc_octet_len, enc_start, &enc_octet_len); + if (stream->rtp_services & sec_serv_conf) { + status = srtp_cipher_encrypt(session_keys->rtp_cipher, rtp + enc_start, + enc_octet_len, srtp + enc_start, + &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } + } else if (rtp != srtp) { + /* if no encryption and not-inplace then need to copy rest of packet */ + memcpy(srtp + enc_start, rtp + enc_start, enc_octet_len); } /* @@ -2473,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; } @@ -2490,43 +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_unprotect2(srtp_t ctx, - const uint8_t *srtp, - size_t srtp_len, - uint8_t *rtp, - size_t *rtp_len) -{ - if (*rtp_len < srtp_len) { - // this is actually expected but for the tests this should not happen - return srtp_err_status_bad_param; - } - memcpy(rtp, srtp, srtp_len); - *rtp_len = srtp_len; - return srtp_unprotect(ctx, rtp, rtp_len); -} - -srtp_err_status_t srtp_unprotect(srtp_ctx_t *ctx, - uint8_t *srtp_hdr, - size_t *pkt_octet_len) +srtp_err_status_t srtp_unprotect(srtp_t ctx, + const uint8_t *srtp, + size_t srtp_len, + uint8_t *rtp, + size_t *rtp_len) { - srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ - uint8_t *auth_start; /* pointer to start of auth. portion */ - size_t enc_octet_len = 0; /* number of octets in encrypted portion */ - uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ - srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ - ssize_t delta; /* delta of local pkt idx and that in hdr */ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)srtp; + size_t enc_start; /* pointer to start of encrypted portion */ + const uint8_t *auth_start; /* pointer to start of auth. portion */ + size_t enc_octet_len = 0; /* number of octets in encrypted portion */ + const uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ + ssize_t delta; /* delta of local pkt idx and that in hdr */ v128_t iv; srtp_err_status_t status; srtp_stream_ctx_t *stream; @@ -2540,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; } @@ -2602,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; } @@ -2614,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 */ @@ -2657,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); } /* @@ -2687,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; @@ -2725,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; } @@ -2768,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, 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); } /* @@ -2845,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; } @@ -3622,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 */ @@ -3636,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); @@ -3645,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 @@ -3706,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 { /* @@ -3722,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); } @@ -3731,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, 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; } @@ -3753,15 +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, - NULL, &nolen); + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, NULL, 0, NULL, + &nolen); if (status) { return srtp_err_status_cipher_fail; } @@ -3773,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; } @@ -3794,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 */ @@ -3822,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 @@ -3866,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 { /* @@ -3885,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); } @@ -3897,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, enc_start, &enc_octet_len); + if (*trailer_p & SRTCP_E_BYTE_BIT) { + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, + srtcp + enc_start, enc_octet_len, + rtcp + enc_start, &enc_octet_len); if (status) { return status; } } else { + /* if no encryption and not-inplace then need to copy rest of packet */ + if (rtcp != srtcp) { + memcpy(rtcp + enc_start, srtcp + enc_start, enc_octet_len); + } + /* * Still need to run the cipher to check the tag */ - tmp_len = tag_len; + tmp_len = 0; status = srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, - tmp_len, auth_tag, &tmp_len); + tag_len, NULL, &tmp_len); if (status) { return status; } } + *rtcp_len = srtcp_len; + /* decrease the packet length by the length of the auth tag and seq_num*/ - *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t) + stream->mki_size); + *rtcp_len -= (tag_len + sizeof(srtcp_trailer_t) + stream->mki_size); /* * verify that stream is for received traffic - this check will @@ -3982,28 +4001,15 @@ static srtp_err_status_t srtp_unprotect_rtcp_aead( return srtp_err_status_ok; } -srtp_err_status_t srtp_protect_rtcp2(srtp_t ctx, - const uint8_t *rtcp, - size_t rtcp_len, - uint8_t *srtcp, - size_t *srtcp_len, - size_t mki_index) -{ - if (*srtcp_len < rtcp_len) { - return srtp_err_status_bad_param; - } - memcpy(srtcp, rtcp, rtcp_len); - *srtcp_len = rtcp_len; - return srtp_protect_rtcp(ctx, srtcp, srtcp_len, mki_index); -} - srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, - uint8_t *rtcp_hdr, - size_t *pkt_octet_len, + const uint8_t *rtcp, + size_t rtcp_len, + uint8_t *srtcp, + size_t *srtcp_len, size_t mki_index) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)rtcp; + size_t enc_start; /* pointer to start of encrypted portion */ uint8_t *auth_start; /* pointer to start of auth. portion */ uint8_t *trailer_p; /* pointer to start of trailer */ uint32_t trailer; /* trailer value */ @@ -4017,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; } @@ -4080,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); } @@ -4088,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); } @@ -4120,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 @@ -4189,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, 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 */ @@ -4207,50 +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_rtcp2(srtp_t ctx, - const uint8_t *srtcp, - size_t srtcp_len, - uint8_t *rtcp, - size_t *rtcp_len) -{ - if (*rtcp_len < srtcp_len) { - // this is actually expected but for the tests this should not happen - return srtp_err_status_bad_param; - } - memcpy(rtcp, srtcp, srtcp_len); - *rtcp_len = srtcp_len; - return srtp_unprotect_rtcp(ctx, rtcp, rtcp_len); -} - srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, - uint8_t *srtcp_hdr, - size_t *pkt_octet_len) + const uint8_t *srtcp, + size_t srtcp_len, + uint8_t *rtcp, + size_t *rtcp_len) { - srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; - uint8_t *enc_start; /* pointer to start of encrypted portion */ - uint8_t *auth_start; /* pointer to start of auth. portion */ - uint8_t *trailer_p; /* pointer to start of trailer */ - uint32_t trailer; /* trailer value */ - size_t enc_octet_len = 0; /* number of octets in encrypted portion */ - uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ + const srtcp_hdr_t *hdr = (const srtcp_hdr_t *)srtcp; + size_t enc_start; /* pointer to start of encrypted portion */ + const uint8_t *auth_start; /* pointer to start of auth. portion */ + const uint8_t *trailer_p; /* pointer to start of trailer */ + uint32_t trailer; /* trailer value */ + size_t enc_octet_len = 0; /* number of octets in encrypted portion */ + const uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ uint8_t tmp_tag[SRTP_MAX_TAG_LEN]; srtp_err_status_t status; size_t auth_len; @@ -4267,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; } @@ -4295,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; @@ -4307,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; } @@ -4318,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 || @@ -4328,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 @@ -4444,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, 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 7adcb23b2..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]; @@ -162,26 +190,61 @@ srtp_master_key_t *test_keys[2] = { bool use_srtp_not_in_place_io_api = false; +void overrun_check_prepare(uint8_t *buffer, size_t offset, size_t buffer_len) +{ + memset(buffer + offset, 0xff, buffer_len - offset); +} + +srtp_err_status_t call_srtp_protect2(srtp_ctx_t *ctx, + uint8_t *rtp, + size_t rtp_len, + size_t *srtp_len, + size_t mki_index) +{ + srtp_err_status_t status = srtp_err_status_fail; + if (use_srtp_not_in_place_io_api) { + uint8_t in_buf[4048]; + if (rtp_len > sizeof(in_buf)) { + printf("rtp_len greater than in_buf"); + exit(1); + } + memcpy(in_buf, rtp, rtp_len); + status = srtp_protect(ctx, in_buf, rtp_len, rtp, srtp_len, mki_index); + } else { + status = srtp_protect(ctx, rtp, rtp_len, rtp, srtp_len, mki_index); + } + return status; +} + srtp_err_status_t call_srtp_protect(srtp_ctx_t *ctx, uint8_t *rtp, size_t *rtp_len, size_t mki_index) +{ + // an assumption + size_t srtp_len = *rtp_len + SRTP_MAX_TRAILER_LEN; + srtp_err_status_t status = + call_srtp_protect2(ctx, rtp, *rtp_len, &srtp_len, mki_index); + *rtp_len = srtp_len; + return status; +} + +srtp_err_status_t call_srtp_unprotect2(srtp_ctx_t *ctx, + uint8_t *srtp, + size_t srtp_len, + size_t *rtp_len) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*rtp_len > sizeof(in_buf)) { - printf("rtp_len greater than in_buf"); + if (srtp_len > sizeof(in_buf)) { + printf("srtp_len greater than in_buf"); exit(1); } - memcpy(in_buf, rtp, *rtp_len); - // an assumption - size_t srtp_len = *rtp_len + SRTP_MAX_TRAILER_LEN; - status = - srtp_protect2(ctx, in_buf, *rtp_len, rtp, &srtp_len, mki_index); - *rtp_len = srtp_len; + memcpy(in_buf, srtp, srtp_len); + status = srtp_unprotect(ctx, in_buf, srtp_len, srtp, rtp_len); } else { - status = srtp_protect(ctx, rtp, rtp_len, mki_index); + status = srtp_unprotect(ctx, srtp, srtp_len, srtp, rtp_len); } return status; } @@ -189,18 +252,29 @@ srtp_err_status_t call_srtp_protect(srtp_ctx_t *ctx, srtp_err_status_t call_srtp_unprotect(srtp_ctx_t *ctx, uint8_t *srtp, size_t *srtp_len) +{ + return call_srtp_unprotect2(ctx, srtp, *srtp_len, srtp_len); +} + +srtp_err_status_t call_srtp_protect_rtcp2(srtp_ctx_t *ctx, + uint8_t *rtcp, + size_t rtcp_len, + size_t *srtcp_len, + size_t mki_index) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*srtp_len > sizeof(in_buf)) { - printf("srtp_len greater than in_buf"); + if (rtcp_len > sizeof(in_buf)) { + printf("rtcp_len greater than in_buf"); exit(1); } - memcpy(in_buf, srtp, *srtp_len); - status = srtp_unprotect2(ctx, in_buf, *srtp_len, srtp, srtp_len); + memcpy(in_buf, rtcp, rtcp_len); + status = srtp_protect_rtcp(ctx, in_buf, rtcp_len, rtcp, srtcp_len, + mki_index); } else { - status = srtp_unprotect(ctx, srtp, srtp_len); + status = + srtp_protect_rtcp(ctx, rtcp, rtcp_len, rtcp, srtcp_len, mki_index); } return status; } @@ -209,22 +283,31 @@ srtp_err_status_t call_srtp_protect_rtcp(srtp_ctx_t *ctx, uint8_t *rtcp, size_t *rtcp_len, size_t mki_index) +{ + // an assumption + size_t srtcp_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN; + srtp_err_status_t status = + call_srtp_protect_rtcp2(ctx, rtcp, *rtcp_len, &srtcp_len, mki_index); + *rtcp_len = srtcp_len; + return status; +} + +srtp_err_status_t call_srtp_unprotect_rtcp2(srtp_ctx_t *ctx, + uint8_t *srtcp, + size_t srtcp_len, + size_t *rtcp_len) { srtp_err_status_t status = srtp_err_status_fail; if (use_srtp_not_in_place_io_api) { uint8_t in_buf[4048]; - if (*rtcp_len > sizeof(in_buf)) { - printf("rtcp_len greater than in_buf"); + if (srtcp_len > sizeof(in_buf)) { + printf("srtcp_len greater than in_buf"); exit(1); } - memcpy(in_buf, rtcp, *rtcp_len); - // an assumption - size_t srtcp_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN; - status = srtp_protect_rtcp2(ctx, in_buf, *rtcp_len, rtcp, &srtcp_len, - mki_index); - *rtcp_len = srtcp_len; + memcpy(in_buf, srtcp, srtcp_len); + status = srtp_unprotect_rtcp(ctx, in_buf, srtcp_len, srtcp, rtcp_len); } else { - status = srtp_protect_rtcp(ctx, rtcp, rtcp_len, mki_index); + status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len, srtcp, rtcp_len); } return status; } @@ -233,20 +316,7 @@ srtp_err_status_t call_srtp_unprotect_rtcp(srtp_ctx_t *ctx, uint8_t *srtcp, size_t *srtcp_len) { - srtp_err_status_t status = srtp_err_status_fail; - if (use_srtp_not_in_place_io_api) { - uint8_t in_buf[4048]; - if (*srtcp_len > sizeof(in_buf)) { - printf("srtcp_len greater than in_buf"); - exit(1); - } - memcpy(in_buf, srtcp, *srtcp_len); - status = - srtp_unprotect_rtcp2(ctx, in_buf, *srtcp_len, srtcp, srtcp_len); - } else { - status = srtp_unprotect_rtcp(ctx, srtcp, srtcp_len); - } - return status; + return call_srtp_unprotect_rtcp2(ctx, srtcp, *srtcp_len, srtcp_len); } void usage(char *prog_name) @@ -432,6 +502,15 @@ int main(int argc, char *argv[]) exit(1); } + printf("testing srtp_protect and srtp_unprotect io lengths\n"); + if (srtp_test_io_lengths(*policy, false, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect and srtp_unprotect with encrypted " "extensions headers\n"); if (srtp_test(*policy, true, false, 0) == srtp_err_status_ok) { @@ -440,6 +519,17 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect and srtp_unprotect io lengths with " + "encrypted extension headers\n"); + if (srtp_test_io_lengths(*policy, true, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n"); if (srtcp_test(*policy, false, 0) == srtp_err_status_ok) { printf("passed\n\n"); @@ -447,6 +537,17 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp io " + "lengths\n"); + if (srtcp_test_io_lengths(*policy, false, 0) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtp and srtp_unprotect_rtp with MKI " "index set to 0\n"); if (srtp_test(*policy, false, true, 0) == srtp_err_status_ok) { @@ -464,6 +565,16 @@ int main(int argc, char *argv[]) exit(1); } + printf("testing srtp_protect and srtp_unprotect io lengths with " + "MKI\n"); + if (srtp_test_io_lengths(*policy, false, true, 1) == + srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI " "index set to 0\n"); if (srtcp_test(*policy, true, 0) == srtp_err_status_ok) { @@ -472,6 +583,7 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI " "index set to 1\n"); if (srtcp_test(*policy, true, 1) == srtp_err_status_ok) { @@ -480,6 +592,16 @@ int main(int argc, char *argv[]) printf("failed\n"); exit(1); } + + printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp io " + "lengths with MKI\n"); + if (srtcp_test_io_lengths(*policy, true, 1) == srtp_err_status_ok) { + printf("passed\n\n"); + } else { + printf("failed\n"); + exit(1); + } + policy++; } @@ -819,6 +941,60 @@ int main(int argc, char *argv[]) return 0; } +uint8_t *create_rtp_test_packet(size_t payload_len, + uint32_t ssrc, + uint16_t seq, + uint32_t ts, + bool add_hdr_xtn, + size_t *rtp_len, + size_t *buffer_len) +{ + uint8_t *buffer; + srtp_hdr_t *hdr; + size_t bytes_in_hdr = 12; + + *rtp_len = payload_len + bytes_in_hdr; + + if (add_hdr_xtn) { + *rtp_len += sizeof(rtp_test_packet_extension_header); + } + + // allocate enough for max trailer and 4 byte overrun detection + *buffer_len = *rtp_len + SRTP_MAX_TRAILER_LEN + 4; + + buffer = (uint8_t *)malloc(*buffer_len); + if (!buffer) { + printf("rtp test packet allocation failed\n"); + exit(1); + } + + overrun_check_prepare(buffer, 0, *buffer_len); + + hdr = (srtp_hdr_t *)buffer; + hdr->version = 2; + hdr->p = 0; + hdr->x = add_hdr_xtn ? 1 : 0; + hdr->cc = 0; + hdr->m = 0; + hdr->pt = 0xf; + hdr->seq = htons(seq); + hdr->ts = htonl(ts); + hdr->ssrc = htonl(ssrc); + buffer += bytes_in_hdr; + + if (add_hdr_xtn) { + memcpy(buffer, rtp_test_packet_extension_header, + sizeof(rtp_test_packet_extension_header)); + buffer += sizeof(rtp_test_packet_extension_header); + } + + /* set RTP data to 0xab */ + memset(buffer, 0xab, payload_len); + buffer += payload_len; + + return buffer - *rtp_len; +} + /* * srtp_create_test_packet(len, ssrc) returns a pointer to a * (malloced) example RTP packet whose data field has the length given @@ -836,168 +1012,75 @@ uint8_t *srtp_create_test_packet(size_t pkt_octet_len, uint32_t ssrc, size_t *pkt_len) { - size_t i; - uint8_t *buffer; - srtp_hdr_t *hdr; - size_t bytes_in_hdr = 12; - - /* allocate memory for test packet */ - hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - SRTP_MAX_TRAILER_LEN + 4); - if (!hdr) { - return NULL; - } - - hdr->version = 2; /* RTP version two */ - hdr->p = 0; /* no padding needed */ - hdr->x = 0; /* no header extension */ - hdr->cc = 0; /* no CSRCs */ - hdr->m = 0; /* marker bit */ - hdr->pt = 0xf; /* payload type */ - hdr->seq = htons(0x1234); /* sequence number */ - hdr->ts = htonl(0xdecafbad); /* timestamp */ - hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; - buffer += bytes_in_hdr; - - /* set RTP data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } - - *pkt_len = bytes_in_hdr + pkt_octet_len; - - return (uint8_t *)hdr; + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, 0x1234, 0x87654321, + false, pkt_len, &buffer_len); } -uint8_t *srtp_create_rtcp_test_packet(size_t pkt_octet_len, - uint32_t ssrc, - size_t *pkt_len) +uint8_t *create_rtcp_test_packet(size_t payload_len, + uint32_t ssrc, + size_t *rtcp_len, + size_t *buffer_len) { - size_t i; uint8_t *buffer; srtcp_hdr_t *hdr; size_t bytes_in_hdr = 8; - /* allocate memory for test packet */ - hdr = (srtcp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - SRTP_MAX_SRTCP_TRAILER_LEN + 4); - if (!hdr) { - return NULL; + *rtcp_len = payload_len + bytes_in_hdr; + + // allocate enough for max trailer and 4 byte overrun detection + *buffer_len = *rtcp_len + SRTP_MAX_SRTCP_TRAILER_LEN + 4; + + buffer = (uint8_t *)malloc(*buffer_len); + if (!buffer) { + printf("rtcp test packet allocation failed\n"); + exit(1); } + overrun_check_prepare(buffer, 0, *buffer_len); + + hdr = (srtcp_hdr_t *)buffer; hdr->version = 2; /* RTP version two */ hdr->p = 0; /* no padding needed */ hdr->rc = 0; /* no reports */ hdr->pt = 0xc8; /* sender report (200) */ - hdr->len = ((bytes_in_hdr + pkt_octet_len) % 4) - 1; + hdr->len = ((bytes_in_hdr + payload_len) % 4) - 1; hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; buffer += bytes_in_hdr; /* set data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_SRTCP_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } + memset(buffer, 0xab, payload_len); + buffer += payload_len; - *pkt_len = bytes_in_hdr + pkt_octet_len; - - return (uint8_t *)hdr; + return buffer - *rtcp_len; } -static uint8_t *srtp_create_test_packet_extended(size_t pkt_octet_len, - uint32_t ssrc, - uint16_t seq, - uint32_t ts, - size_t *pkt_len) +uint8_t *srtp_create_rtcp_test_packet(size_t pkt_octet_len, + uint32_t ssrc, + size_t *pkt_len) { - srtp_hdr_t *hdr; - - hdr = (srtp_hdr_t *)srtp_create_test_packet(pkt_octet_len, ssrc, pkt_len); - if (hdr == NULL) { - return NULL; - } + size_t buffer_len; + return create_rtcp_test_packet(pkt_octet_len, ssrc, pkt_len, &buffer_len); +} - hdr->seq = htons(seq); - hdr->ts = htonl(ts); - return (uint8_t *)hdr; +uint8_t *srtp_create_test_packet_extended(size_t pkt_octet_len, + uint32_t ssrc, + uint16_t seq, + uint32_t ts, + size_t *pkt_len) +{ + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, seq, ts, false, pkt_len, + &buffer_len); } uint8_t *srtp_create_test_packet_ext_hdr(size_t pkt_octet_len, uint32_t ssrc, size_t *pkt_len) { - size_t i; - uint8_t *buffer; - srtp_hdr_t *hdr; - size_t bytes_in_hdr = 12; - uint8_t extension_header[12] = { /* one-byte header */ - 0xbe, 0xde, - /* size */ - 0x00, 0x02, - /* id 1, length 1 (i.e. 2 bytes) */ - 0x11, - /* payload */ - 0xca, 0xfe, - /* padding */ - 0x00, - /* id 2, length 0 (i.e. 1 byte) */ - 0x20, - /* payload */ - 0xba, - /* padding */ - 0x00, 0x00 - }; - - /* allocate memory for test packet */ - hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr + - sizeof(extension_header) + SRTP_MAX_TRAILER_LEN + - 4); - if (!hdr) { - return NULL; - } - - hdr->version = 2; /* RTP version two */ - hdr->p = 0; /* no padding needed */ - hdr->x = 1; /* no header extension */ - hdr->cc = 0; /* no CSRCs */ - hdr->m = 0; /* marker bit */ - hdr->pt = 0xf; /* payload type */ - hdr->seq = htons(0x1234); /* sequence number */ - hdr->ts = htonl(0xdecafbad); /* timestamp */ - hdr->ssrc = htonl(ssrc); /* synch. source */ - - buffer = (uint8_t *)hdr; - buffer += bytes_in_hdr; - - memcpy(buffer, extension_header, sizeof(extension_header)); - buffer += sizeof(extension_header); - - /* set RTP data to 0xab */ - for (i = 0; i < pkt_octet_len; i++) { - *buffer++ = 0xab; - } - - /* set post-data value to 0xffff to enable overrun checking */ - for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++) { - *buffer++ = 0xff; - } - - *pkt_len = bytes_in_hdr + sizeof(extension_header) + pkt_octet_len; - - return (uint8_t *)hdr; + size_t buffer_len; + return create_rtp_test_packet(pkt_octet_len, ssrc, 0x1234, 0x87654321, true, + pkt_len, &buffer_len); } void srtp_do_timing(const srtp_policy_t *policy) @@ -1164,6 +1247,82 @@ void err_check(srtp_err_status_t s) } } +void check_ok(srtp_err_status_t s, const char *msg) +{ + if (s != srtp_err_status_ok) { + fprintf(stderr, "error: unexpected srtp failure (code %d) - %s\n", s, + msg); + exit(1); + } +} + +void check_return(srtp_err_status_t actual, + srtp_err_status_t expected, + const char *msg) +{ + if (actual != expected) { + fprintf(stderr, "error: unexpected srtp status (code %d != %d) - %s\n", + actual, expected, msg); + exit(1); + } +} + +void check_ok_impl(srtp_err_status_t status, const char *file, int line) +{ + if (status != srtp_err_status_ok) { + fprintf(stderr, "error at %s:%d, unexpected srtp failure (code %d)\n", + file, line, status); + exit(1); + } +} + +void check_return_impl(srtp_err_status_t status, + srtp_err_status_t expected, + const char *file, + int line) +{ + if (status != expected) { + fprintf(stderr, + "error at %s:%d, unexpected srtp status (code %d != %d)\n", + file, line, status, expected); + exit(1); + } +} + +void check_impl(bool condition, + const char *file, + int line, + const char *condition_str) +{ + if (!condition) { + fprintf(stderr, "error at %s:%d, %s)\n", file, line, condition_str); + exit(1); + } +} + +void check_overrun_impl(const uint8_t *buffer, + size_t offset, + size_t buffer_length, + const char *file, + int line) +{ + for (size_t i = offset; i < buffer_length; i++) { + if (buffer[i] != 0xff) { + printf("error at %s:%d, overrun detected in buffer at index %zu " + "(expected %x, found %x)\n", + file, line, i, 0xff, buffer[i]); + exit(1); + } + } +} + +#define CHECK_OK(status) check_ok_impl((status), __FILE__, __LINE__) +#define CHECK_RETURN(status, expected) \ + check_return_impl((status), (expected), __FILE__, __LINE__) +#define CHECK(condition) check_impl((condition), __FILE__, __LINE__, #condition) +#define CHECK_OVERRUN(buffer, offset, length) \ + check_overrun_impl((buffer), (offset), (length), __FILE__, __LINE__) + srtp_err_status_t srtp_test(const srtp_policy_t *policy, bool test_extension_headers, bool use_mki, @@ -1374,6 +1533,211 @@ srtp_err_status_t srtp_test(const srtp_policy_t *policy, return srtp_err_status_ok; } +srtp_err_status_t srtp_test_io_lengths(const srtp_policy_t *policy, + bool test_extension_headers, + bool use_mki, + size_t mki_index) +{ + srtp_t srtp_sender; + srtp_policy_t send_policy; + uint32_t ssrc; + uint16_t seq = 1; + uint32_t ts = 1234; + uint8_t *rtp; + size_t rtp_len, buffer_len, srtp_len; + size_t rtp_header_len = 12; + uint8_t xtn_header_id = 1; + + memcpy(&send_policy, policy, sizeof(srtp_policy_t)); + + send_policy.use_mki = use_mki; + if (!use_mki) { + send_policy.mki_size = 0; + } + + if (test_extension_headers) { + send_policy.enc_xtn_hdr = &xtn_header_id; + send_policy.enc_xtn_hdr_count = 1; + rtp_header_len += sizeof(rtp_test_packet_extension_header); + } + + CHECK_OK(srtp_create(&srtp_sender, &send_policy)); + + // get required trailer length + size_t trailer_len; + CHECK_OK( + srtp_get_protect_trailer_length(srtp_sender, mki_index, &trailer_len)); + + CHECK_OK(srtp_session_print_policy(srtp_sender)); + + if (policy->ssrc.type != ssrc_specific) { + ssrc = 0xdecafbad; + } else { + ssrc = policy->ssrc.value; + } + + // 0 byte input + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, 0, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, 0, &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, 0, buffer_len); + free(rtp); + + // 1 byte input + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, 1, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, 1, &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, 1, buffer_len); + free(rtp); + + // too short header + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len - 1, buffer_len); + CHECK_RETURN(call_srtp_protect2(srtp_sender, rtp, rtp_header_len - 1, + &srtp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtp, rtp_header_len - 1, buffer_len); + free(rtp); + + // zero payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len, buffer_len); + CHECK_OK(call_srtp_protect2(srtp_sender, rtp, rtp_header_len, &srtp_len, + mki_index)); + CHECK(srtp_len == rtp_header_len + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + free(rtp); + + // 1 byte payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + overrun_check_prepare(rtp, rtp_header_len + 1, buffer_len); + CHECK_OK(call_srtp_protect2(srtp_sender, rtp, rtp_header_len + 1, &srtp_len, + mki_index)); + CHECK(srtp_len == rtp_header_len + 1 + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + free(rtp); + + // 0 byte output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = 0; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + // 1 byte output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = 1; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + if (trailer_len != 0) { + // no space for trailer output + rtp = create_rtp_test_packet( + 28, ssrc, seq++, ts, test_extension_headers, &rtp_len, &buffer_len); + srtp_len = rtp_len; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + } + + // 1 byte too small output + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = rtp_len + trailer_len - 1; + overrun_check_prepare(rtp, rtp_len, buffer_len); + CHECK_RETURN( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtp, rtp_len, buffer_len); + free(rtp); + + // full payload + rtp = create_rtp_test_packet(28, ssrc, seq++, ts, test_extension_headers, + &rtp_len, &buffer_len); + srtp_len = buffer_len; + CHECK_OK( + call_srtp_protect2(srtp_sender, rtp, rtp_len, &srtp_len, mki_index)); + CHECK(srtp_len == rtp_len + trailer_len); + CHECK_OVERRUN(rtp, srtp_len, buffer_len); + + CHECK_OK(srtp_dealloc(srtp_sender)); + + // unprotect + srtp_t srtp_receiver; + srtp_policy_t receive_policy; + + memcpy(&receive_policy, &send_policy, sizeof(srtp_policy_t)); + receive_policy.ssrc.type = ssrc_any_inbound; + + CHECK_OK(srtp_create(&srtp_receiver, &receive_policy)); + + // unprotect zero byte input + rtp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, 0, &rtp_len), + srtp_err_status_bad_param); + + // unprotect 1 byte input + rtp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, 1, &rtp_len), + srtp_err_status_bad_param); + + // unprotect short header + rtp_len = buffer_len; + CHECK_RETURN( + call_srtp_unprotect2(srtp_receiver, rtp, rtp_header_len - 1, &rtp_len), + srtp_err_status_bad_param); + + // 0 byte output + rtp_len = 0; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // 1 byte output + rtp_len = 1; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // 1 byte too small output + rtp_len = srtp_len - trailer_len - 1; + CHECK_RETURN(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len), + srtp_err_status_buffer_small); + + // full unprotect + rtp_len = buffer_len; + CHECK_OK(call_srtp_unprotect2(srtp_receiver, rtp, srtp_len, &rtp_len)); + CHECK(rtp_len == srtp_len - trailer_len); + + free(rtp); + + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} + srtp_err_status_t srtcp_test(const srtp_policy_t *policy, bool use_mki, size_t mki_index) @@ -1567,6 +1931,197 @@ srtp_err_status_t srtcp_test(const srtp_policy_t *policy, return srtp_err_status_ok; } +srtp_err_status_t srtcp_test_io_lengths(const srtp_policy_t *policy, + bool use_mki, + size_t mki_index) +{ + srtp_t srtp_sender; + srtp_policy_t send_policy; + uint32_t ssrc; + uint8_t *rtcp; + size_t rtcp_len, buffer_len, srtcp_len; + size_t rtcp_header_len = 8; + + memcpy(&send_policy, policy, sizeof(srtp_policy_t)); + + send_policy.use_mki = use_mki; + if (!use_mki) { + send_policy.mki_size = 0; + } + + CHECK_OK(srtp_create(&srtp_sender, &send_policy)); + + // get required trailer length + size_t trailer_len; + CHECK_OK(srtp_get_protect_rtcp_trailer_length(srtp_sender, mki_index, + &trailer_len)); + + CHECK_OK(srtp_session_print_policy(srtp_sender)); + + if (policy->ssrc.type != ssrc_specific) { + ssrc = 0xdecafbad; + } else { + ssrc = policy->ssrc.value; + } + + // 0 byte input + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, 0, buffer_len); + CHECK_RETURN( + call_srtp_protect_rtcp2(srtp_sender, rtcp, 0, &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, 0, buffer_len); + free(rtcp); + + // 1 byte input + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, 1, buffer_len); + CHECK_RETURN( + call_srtp_protect_rtcp2(srtp_sender, rtcp, 1, &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, 1, buffer_len); + free(rtcp); + + // too short header + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len - 1, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len - 1, + &srtcp_len, mki_index), + srtp_err_status_bad_param); + CHECK_OVERRUN(rtcp, rtcp_header_len - 1, buffer_len); + free(rtcp); + + // zero payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len, buffer_len); + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len, + &srtcp_len, mki_index)); + CHECK(srtcp_len == rtcp_header_len + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + free(rtcp); + + // 1 byte payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + overrun_check_prepare(rtcp, rtcp_header_len + 1, buffer_len); + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_header_len + 1, + &srtcp_len, mki_index)); + CHECK(srtcp_len == rtcp_header_len + 1 + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + free(rtcp); + + // 0 byte output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = 0; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + // 1 byte output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = 1; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + if (trailer_len != 0) { + // no space for trailer output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = rtcp_len; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + } + + // 1 byte too small output + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = rtcp_len + trailer_len - 1; + overrun_check_prepare(rtcp, rtcp_len, buffer_len); + CHECK_RETURN(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, + &srtcp_len, mki_index), + srtp_err_status_buffer_small); + CHECK_OVERRUN(rtcp, rtcp_len, buffer_len); + free(rtcp); + + // full payload + rtcp = create_rtcp_test_packet(28, ssrc, &rtcp_len, &buffer_len); + srtcp_len = buffer_len; + CHECK_OK(call_srtp_protect_rtcp2(srtp_sender, rtcp, rtcp_len, &srtcp_len, + mki_index)); + CHECK(srtcp_len == rtcp_len + trailer_len); + CHECK_OVERRUN(rtcp, srtcp_len, buffer_len); + + CHECK_OK(srtp_dealloc(srtp_sender)); + + // unprotect + srtp_t srtp_receiver; + srtp_policy_t receive_policy; + + memcpy(&receive_policy, &send_policy, sizeof(srtp_policy_t)); + receive_policy.ssrc.type = ssrc_any_inbound; + + CHECK_OK(srtp_create(&srtp_receiver, &receive_policy)); + + // unprotect zero byte input + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, 0, &rtcp_len), + srtp_err_status_bad_param); + + // unprotect 1 byte input + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, 1, &rtcp_len), + srtp_err_status_bad_param); + + // unprotect short header + rtcp_len = buffer_len; + CHECK_RETURN(call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, + rtcp_header_len - 1, &rtcp_len), + srtp_err_status_bad_param); + + // 0 byte output + rtcp_len = 0; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // 1 byte output + rtcp_len = 1; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // 1 byte too small output + rtcp_len = srtcp_len - trailer_len - 1; + CHECK_RETURN( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len), + srtp_err_status_buffer_small); + + // full unprotect + rtcp_len = buffer_len; + CHECK_OK( + call_srtp_unprotect_rtcp2(srtp_receiver, rtcp, srtcp_len, &rtcp_len)); + CHECK(rtcp_len == srtcp_len - trailer_len); + + free(rtcp); + + CHECK_OK(srtp_dealloc(srtp_receiver)); + + return srtp_err_status_ok; +} + struct srtp_session_print_stream_data { // set by callback to indicate failure srtp_err_status_t status; From 00b888de602f5ca491432b00dc487e152ad82f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Sun, 5 May 2024 11:26:29 +0200 Subject: [PATCH 4/8] update wolfssl to support not-in-place io --- crypto/cipher/aes_gcm_wssl.c | 31 ++++++++++++++++++------------- crypto/cipher/aes_icm_wssl.c | 9 ++++++--- 2 files changed, 24 insertions(+), 16 deletions(-) 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_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; } From 0a0dff66263e4d08e0a708e28267c121d4ec4e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Thu, 23 May 2024 22:11:56 +0200 Subject: [PATCH 5/8] Update api documentation for not in-place io Also update the minimal code example in README.md to reflect the new api. --- README.md | 10 ++-- include/srtp.h | 136 ++++++++++++++++++++++++++----------------------- 2 files changed, 78 insertions(+), 68 deletions(-) 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/include/srtp.h b/include/srtp.h index 86b3ecfed..f5d872f08 100644 --- a/include/srtp.h +++ b/include/srtp.h @@ -387,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. * @@ -398,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 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 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_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. @@ -424,6 +423,8 @@ 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_t ctx, @@ -437,11 +438,11 @@ srtp_err_status_t srtp_protect(srtp_t ctx, * @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. * @@ -454,15 +455,19 @@ srtp_err_status_t srtp_protect(srtp_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 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 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 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. @@ -1115,39 +1120,39 @@ 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 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 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 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. */ @@ -1162,11 +1167,11 @@ srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, * @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. * @@ -1176,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. From 327bdc2e05d72de8404a8ac5eb846c80a08c5efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Sun, 26 May 2024 23:29:46 +0200 Subject: [PATCH 6/8] add length check of dst buffer to aes icm encrypt --- crypto/cipher/aes_icm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crypto/cipher/aes_icm.c b/crypto/cipher/aes_icm.c index a612edc2d..fea79f019 100644 --- a/crypto/cipher/aes_icm.c +++ b/crypto/cipher/aes_icm.c @@ -305,7 +305,10 @@ static srtp_err_status_t srtp_aes_icm_encrypt(void *cv, uint32_t *b; const uint32_t *s; - // check out length if not equal or greater bail! + if (*dst_len < src_len) { + return srtp_err_status_buffer_small; + } + *dst_len = src_len; unsigned char *buf = dst; From 01b87044eb2ce1d58a0c2f39884c52bf7a2c1f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Sun, 26 May 2024 23:34:58 +0200 Subject: [PATCH 7/8] remove unnecessary assumption about the size of dst With the new api the full length of dst is now passed in, if it is too small it should fail. --- crypto/cipher/aes_gcm_nss.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crypto/cipher/aes_gcm_nss.c b/crypto/cipher/aes_gcm_nss.c index 68e8685c9..c3c3647ae 100644 --- a/crypto/cipher/aes_gcm_nss.c +++ b/crypto/cipher/aes_gcm_nss.c @@ -337,12 +337,6 @@ static srtp_err_status_t srtp_aes_gcm_nss_encrypt(void *cv, { srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; - //#todo, this might need som looking at - // nss requires space for tag, currently we assume that ther is space, this - // should change, the best would be to merge the cipher encrypt and get_tag - // api - *dst_len += 16; - // 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, // even though there's no data, we need to give NSS a buffer From 703f2e9b71c377624cbb03949a721b63429c279f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20B=C3=BChler?= Date: Tue, 11 Jun 2024 21:11:38 +0200 Subject: [PATCH 8/8] explicitly check dst len is >= tag size This is a safety check to ensure we do not wrap dst len when removing tag size. All of this code would get much cleaner if the tag could just be returned instead of cached. see #714 --- crypto/cipher/aes_gcm_nss.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crypto/cipher/aes_gcm_nss.c b/crypto/cipher/aes_gcm_nss.c index c3c3647ae..db17b918b 100644 --- a/crypto/cipher/aes_gcm_nss.c +++ b/crypto/cipher/aes_gcm_nss.c @@ -337,8 +337,8 @@ static srtp_err_status_t srtp_aes_gcm_nss_encrypt(void *cv, { 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. @@ -359,6 +359,10 @@ static srtp_err_status_t srtp_aes_gcm_nss_encrypt(void *cv, return status; } + 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;