diff --git a/third_party/libsrtp/moz.yaml b/third_party/libsrtp/moz.yaml --- a/third_party/libsrtp/moz.yaml +++ b/third_party/libsrtp/moz.yaml @@ -10,12 +10,12 @@ url: "https://github.com/cisco/libsrtp/" license: BSD-3-Clause license-file: LICENSE - release: v2.4.2 (2021-09-20T16:10:47+02:00). - revision: v2.4.2 + release: v2.7.0 (2025-03-11T23:03:18+01:00). + revision: v2.7.0 updatebot: maintainer-phab: jesup maintainer-bz: rjesup@jesup.org diff --git a/third_party/libsrtp/src/CHANGES b/third_party/libsrtp/src/CHANGES --- a/third_party/libsrtp/src/CHANGES +++ b/third_party/libsrtp/src/CHANGES @@ -1,24 +1,86 @@ Changelog -2.4.2 +2.7.0 + +#746 - Fix function signature mismatch for srtp_remove_stream + +#733 - Fix srtp_unprotect_rtcp_mki when RTP auth != RTCP + +2.6.0 + +#667 - remove use of pointers to 32bit values + +#666 - Cleaning up cmake and enabled more warnings. + +#665 - start using const on internal arguments + +#662 - Some srtp_driver fixes + +#661 - remove travis reference from README.md -#563 - Fix typo introduced by PR 559 +#660 - meson.build: implement mbedtls support + +#649 - iv length is constant so set only once + +#507 - Add x86 SIMD optimizations to crypto datatypes + +#643 - Add a missing typedef for stream list ctx + +#641 - cmake: Rename TEST_APPS as LIBSRTP_TEST_APPS option + +#640 - cmake: Support configuring as subproject + +2.5.0 + +#636 - Make mbedtls hmac less restrictive in line with RFC and library capabilities + +#612 - Allow overriding stream list implementation -2.4.1 +#629 - update min openssl version to 1.1.0 + +#602 - Openssl 3 support for EVP MAC + +#628 - Add android build to CI + +#616 - add CIFuzz Github action to workflows + +#621 - Add policy_set_aes_cm_192_xxx symbols to def file + +#617 - Use current directions in stream update test + +#614 - Call `set_aad` and `get_tag` in AEAD performance tests + +#611 - Create alias for srtp2 as libSRTP::srtp2 + +#593 - Remove compatibility code for legacy OpenSSL to fix LibreSSL build -Major changes +#573 - Export CMake Targets + +#586 - Avoid initializing local char table when converting nibble to hex + +#591 - EVP_CIPHER_CTX_cleanup() is deprecated in OpenSSL 1.1.0 + +#589 - Correct null cipher key sizes and be more defensive -#560 - Merge PR 559, Use a full-length key even with null ciphers +#570 - Include directory should point to 'include' not to 'include/srtp2' + +#551 - Count blocks instead of bytes in AES-ICM limit computation + +#561 - Rtp decoder support ssrc and roc + +#559 - Use a full-length key even with null ciphers + +#558 - Fix set ROC functionality with gcm 2.4.0 Major changes #529 - Remove EKT files, this was never completed and the draft has since changed. -#512 - Adds suport for Mbedtls as a crypto backend. +#512 - Adds support for Mbedtls as a crypto backend. #503 - Support apple silicon build. #495 - Adds support for the Meson build system. This is an alternative to Cmake and auto tools. @@ -62,11 +124,11 @@ Major changes A fuzzer was added to the project based on libFuzzer. This is run as part of Google oss-fuzz, the current status can be found at https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libsrtp . Details available in PR #442 and issue #393. -CMake support was added as an alternative build system. This was primarily added to replace the Visual Studio project files currently checked in but has been extend to support building on all platforms. Initial PR #449 and #455 but has been support has been continuously improved. +CMake support was added as an alternative build system. This was primarily added to replace the Visual Studio project files currently checked in but has been extend to support building on all platforms. Initial PR #449 and #455 but has been support has been continuously improved. NSS support for crypto backend was added. This is can be used as an alternative to openssl. Initial PR #413 but there has been numerous improvements. Other changes diff --git a/third_party/libsrtp/src/README.md b/third_party/libsrtp/src/README.md --- a/third_party/libsrtp/src/README.md +++ b/third_party/libsrtp/src/README.md @@ -1,7 +1,7 @@ [![CMake Build](https://github.com/cisco/libsrtp/actions/workflows/cmake.yml/badge.svg)](https://github.com/cisco/libsrtp/actions/workflows/cmake.yml) -[![Build Status](https://travis-ci.org/cisco/libsrtp.svg?branch=master)](https://travis-ci.org/cisco/libsrtp) +[![Autotools Build](https://github.com/cisco/libsrtp/actions/workflows/autotools.yml/badge.svg)](https://github.com/cisco/libsrtp/actions/workflows/autotools.yml) [![Coverity Scan Build Status](https://scan.coverity.com/projects/14274/badge.svg)](https://scan.coverity.com/projects/cisco-libsrtp) [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#libsrtp) # Introduction to libSRTP @@ -210,22 +210,32 @@ - key derivation rates other than zero, - the cipher F8, - the use of the packet index to select between master keys. -The user should be aware that it is possible to misuse this libary, +The user should be aware that it is possible to misuse this library, and that the result may be that the security level it provides is inadequate. If you are implementing a feature using this library, you will want to read the Security Considerations section of [RFC 3711](https://tools.ietf.org/html/rfc3711#section-9). In addition, it is important that you read and understand the terms outlined in the [License and Disclaimer](#license-and-disclaimer) section. +This library also supports the AES-GCM Authenticated Encryption methods +described in [RFC 7714](https://tools.ietf.org/html/rfc7714) + -------------------------------------------------------------------------------- ## Implementation Notes + * It is possible to configure which 3rd party (ie openssl/nss/etc) crypto backend + libSRTP will be built with. If no 3rd party backend is set then libSRTP provides + an internal implementation of AES and Sha1. The internal implementation only + 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 is not valid, memory corruption will ensue. @@ -280,15 +290,17 @@ Option | Description -------------------------------|-------------------- \-\-help \-h | Display help \-\-enable-debug-logging | Enable debug logging in all modules -\-\-enable-log-stdout | Enable logging to stdout \-\-enable-openssl | Enable OpenSSL crypto engine +\-\-enable-nss | Enable NSS crypto engine \-\-enable-openssl-kdf | Enable OpenSSL KDF algorithm +\-\-enable-log-stdout | Enable logging to stdout +\-\-with-openssl-dir | Location of OpenSSL installation +\-\-with-nss-dir | Location of NSS installation \-\-with-log-file | Use file for logging -\-\-with-openssl-dir | Location of OpenSSL installation By default there is no log output, logging can be enabled to be output to stdout or a given file using the configure options. This package has been tested on the following platforms: Mac OS X @@ -338,11 +350,11 @@ -------------------------------------------------------------------------------- ## Using Meson -On all platforms including Windows, one can build using [Meson](https://mesonbuild.org). +On all platforms including Windows, one can build using [Meson](https://mesonbuild.com). Steps to download Meson are here: https://mesonbuild.com/Getting-meson.html To build with Meson, you can do something like: ``` diff --git a/third_party/libsrtp/src/crypto/.cvsignore b/third_party/libsrtp/src/crypto/.cvsignore deleted file mode 100644 --- a/third_party/libsrtp/src/crypto/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -Makefile diff --git a/third_party/libsrtp/src/crypto/cipher/aes.c b/third_party/libsrtp/src/crypto/cipher/aes.c --- a/third_party/libsrtp/src/crypto/cipher/aes.c +++ b/third_party/libsrtp/src/crypto/cipher/aes.c @@ -1816,12 +1816,12 @@ static inline void aes_inv_round(v128_t *state, const v128_t *round_key) { uint32_t column0, column1, column2, column3; -/* compute the columns of the output square in terms of the octets - of state, using the tables U0, U1, U2, U3 */ + /* compute the columns of the output square in terms of the octets + of state, using the tables U0, U1, U2, U3 */ #ifdef WORDS_BIGENDIAN column0 = U0[state->v32[0] >> 24] ^ U1[(state->v32[3] >> 16) & 0xff] ^ U2[(state->v32[2] >> 8) & 0xff] ^ U3[state->v32[1] & 0xff]; diff --git a/third_party/libsrtp/src/crypto/cipher/aes_gcm_mbedtls.c b/third_party/libsrtp/src/crypto/cipher/aes_gcm_mbedtls.c --- a/third_party/libsrtp/src/crypto/cipher/aes_gcm_mbedtls.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_gcm_mbedtls.c @@ -254,11 +254,10 @@ static srtp_err_status_t srtp_aes_gcm_mbedtls_set_aad(void *cv, const uint8_t *aad, uint32_t aad_len) { FUNC_ENTRY(); - int errCode = 0; srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; debug_print(srtp_mod_aes_gcm, "setting AAD: %s", srtp_octet_string_hex_string(aad, aad_len)); @@ -341,11 +340,10 @@ unsigned int *enc_len) { FUNC_ENTRY(); srtp_aes_gcm_ctx_t *c = (srtp_aes_gcm_ctx_t *)cv; int errCode = 0; - int len = *enc_len; if (c->dir != srtp_direction_encrypt && c->dir != srtp_direction_decrypt) { return (srtp_err_status_bad_param); } diff --git a/third_party/libsrtp/src/crypto/cipher/aes_gcm_nss.c b/third_party/libsrtp/src/crypto/cipher/aes_gcm_nss.c --- a/third_party/libsrtp/src/crypto/cipher/aes_gcm_nss.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_gcm_nss.c @@ -210,11 +210,13 @@ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_AES_GCM, NULL); if (!slot) { return (srtp_err_status_cipher_fail); } - SECItem key_item = { siBuffer, (unsigned char *)key, c->key_size }; + /* explicitly cast away const of key */ + SECItem key_item = { siBuffer, (unsigned char *)(uintptr_t)key, + c->key_size }; c->key = PK11_ImportSymKey(slot, CKM_AES_GCM, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL); PK11_FreeSlot(slot); if (!c->key) { diff --git a/third_party/libsrtp/src/crypto/cipher/aes_gcm_ossl.c b/third_party/libsrtp/src/crypto/cipher/aes_gcm_ossl.c --- a/third_party/libsrtp/src/crypto/cipher/aes_gcm_ossl.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_gcm_ossl.c @@ -191,15 +191,20 @@ default: return (srtp_err_status_bad_param); break; } - EVP_CIPHER_CTX_cleanup(c->ctx); + EVP_CIPHER_CTX_reset(c->ctx); + if (!EVP_CipherInit_ex(c->ctx, evp, NULL, key, NULL, 0)) { return (srtp_err_status_init_fail); } + if (!EVP_CIPHER_CTX_ctrl(c->ctx, EVP_CTRL_GCM_SET_IVLEN, 12, 0)) { + return (srtp_err_status_init_fail); + } + return (srtp_err_status_ok); } /* * aes_gcm_openssl_set_iv(c, iv) sets the counter value to the exor of iv with @@ -219,14 +224,10 @@ c->dir = direction; debug_print(srtp_mod_aes_gcm, "setting iv: %s", srtp_octet_string_hex_string(iv, 12)); - if (!EVP_CIPHER_CTX_ctrl(c->ctx, EVP_CTRL_GCM_SET_IVLEN, 12, 0)) { - return (srtp_err_status_init_fail); - } - if (!EVP_CipherInit_ex(c->ctx, NULL, NULL, NULL, iv, (c->dir == srtp_direction_encrypt ? 1 : 0))) { return (srtp_err_status_init_fail); } @@ -273,11 +274,11 @@ return (srtp_err_status_algo_fail); } } rv = EVP_Cipher(c->ctx, NULL, aad, aad_len); - if (rv != aad_len) { + if (rv < 0 || (uint32_t)rv != aad_len) { return (srtp_err_status_algo_fail); } else { return (srtp_err_status_ok); } } diff --git a/third_party/libsrtp/src/crypto/cipher/aes_icm.c b/third_party/libsrtp/src/crypto/cipher/aes_icm.c --- a/third_party/libsrtp/src/crypto/cipher/aes_icm.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_icm.c @@ -96,10 +96,11 @@ static srtp_err_status_t srtp_aes_icm_alloc(srtp_cipher_t **c, int key_len, int tlen) { srtp_aes_icm_ctx_t *icm; + (void)tlen; debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d", key_len); /* @@ -236,10 +237,11 @@ uint8_t *iv, srtp_cipher_direction_t direction) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; v128_t nonce; + (void)direction; /* set nonce (for alignment) */ v128_copy_octet_string(&nonce, iv); debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); @@ -300,11 +302,13 @@ unsigned int bytes_to_encr = *enc_len; unsigned int i; uint32_t *b; /* check that there's enough segment left*/ - if ((bytes_to_encr + htons(c->counter.v16[7])) > 0xffff) { + unsigned int bytes_of_new_keystream = bytes_to_encr - c->bytes_in_buffer; + unsigned int blocks_of_new_keystream = (bytes_of_new_keystream + 15) >> 4; + if ((blocks_of_new_keystream + htons(c->counter.v16[7])) > 0xffff) { return srtp_err_status_terminus; } debug_print(srtp_mod_aes_icm, "block index: %d", htons(c->counter.v16[7])); if (bytes_to_encr <= (unsigned int)c->bytes_in_buffer) { @@ -333,14 +337,14 @@ /* now loop over entire 16-byte blocks of keystream */ for (i = 0; i < (bytes_to_encr / sizeof(v128_t)); i++) { /* fill buffer with new keystream */ srtp_aes_icm_advance(c); -/* - * add keystream into the data buffer (this would be a lot faster - * if we could assume 32-bit alignment!) - */ + /* + * add keystream into the data buffer (this would be a lot faster + * if we could assume 32-bit alignment!) + */ #if ALIGN_32 b = (uint32_t *)buf; *b++ ^= c->keystream_buffer.v32[0]; *b++ ^= c->keystream_buffer.v32[1]; diff --git a/third_party/libsrtp/src/crypto/cipher/aes_icm_mbedtls.c b/third_party/libsrtp/src/crypto/cipher/aes_icm_mbedtls.c --- a/third_party/libsrtp/src/crypto/cipher/aes_icm_mbedtls.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_icm_mbedtls.c @@ -116,10 +116,11 @@ static srtp_err_status_t srtp_aes_icm_mbedtls_alloc(srtp_cipher_t **c, int key_len, int tlen) { srtp_aes_icm_ctx_t *icm; + (void)tlen; debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d", key_len); /* @@ -262,10 +263,12 @@ uint8_t *iv, srtp_cipher_direction_t dir) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; v128_t nonce; + (void)dir; + c->nc_off = 0; /* set nonce (for alignment) */ v128_copy_octet_string(&nonce, iv); debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); diff --git a/third_party/libsrtp/src/crypto/cipher/aes_icm_nss.c b/third_party/libsrtp/src/crypto/cipher/aes_icm_nss.c --- a/third_party/libsrtp/src/crypto/cipher/aes_icm_nss.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_icm_nss.c @@ -105,10 +105,11 @@ int key_len, int tlen) { srtp_aes_icm_ctx_t *icm; NSSInitContext *nss; + (void)tlen; debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d", key_len); /* @@ -251,11 +252,13 @@ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_AES_CTR, NULL); if (!slot) { return srtp_err_status_bad_param; } - SECItem keyItem = { siBuffer, (unsigned char *)key, c->key_size }; + /* explicitly cast away const of key */ + SECItem keyItem = { siBuffer, (unsigned char *)(uintptr_t)key, + c->key_size }; c->key = PK11_ImportSymKey(slot, CKM_AES_CTR, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL); PK11_FreeSlot(slot); if (!c->key) { @@ -273,10 +276,11 @@ uint8_t *iv, srtp_cipher_direction_t dir) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; v128_t nonce; + (void)dir; /* set nonce (for alignment) */ v128_copy_octet_string(&nonce, iv); debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); diff --git a/third_party/libsrtp/src/crypto/cipher/aes_icm_ossl.c b/third_party/libsrtp/src/crypto/cipher/aes_icm_ossl.c --- a/third_party/libsrtp/src/crypto/cipher/aes_icm_ossl.c +++ b/third_party/libsrtp/src/crypto/cipher/aes_icm_ossl.c @@ -110,10 +110,11 @@ static srtp_err_status_t srtp_aes_icm_openssl_alloc(srtp_cipher_t **c, int key_len, int tlen) { srtp_aes_icm_ctx_t *icm; + (void)tlen; debug_print(srtp_mod_aes_icm, "allocating cipher with key length %d", key_len); /* @@ -166,11 +167,11 @@ (*c)->type = &srtp_aes_icm_256; icm->key_size = SRTP_AES_256_KEY_LEN; break; } - /* set key size */ + /* set key size */ (*c)->key_len = key_len; return srtp_err_status_ok; } @@ -247,15 +248,14 @@ default: return srtp_err_status_bad_param; break; } - EVP_CIPHER_CTX_cleanup(c->ctx); + EVP_CIPHER_CTX_reset(c->ctx); + if (!EVP_EncryptInit_ex(c->ctx, evp, NULL, key, NULL)) { return srtp_err_status_fail; - } else { - return srtp_err_status_ok; } return srtp_err_status_ok; } @@ -268,10 +268,11 @@ uint8_t *iv, srtp_cipher_direction_t dir) { srtp_aes_icm_ctx_t *c = (srtp_aes_icm_ctx_t *)cv; v128_t nonce; + (void)dir; /* set nonce (for alignment) */ v128_copy_octet_string(&nonce, iv); debug_print(srtp_mod_aes_icm, "setting iv: %s", v128_hex_string(&nonce)); @@ -281,13 +282,13 @@ debug_print(srtp_mod_aes_icm, "set_counter: %s", v128_hex_string(&c->counter)); if (!EVP_EncryptInit_ex(c->ctx, NULL, NULL, NULL, c->counter.v8)) { return srtp_err_status_fail; - } else { - return srtp_err_status_ok; } + + return srtp_err_status_ok; } /* * This function encrypts a buffer using AES CTR mode * diff --git a/third_party/libsrtp/src/crypto/cipher/cipher.c b/third_party/libsrtp/src/crypto/cipher/cipher.c --- a/third_party/libsrtp/src/crypto/cipher/cipher.c +++ b/third_party/libsrtp/src/crypto/cipher/cipher.c @@ -630,28 +630,51 @@ int i; v128_t nonce; clock_t timer; unsigned char *enc_buf; unsigned int len = octets_in_buffer; + uint32_t tag_len = SRTP_MAX_TAG_LEN; + unsigned char aad[4] = { 0, 0, 0, 0 }; + uint32_t aad_len = 4; - enc_buf = (unsigned char *)srtp_crypto_alloc(octets_in_buffer); + enc_buf = (unsigned char *)srtp_crypto_alloc(octets_in_buffer + tag_len); if (enc_buf == NULL) { return 0; /* indicate bad parameters by returning null */ } /* time repeated trials */ v128_set_to_zero(&nonce); timer = clock(); for (i = 0; i < num_trials; i++, nonce.v32[3] = i) { + // Set IV if (srtp_cipher_set_iv(c, (uint8_t *)&nonce, srtp_direction_encrypt) != srtp_err_status_ok) { srtp_crypto_free(enc_buf); return 0; } + + // Set (empty) AAD if supported by the cipher + if (c->type->set_aad) { + if (srtp_cipher_set_aad(c, aad, aad_len) != srtp_err_status_ok) { + srtp_crypto_free(enc_buf); + return 0; + } + } + + // Encrypt the buffer if (srtp_cipher_encrypt(c, enc_buf, &len) != srtp_err_status_ok) { srtp_crypto_free(enc_buf); return 0; } + + // Get tag if supported by the cipher + if (c->type->get_tag) { + if (srtp_cipher_get_tag(c, (uint8_t *)(enc_buf + len), &tag_len) != + srtp_err_status_ok) { + srtp_crypto_free(enc_buf); + return 0; + } + } } timer = clock() - timer; srtp_crypto_free(enc_buf); diff --git a/third_party/libsrtp/src/crypto/cipher/null_cipher.c b/third_party/libsrtp/src/crypto/cipher/null_cipher.c --- a/third_party/libsrtp/src/crypto/cipher/null_cipher.c +++ b/third_party/libsrtp/src/crypto/cipher/null_cipher.c @@ -57,10 +57,11 @@ static srtp_err_status_t srtp_null_cipher_alloc(srtp_cipher_t **c, int key_len, int tlen) { extern const srtp_cipher_type_t srtp_null_cipher; + (void)tlen; debug_print(srtp_mod_cipher, "allocating cipher with key length %d", key_len); /* allocate memory a cipher of type null_cipher */ @@ -94,29 +95,36 @@ } static srtp_err_status_t srtp_null_cipher_init(void *cv, const uint8_t *key) { /* srtp_null_cipher_ctx_t *c = (srtp_null_cipher_ctx_t *)cv; */ - + (void)cv; + (void)key; debug_print0(srtp_mod_cipher, "initializing null cipher"); return srtp_err_status_ok; } static srtp_err_status_t srtp_null_cipher_set_iv(void *cv, uint8_t *iv, srtp_cipher_direction_t dir) { /* srtp_null_cipher_ctx_t *c = (srtp_null_cipher_ctx_t *)cv; */ + (void)cv; + (void)iv; + (void)dir; return srtp_err_status_ok; } static srtp_err_status_t srtp_null_cipher_encrypt(void *cv, unsigned char *buf, unsigned int *bytes_to_encr) { /* srtp_null_cipher_ctx_t *c = (srtp_null_cipher_ctx_t *)cv; */ + (void)cv; + (void)buf; + (void)bytes_to_encr; return srtp_err_status_ok; } static const char srtp_null_cipher_description[] = "null cipher"; diff --git a/third_party/libsrtp/src/crypto/hash/hmac_mbedtls.c b/third_party/libsrtp/src/crypto/hash/hmac_mbedtls.c --- a/third_party/libsrtp/src/crypto/hash/hmac_mbedtls.c +++ b/third_party/libsrtp/src/crypto/hash/hmac_mbedtls.c @@ -70,14 +70,10 @@ key_len); debug_print(srtp_mod_hmac, " tag length %d", out_len); /* check output length - should be less than 20 bytes */ - if (key_len > SHA1_DIGEST_SIZE) { - return srtp_err_status_bad_param; - } - /* check output length - should be less than 20 bytes */ if (out_len > SHA1_DIGEST_SIZE) { return srtp_err_status_bad_param; } *a = (srtp_auth_t *)srtp_crypto_alloc(sizeof(srtp_auth_t)); diff --git a/third_party/libsrtp/src/crypto/hash/hmac_nss.c b/third_party/libsrtp/src/crypto/hash/hmac_nss.c --- a/third_party/libsrtp/src/crypto/hash/hmac_nss.c +++ b/third_party/libsrtp/src/crypto/hash/hmac_nss.c @@ -185,11 +185,12 @@ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL); if (!slot) { return srtp_err_status_bad_param; } - SECItem key_item = { siBuffer, (unsigned char *)key, key_len }; + /* explicitly cast away const of key */ + SECItem key_item = { siBuffer, (unsigned char *)(uintptr_t)key, key_len }; sym_key = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap, CKA_SIGN, &key_item, NULL); PK11_FreeSlot(slot); if (!sym_key) { @@ -254,11 +255,11 @@ if (PK11_DigestFinal(hmac->ctx, hash_value, &len, SHA1_DIGEST_SIZE) != SECSuccess) { return srtp_err_status_auth_fail; } - if (len < tag_len) + if (tag_len < 0 || len < (unsigned int)tag_len) return srtp_err_status_auth_fail; /* copy hash_value to *result */ for (i = 0; i < tag_len; i++) { result[i] = hash_value[i]; diff --git a/third_party/libsrtp/src/crypto/hash/hmac_ossl.c b/third_party/libsrtp/src/crypto/hash/hmac_ossl.c --- a/third_party/libsrtp/src/crypto/hash/hmac_ossl.c +++ b/third_party/libsrtp/src/crypto/hash/hmac_ossl.c @@ -49,26 +49,61 @@ #include "auth.h" #include "alloc.h" #include "err.h" /* for srtp_debug */ #include "auth_test_cases.h" #include + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#define SRTP_OSSL_USE_EVP_MAC +/* before this version reinit of EVP_MAC_CTX was not supported so need to + * duplicate the CTX each time */ +#define SRTP_OSSL_MIN_REINIT_VERSION 0x30000030L +#endif + +#ifndef SRTP_OSSL_USE_EVP_MAC #include +#endif #define SHA1_DIGEST_SIZE 20 -/* the debug module for authentiation */ +/* the debug module for authentication */ srtp_debug_module_t srtp_mod_hmac = { 0, /* debugging is off by default */ "hmac sha-1 openssl" /* printable name for module */ }; +/* + * There are three different behaviors of OpenSSL HMAC for different versions. + * + * 1. Pre-3.0 - Use HMAC API + * 2. 3.0.0 - 3.0.2 - EVP API is required, but doesn't support reinitialization, + * so we have to use EVP_MAC_CTX_dup + * 3. 3.0.3 and later - EVP API is required and supports reinitialization + * + * The distingtion between cases 2 & 3 needs to be made at runtime, because in a + * shared library context you might end up building against 3.0.3 and running + * against 3.0.2. + */ + +typedef struct { +#ifdef SRTP_OSSL_USE_EVP_MAC + EVP_MAC *mac; + EVP_MAC_CTX *ctx; + int use_dup; + EVP_MAC_CTX *ctx_dup; +#else + HMAC_CTX *ctx; +#endif +} srtp_hmac_ossl_ctx_t; + static srtp_err_status_t srtp_hmac_alloc(srtp_auth_t **a, int key_len, int out_len) { extern const srtp_auth_type_t srtp_hmac; + srtp_hmac_ossl_ctx_t *hmac; debug_print(srtp_mod_hmac, "allocating auth func with key length %d", key_len); debug_print(srtp_mod_hmac, " tag length %d", out_len); @@ -76,141 +111,202 @@ /* check output length - should be less than 20 bytes */ if (out_len > SHA1_DIGEST_SIZE) { return srtp_err_status_bad_param; } -/* OpenSSL 1.1.0 made HMAC_CTX an opaque structure, which must be allocated - using HMAC_CTX_new. But this function doesn't exist in OpenSSL 1.0.x. */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER - { - /* allocate memory for auth and HMAC_CTX structures */ - uint8_t *pointer; - HMAC_CTX *new_hmac_ctx; - pointer = (uint8_t *)srtp_crypto_alloc(sizeof(HMAC_CTX) + - sizeof(srtp_auth_t)); - if (pointer == NULL) { - return srtp_err_status_alloc_fail; - } - *a = (srtp_auth_t *)pointer; - (*a)->state = pointer + sizeof(srtp_auth_t); - new_hmac_ctx = (HMAC_CTX *)((*a)->state); - - HMAC_CTX_init(new_hmac_ctx); - } - -#else *a = (srtp_auth_t *)srtp_crypto_alloc(sizeof(srtp_auth_t)); if (*a == NULL) { return srtp_err_status_alloc_fail; } - (*a)->state = HMAC_CTX_new(); - if ((*a)->state == NULL) { + hmac = + (srtp_hmac_ossl_ctx_t *)srtp_crypto_alloc(sizeof(srtp_hmac_ossl_ctx_t)); + if (hmac == NULL) { + srtp_crypto_free(*a); + *a = NULL; + return srtp_err_status_alloc_fail; + } + +#ifdef SRTP_OSSL_USE_EVP_MAC + hmac->mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (hmac->mac == NULL) { + srtp_crypto_free(hmac); + srtp_crypto_free(*a); + *a = NULL; + return srtp_err_status_alloc_fail; + } + + hmac->ctx = EVP_MAC_CTX_new(hmac->mac); + if (hmac->ctx == NULL) { + EVP_MAC_free(hmac->mac); + srtp_crypto_free(hmac); + srtp_crypto_free(*a); + *a = NULL; + return srtp_err_status_alloc_fail; + } + + hmac->use_dup = + OpenSSL_version_num() < SRTP_OSSL_MIN_REINIT_VERSION ? 1 : 0; + + if (hmac->use_dup) { + debug_print0(srtp_mod_hmac, "using EVP_MAC_CTX_dup"); + hmac->ctx_dup = hmac->ctx; + hmac->ctx = NULL; + } +#else + hmac->ctx = HMAC_CTX_new(); + if (hmac->ctx == NULL) { + srtp_crypto_free(hmac); srtp_crypto_free(*a); *a = NULL; return srtp_err_status_alloc_fail; } #endif /* set pointers */ + (*a)->state = hmac; (*a)->type = &srtp_hmac; (*a)->out_len = out_len; (*a)->key_len = key_len; (*a)->prefix_len = 0; return srtp_err_status_ok; } static srtp_err_status_t srtp_hmac_dealloc(srtp_auth_t *a) { - HMAC_CTX *hmac_ctx; - - hmac_ctx = (HMAC_CTX *)a->state; + srtp_hmac_ossl_ctx_t *hmac = (srtp_hmac_ossl_ctx_t *)a->state; -#if OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER - HMAC_CTX_cleanup(hmac_ctx); + if (hmac) { +#ifdef SRTP_OSSL_USE_EVP_MAC + EVP_MAC_CTX_free(hmac->ctx); + EVP_MAC_CTX_free(hmac->ctx_dup); + EVP_MAC_free(hmac->mac); +#else + HMAC_CTX_free(hmac->ctx); +#endif + /* zeroize entire state*/ + octet_string_set_to_zero(hmac, sizeof(srtp_hmac_ossl_ctx_t)); - /* zeroize entire state*/ - octet_string_set_to_zero(a, sizeof(HMAC_CTX) + sizeof(srtp_auth_t)); - -#else - HMAC_CTX_free(hmac_ctx); + srtp_crypto_free(hmac); + } /* zeroize entire state*/ octet_string_set_to_zero(a, sizeof(srtp_auth_t)); -#endif /* free memory */ srtp_crypto_free(a); return srtp_err_status_ok; } static srtp_err_status_t srtp_hmac_start(void *statev) { - HMAC_CTX *state = (HMAC_CTX *)statev; + srtp_hmac_ossl_ctx_t *hmac = (srtp_hmac_ossl_ctx_t *)statev; - if (HMAC_Init_ex(state, NULL, 0, NULL, NULL) == 0) +#ifdef SRTP_OSSL_USE_EVP_MAC + if (hmac->use_dup) { + EVP_MAC_CTX_free(hmac->ctx); + hmac->ctx = EVP_MAC_CTX_dup(hmac->ctx_dup); + if (hmac->ctx == NULL) { + return srtp_err_status_alloc_fail; + } + } else { + if (EVP_MAC_init(hmac->ctx, NULL, 0, NULL) == 0) { + return srtp_err_status_auth_fail; + } + } +#else + if (HMAC_Init_ex(hmac->ctx, NULL, 0, NULL, NULL) == 0) return srtp_err_status_auth_fail; - +#endif return srtp_err_status_ok; } static srtp_err_status_t srtp_hmac_init(void *statev, const uint8_t *key, int key_len) { - HMAC_CTX *state = (HMAC_CTX *)statev; + srtp_hmac_ossl_ctx_t *hmac = (srtp_hmac_ossl_ctx_t *)statev; + +#ifdef SRTP_OSSL_USE_EVP_MAC + OSSL_PARAM params[2]; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", "SHA1", 0); + params[1] = OSSL_PARAM_construct_end(); - if (HMAC_Init_ex(state, key, key_len, EVP_sha1(), NULL) == 0) + if (EVP_MAC_init(hmac->use_dup ? hmac->ctx_dup : hmac->ctx, key, key_len, + params) == 0) { return srtp_err_status_auth_fail; - + } +#else + if (HMAC_Init_ex(hmac->ctx, key, key_len, EVP_sha1(), NULL) == 0) + return srtp_err_status_auth_fail; +#endif return srtp_err_status_ok; } static srtp_err_status_t srtp_hmac_update(void *statev, const uint8_t *message, int msg_octets) { - HMAC_CTX *state = (HMAC_CTX *)statev; + srtp_hmac_ossl_ctx_t *hmac = (srtp_hmac_ossl_ctx_t *)statev; debug_print(srtp_mod_hmac, "input: %s", srtp_octet_string_hex_string(message, msg_octets)); - if (HMAC_Update(state, message, msg_octets) == 0) +#ifdef SRTP_OSSL_USE_EVP_MAC + if (EVP_MAC_update(hmac->ctx, message, msg_octets) == 0) { return srtp_err_status_auth_fail; - + } +#else + if (HMAC_Update(hmac->ctx, message, msg_octets) == 0) + return srtp_err_status_auth_fail; +#endif return srtp_err_status_ok; } static srtp_err_status_t srtp_hmac_compute(void *statev, const uint8_t *message, int msg_octets, int tag_len, uint8_t *result) { - HMAC_CTX *state = (HMAC_CTX *)statev; + srtp_hmac_ossl_ctx_t *hmac = (srtp_hmac_ossl_ctx_t *)statev; uint8_t hash_value[SHA1_DIGEST_SIZE]; int i; +#ifdef SRTP_OSSL_USE_EVP_MAC + size_t len; +#else unsigned int len; +#endif debug_print(srtp_mod_hmac, "input: %s", srtp_octet_string_hex_string(message, msg_octets)); /* check tag length, return error if we can't provide the value expected */ if (tag_len > SHA1_DIGEST_SIZE) { return srtp_err_status_bad_param; } /* hash message, copy output into H */ - if (HMAC_Update(state, message, msg_octets) == 0) +#ifdef SRTP_OSSL_USE_EVP_MAC + if (EVP_MAC_update(hmac->ctx, message, msg_octets) == 0) { + return srtp_err_status_auth_fail; + } + + if (EVP_MAC_final(hmac->ctx, hash_value, &len, sizeof hash_value) == 0) { + return srtp_err_status_auth_fail; + } +#else + if (HMAC_Update(hmac->ctx, message, msg_octets) == 0) return srtp_err_status_auth_fail; - if (HMAC_Final(state, hash_value, &len) == 0) + if (HMAC_Final(hmac->ctx, hash_value, &len) == 0) return srtp_err_status_auth_fail; - - if (len < tag_len) +#endif + if (tag_len < 0 || len < (unsigned int)tag_len) return srtp_err_status_auth_fail; /* copy hash_value to *result */ for (i = 0; i < tag_len; i++) { result[i] = hash_value[i]; diff --git a/third_party/libsrtp/src/crypto/hash/null_auth.c b/third_party/libsrtp/src/crypto/hash/null_auth.c --- a/third_party/libsrtp/src/crypto/hash/null_auth.c +++ b/third_party/libsrtp/src/crypto/hash/null_auth.c @@ -100,10 +100,14 @@ static srtp_err_status_t srtp_null_auth_init(void *statev, const uint8_t *key, int key_len) { /* srtp_null_auth_ctx_t *state = (srtp_null_auth_ctx_t *)statev; */ + (void)statev; + (void)key; + (void)key_len; + /* accept any length of key, and do nothing */ return srtp_err_status_ok; } @@ -112,26 +116,35 @@ int msg_octets, int tag_len, uint8_t *result) { /* srtp_null_auth_ctx_t *state = (srtp_null_auth_ctx_t *)statev; */ + (void)statev; + (void)message; + (void)msg_octets; + (void)tag_len; + (void)result; return srtp_err_status_ok; } static srtp_err_status_t srtp_null_auth_update(void *statev, const uint8_t *message, int msg_octets) { /* srtp_null_auth_ctx_t *state = (srtp_null_auth_ctx_t *)statev; */ + (void)statev; + (void)message; + (void)msg_octets; return srtp_err_status_ok; } static srtp_err_status_t srtp_null_auth_start(void *statev) { /* srtp_null_auth_ctx_t *state = (srtp_null_auth_ctx_t *)statev; */ + (void)statev; return srtp_err_status_ok; } /* diff --git a/third_party/libsrtp/src/crypto/include/.cvsignore b/third_party/libsrtp/src/crypto/include/.cvsignore deleted file mode 100644 --- a/third_party/libsrtp/src/crypto/include/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -config.h diff --git a/third_party/libsrtp/src/crypto/include/cipher.h b/third_party/libsrtp/src/crypto/include/cipher.h --- a/third_party/libsrtp/src/crypto/include/cipher.h +++ b/third_party/libsrtp/src/crypto/include/cipher.h @@ -151,11 +151,11 @@ srtp_cipher_alloc_func_t alloc; srtp_cipher_dealloc_func_t dealloc; srtp_cipher_init_func_t init; srtp_cipher_set_aad_func_t set_aad; srtp_cipher_encrypt_func_t encrypt; - srtp_cipher_encrypt_func_t decrypt; + srtp_cipher_decrypt_func_t decrypt; srtp_cipher_set_iv_func_t set_iv; srtp_cipher_get_tag_func_t get_tag; const char *description; const srtp_cipher_test_case_t *test_data; srtp_cipher_type_id_t id; diff --git a/third_party/libsrtp/src/crypto/include/datatypes.h b/third_party/libsrtp/src/crypto/include/datatypes.h --- a/third_party/libsrtp/src/crypto/include/datatypes.h +++ b/third_party/libsrtp/src/crypto/include/datatypes.h @@ -60,10 +60,14 @@ #include #else #error "Platform not recognized" #endif +#if defined(__SSE2__) +#include +#endif + #ifdef __cplusplus extern "C" { #endif typedef union { @@ -88,10 +92,30 @@ /* * the following macros define the data manipulation functions * */ +#if defined(__SSE2__) + +#define v128_set_to_zero(x) \ + (_mm_storeu_si128((__m128i *)(x), _mm_setzero_si128())) + +#define v128_copy(x, y) \ + (_mm_storeu_si128((__m128i *)(x), _mm_loadu_si128((const __m128i *)(y)))) + +#define v128_xor(z, x, y) \ + (_mm_storeu_si128((__m128i *)(z), \ + _mm_xor_si128(_mm_loadu_si128((const __m128i *)(x)), \ + _mm_loadu_si128((const __m128i *)(y))))) + +#define v128_xor_eq(z, x) \ + (_mm_storeu_si128((__m128i *)(z), \ + _mm_xor_si128(_mm_loadu_si128((const __m128i *)(x)), \ + _mm_loadu_si128((const __m128i *)(z))))) + +#else /* defined(__SSE2__) */ + #define v128_set_to_zero(x) \ ((x)->v32[0] = 0, (x)->v32[1] = 0, (x)->v32[2] = 0, (x)->v32[3] = 0) #define v128_copy(x, y) \ ((x)->v32[0] = (y)->v32[0], (x)->v32[1] = (y)->v32[1], \ @@ -111,10 +135,12 @@ #else #define v128_xor_eq(z, x) \ ((z)->v64[0] ^= (x)->v64[0], (z)->v64[1] ^= (x)->v64[1]) #endif +#endif /* defined(__SSE2__) */ + /* NOTE! This assumes an odd ordering! */ /* This will not be compatible directly with math on some processors */ /* bit 0 is first 32-bit word, low order bit. in little-endian, that's the first byte of the first 32-bit word. In big-endian, that's the 3rd byte of the first 32-bit word */ @@ -135,11 +161,11 @@ * a and b are not equal. It returns 0 otherwise. The running time of the * comparison depends only on len, making this safe to use for (e.g.) * verifying authentication tags. */ -int srtp_octet_string_is_eq(uint8_t *a, uint8_t *b, int len); +int srtp_octet_string_is_eq(const uint8_t *a, const uint8_t *b, int len); /* * A portable way to zero out memory as recommended by * https://cryptocoding.net/index.php/Coding_rules#Clean_memory_of_secret_data * This is used to zero memory when OPENSSL_cleanse() is not available. @@ -164,19 +190,22 @@ #elif defined(HAVE_BYTESWAP_H) /* We have (hopefully) optimized versions in byteswap.h */ #include #define be32_to_cpu(x) bswap_32((x)) #define be64_to_cpu(x) bswap_64((x)) +#elif defined(__APPLE__) +// Mac OS X / Darwin features +#include +#define be32_to_cpu(x) OSSwapInt32(x) +#define be64_to_cpu(x) OSSwapInt64(x) #else /* WORDS_BIGENDIAN */ -#if defined(__GNUC__) && (defined(HAVE_X86) || defined(__x86_64__)) +#if defined(__GNUC__) /* Fall back. */ static inline uint32_t be32_to_cpu(uint32_t v) { - /* optimized for x86. */ - asm("bswap %0" : "=r"(v) : "0"(v)); - return v; + return __builtin_bswap32(v); } #else /* HAVE_X86 */ #ifdef HAVE_NETINET_IN_H #include #elif defined HAVE_WINSOCK2_H @@ -185,11 +214,13 @@ #define be32_to_cpu(x) ntohl((x)) #endif /* HAVE_X86 */ static inline uint64_t be64_to_cpu(uint64_t v) { -#ifdef NO_64BIT_MATH +#if defined(__GNUC__) + v = __builtin_bswap64(v); +#elif defined(NO_64BIT_MATH) /* use the make64 functions to do 64-bit math */ v = make64(htonl(low32(v)), htonl(high32(v))); #else /* NO_64BIT_MATH */ /* use the native 64-bit math */ v = (uint64_t)((be32_to_cpu((uint32_t)(v >> 32))) | diff --git a/third_party/libsrtp/src/crypto/include/err.h b/third_party/libsrtp/src/crypto/include/err.h --- a/third_party/libsrtp/src/crypto/include/err.h +++ b/third_party/libsrtp/src/crypto/include/err.h @@ -47,10 +47,21 @@ #include #include #include "srtp.h" +#if defined(__clang__) || (defined(__GNUC__) && defined(__has_attribute)) +#if __has_attribute(format) +#define LIBSRTP_FORMAT_PRINTF(fmt, args) \ + __attribute__((format(__printf__, fmt, args))) +#else +#define LIBSRTP_FORMAT_PRINTF(fmt, args) +#endif +#else +#define LIBSRTP_FORMAT_PRINTF(fmt, args) +#endif + #ifdef __cplusplus extern "C" { #endif /** @@ -94,11 +105,12 @@ * Errors will be reported to stdout, if ERR_REPORTING_STDOUT * is defined. * */ -void srtp_err_report(srtp_err_reporting_level_t level, const char *format, ...); +void srtp_err_report(srtp_err_reporting_level_t level, const char *format, ...) + LIBSRTP_FORMAT_PRINTF(2, 3); /* * debug_module_t defines a debug module */ diff --git a/third_party/libsrtp/src/crypto/kernel/crypto_kernel.c b/third_party/libsrtp/src/crypto/kernel/crypto_kernel.c --- a/third_party/libsrtp/src/crypto/kernel/crypto_kernel.c +++ b/third_party/libsrtp/src/crypto/kernel/crypto_kernel.c @@ -58,20 +58,20 @@ "crypto kernel" /* printable name for module */ }; /* crypto_kernel is a global variable, the only one of its datatype */ -srtp_crypto_kernel_t crypto_kernel = { +static srtp_crypto_kernel_t crypto_kernel = { srtp_crypto_kernel_state_insecure, /* start off in insecure state */ NULL, /* no cipher types yet */ NULL, /* no auth types yet */ NULL /* no debug modules yet */ }; #define MAX_RNG_TRIALS 25 -srtp_err_status_t srtp_crypto_kernel_init() +srtp_err_status_t srtp_crypto_kernel_init(void) { srtp_err_status_t status; /* check the security state */ if (crypto_kernel.state == srtp_crypto_kernel_state_secure) { @@ -166,11 +166,11 @@ crypto_kernel.state = srtp_crypto_kernel_state_secure; return srtp_err_status_ok; } -srtp_err_status_t srtp_crypto_kernel_status() +srtp_err_status_t srtp_crypto_kernel_status(void) { srtp_err_status_t status; srtp_kernel_cipher_type_t *ctype = crypto_kernel.cipher_type_list; srtp_kernel_auth_type_t *atype = crypto_kernel.auth_type_list; @@ -207,11 +207,11 @@ srtp_crypto_kernel_list_debug_modules(); return srtp_err_status_ok; } -srtp_err_status_t srtp_crypto_kernel_list_debug_modules() +srtp_err_status_t srtp_crypto_kernel_list_debug_modules(void) { srtp_kernel_debug_module_t *dm = crypto_kernel.debug_module_list; /* describe each debug module */ srtp_err_report(srtp_err_level_info, "debug modules loaded:\n"); @@ -226,11 +226,11 @@ } return srtp_err_status_ok; } -srtp_err_status_t srtp_crypto_kernel_shutdown() +srtp_err_status_t srtp_crypto_kernel_shutdown(void) { /* * free dynamic memory used in crypto_kernel at present */ diff --git a/third_party/libsrtp/src/crypto/kernel/err.c b/third_party/libsrtp/src/crypto/kernel/err.c --- a/third_party/libsrtp/src/crypto/kernel/err.c +++ b/third_party/libsrtp/src/crypto/kernel/err.c @@ -52,11 +52,11 @@ /* srtp_err_file is the FILE to which errors are reported */ static FILE *srtp_err_file = NULL; -srtp_err_status_t srtp_err_reporting_init() +srtp_err_status_t srtp_err_reporting_init(void) { #ifdef ERR_REPORTING_STDOUT srtp_err_file = stdout; #elif defined(ERR_REPORTING_FILE) /* open file for error reporting */ diff --git a/third_party/libsrtp/src/crypto/math/datatypes.c b/third_party/libsrtp/src/crypto/math/datatypes.c --- a/third_party/libsrtp/src/crypto/math/datatypes.c +++ b/third_party/libsrtp/src/crypto/math/datatypes.c @@ -51,23 +51,33 @@ #include #endif #include "datatypes.h" +#if defined(__SSE2__) +#include +#endif + +#if defined(_MSC_VER) +#define ALIGNMENT(N) __declspec(align(N)) +#else +#define ALIGNMENT(N) __attribute__((aligned(N))) +#endif + /* * bit_string is a buffer that is used to hold output strings, e.g. * for printing. */ /* the value MAX_PRINT_STRING_LEN is defined in datatypes.h */ /* include space for null terminator */ static char bit_string[MAX_PRINT_STRING_LEN + 1]; -uint8_t srtp_nibble_to_hex_char(uint8_t nibble) +static uint8_t srtp_nibble_to_hex_char(uint8_t nibble) { - char buf[16] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + static const char buf[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; return buf[nibble & 0xF]; } char *srtp_octet_string_hex_string(const void *s, int length) { @@ -121,10 +131,13 @@ return bit_string; } void v128_copy_octet_string(v128_t *x, const uint8_t s[16]) { +#if defined(__SSE2__) + _mm_storeu_si128((__m128i *)(x), _mm_loadu_si128((const __m128i *)(s))); +#else #ifdef ALIGNMENT_32BIT_REQUIRED if ((((uint32_t)&s[0]) & 0x3) != 0) #endif { x->v8[0] = s[0]; @@ -149,12 +162,71 @@ v128_t *v = (v128_t *)&s[0]; v128_copy(x, v); } #endif +#endif /* defined(__SSE2__) */ } +#if defined(__SSSE3__) + +/* clang-format off */ + +ALIGNMENT(16) +static const uint8_t right_shift_masks[5][16] = { + { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, + 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u }, + { 0x80, 0x80, 0x80, 0x80, 0u, 1u, 2u, 3u, + 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u }, + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u }, + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0u, 1u, 2u, 3u }, + /* needed for bitvector_left_shift */ + { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } +}; + +ALIGNMENT(16) +static const uint8_t left_shift_masks[4][16] = { + { 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, + 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u }, + { 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, + 12u, 13u, 14u, 15u, 0x80, 0x80, 0x80, 0x80 }, + { 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, + { 12u, 13u, 14u, 15u, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } +}; + +/* clang-format on */ + +void v128_left_shift(v128_t *x, int shift) +{ + if (shift > 127) { + v128_set_to_zero(x); + return; + } + + const int base_index = shift >> 5; + const int bit_index = shift & 31; + + __m128i mm = _mm_loadu_si128((const __m128i *)x); + __m128i mm_shift_right = _mm_cvtsi32_si128(bit_index); + __m128i mm_shift_left = _mm_cvtsi32_si128(32 - bit_index); + mm = _mm_shuffle_epi8(mm, ((const __m128i *)left_shift_masks)[base_index]); + + __m128i mm1 = _mm_srl_epi32(mm, mm_shift_right); + __m128i mm2 = _mm_sll_epi32(mm, mm_shift_left); + mm2 = _mm_srli_si128(mm2, 4); + mm1 = _mm_or_si128(mm1, mm2); + + _mm_storeu_si128((__m128i *)x, mm1); +} + +#else /* defined(__SSSE3__) */ + void v128_left_shift(v128_t *x, int shift) { int i; const int base_index = shift >> 5; const int bit_index = shift & 31; @@ -177,10 +249,12 @@ /* now wrap up the final portion */ for (i = 4 - base_index; i < 4; i++) x->v32[i] = 0; } +#endif /* defined(__SSSE3__) */ + /* functions manipulating bitvector_t */ int bitvector_alloc(bitvector_t *v, unsigned long length) { unsigned long l; @@ -188,10 +262,11 @@ /* Round length up to a multiple of bits_per_word */ length = (length + bits_per_word - 1) & ~(unsigned long)((bits_per_word - 1)); l = length / bits_per_word * bytes_per_word; + l = (l + 15ul) & ~15ul; /* allocate memory, then set parameters */ if (l == 0) { v->word = NULL; v->length = 0; @@ -223,10 +298,77 @@ { /* C99 guarantees that memset(0) will set the value 0 for uint32_t */ memset(x->word, 0, x->length >> 3); } +#if defined(__SSSE3__) + +void bitvector_left_shift(bitvector_t *x, int shift) +{ + if ((uint32_t)shift >= x->length) { + bitvector_set_to_zero(x); + return; + } + + const int base_index = shift >> 5; + const int bit_index = shift & 31; + const int vec_length = (x->length + 127u) >> 7; + const __m128i *from = ((const __m128i *)x->word) + (base_index >> 2); + __m128i *to = (__m128i *)x->word; + __m128i *const end = to + vec_length; + + __m128i mm_right_shift_mask = + ((const __m128i *)right_shift_masks)[4u - (base_index & 3u)]; + __m128i mm_left_shift_mask = + ((const __m128i *)left_shift_masks)[base_index & 3u]; + __m128i mm_shift_right = _mm_cvtsi32_si128(bit_index); + __m128i mm_shift_left = _mm_cvtsi32_si128(32 - bit_index); + + __m128i mm_current = _mm_loadu_si128(from); + __m128i mm_current_r = _mm_srl_epi32(mm_current, mm_shift_right); + __m128i mm_current_l = _mm_sll_epi32(mm_current, mm_shift_left); + + while ((end - from) >= 2) { + ++from; + __m128i mm_next = _mm_loadu_si128(from); + + __m128i mm_next_r = _mm_srl_epi32(mm_next, mm_shift_right); + __m128i mm_next_l = _mm_sll_epi32(mm_next, mm_shift_left); + mm_current_l = _mm_alignr_epi8(mm_next_l, mm_current_l, 4); + mm_current = _mm_or_si128(mm_current_r, mm_current_l); + + mm_current = _mm_shuffle_epi8(mm_current, mm_left_shift_mask); + + __m128i mm_temp_next = _mm_srli_si128(mm_next_l, 4); + mm_temp_next = _mm_or_si128(mm_next_r, mm_temp_next); + + mm_temp_next = _mm_shuffle_epi8(mm_temp_next, mm_right_shift_mask); + mm_current = _mm_or_si128(mm_temp_next, mm_current); + + _mm_storeu_si128(to, mm_current); + ++to; + + mm_current_r = mm_next_r; + mm_current_l = mm_next_l; + } + + mm_current_l = _mm_srli_si128(mm_current_l, 4); + mm_current = _mm_or_si128(mm_current_r, mm_current_l); + + mm_current = _mm_shuffle_epi8(mm_current, mm_left_shift_mask); + + _mm_storeu_si128(to, mm_current); + ++to; + + while (to < end) { + _mm_storeu_si128(to, _mm_setzero_si128()); + ++to; + } +} + +#else /* defined(__SSSE3__) */ + void bitvector_left_shift(bitvector_t *x, int shift) { int i; const int base_index = shift >> 5; const int bit_index = shift & 31; @@ -251,37 +393,108 @@ /* now wrap up the final portion */ for (i = word_length - base_index; i < word_length; i++) x->word[i] = 0; } -int srtp_octet_string_is_eq(uint8_t *a, uint8_t *b, int len) +#endif /* defined(__SSSE3__) */ + +int srtp_octet_string_is_eq(const uint8_t *a, const uint8_t *b, int len) { - uint8_t *end = b + len; - uint8_t accumulator = 0; - /* * We use this somewhat obscure implementation to try to ensure the running * time only depends on len, even accounting for compiler optimizations. * The accumulator ends up zero iff the strings are equal. */ + const uint8_t *end = b + len; + uint32_t accumulator = 0; + +#if defined(__SSE2__) + __m128i mm_accumulator1 = _mm_setzero_si128(); + __m128i mm_accumulator2 = _mm_setzero_si128(); + for (int i = 0, n = len >> 5; i < n; ++i, a += 32, b += 32) { + __m128i mm_a1 = _mm_loadu_si128((const __m128i *)a); + __m128i mm_b1 = _mm_loadu_si128((const __m128i *)b); + __m128i mm_a2 = _mm_loadu_si128((const __m128i *)(a + 16)); + __m128i mm_b2 = _mm_loadu_si128((const __m128i *)(b + 16)); + mm_a1 = _mm_xor_si128(mm_a1, mm_b1); + mm_a2 = _mm_xor_si128(mm_a2, mm_b2); + mm_accumulator1 = _mm_or_si128(mm_accumulator1, mm_a1); + mm_accumulator2 = _mm_or_si128(mm_accumulator2, mm_a2); + } + + mm_accumulator1 = _mm_or_si128(mm_accumulator1, mm_accumulator2); + + if ((end - b) >= 16) { + __m128i mm_a1 = _mm_loadu_si128((const __m128i *)a); + __m128i mm_b1 = _mm_loadu_si128((const __m128i *)b); + mm_a1 = _mm_xor_si128(mm_a1, mm_b1); + mm_accumulator1 = _mm_or_si128(mm_accumulator1, mm_a1); + a += 16; + b += 16; + } + + if ((end - b) >= 8) { + __m128i mm_a1 = _mm_loadl_epi64((const __m128i *)a); + __m128i mm_b1 = _mm_loadl_epi64((const __m128i *)b); + mm_a1 = _mm_xor_si128(mm_a1, mm_b1); + mm_accumulator1 = _mm_or_si128(mm_accumulator1, mm_a1); + a += 8; + b += 8; + } + + mm_accumulator1 = _mm_or_si128( + mm_accumulator1, _mm_unpackhi_epi64(mm_accumulator1, mm_accumulator1)); + mm_accumulator1 = + _mm_or_si128(mm_accumulator1, _mm_srli_si128(mm_accumulator1, 4)); + accumulator = _mm_cvtsi128_si32(mm_accumulator1); +#else + uint32_t accumulator2 = 0; + for (int i = 0, n = len >> 3; i < n; ++i, a += 8, b += 8) { + uint32_t a_val1, b_val1; + uint32_t a_val2, b_val2; + memcpy(&a_val1, a, sizeof(a_val1)); + memcpy(&b_val1, b, sizeof(b_val1)); + memcpy(&a_val2, a + 4, sizeof(a_val2)); + memcpy(&b_val2, b + 4, sizeof(b_val2)); + accumulator |= a_val1 ^ b_val1; + accumulator2 |= a_val2 ^ b_val2; + } + + accumulator |= accumulator2; + + if ((end - b) >= 4) { + uint32_t a_val, b_val; + memcpy(&a_val, a, sizeof(a_val)); + memcpy(&b_val, b, sizeof(b_val)); + accumulator |= a_val ^ b_val; + a += 4; + b += 4; + } +#endif + while (b < end) accumulator |= (*a++ ^ *b++); /* Return 1 if *not* equal. */ return accumulator != 0; } void srtp_cleanse(void *s, size_t len) { +#if defined(__GNUC__) + memset(s, 0, len); + __asm__ __volatile__("" : : "r"(s) : "memory"); +#else volatile unsigned char *p = (volatile unsigned char *)s; while (len--) *p++ = 0; +#endif } void octet_string_set_to_zero(void *s, size_t len) { -#if defined(OPENSSL) && !defined(OPENSSL_CLEANSE_BROKEN) +#if defined(OPENSSL) OPENSSL_cleanse(s, len); #else srtp_cleanse(s, len); #endif } diff --git a/third_party/libsrtp/src/crypto/replay/rdbx.c b/third_party/libsrtp/src/crypto/replay/rdbx.c --- a/third_party/libsrtp/src/crypto/replay/rdbx.c +++ b/third_party/libsrtp/src/crypto/replay/rdbx.c @@ -277,11 +277,11 @@ */ srtp_err_status_t srtp_rdbx_add_index(srtp_rdbx_t *rdbx, int delta) { if (delta > 0) { /* shift forward by delta */ - srtp_index_advance(&rdbx->index, delta); + srtp_index_advance(&rdbx->index, (srtp_sequence_number_t)delta); bitvector_left_shift(&rdbx->bitmask, delta); bitvector_set_bit(&rdbx->bitmask, bitvector_get_length(&rdbx->bitmask) - 1); } else { /* delta is in window */ @@ -304,17 +304,17 @@ */ int32_t srtp_rdbx_estimate_index(const srtp_rdbx_t *rdbx, srtp_xtd_seq_num_t *guess, srtp_sequence_number_t s) { -/* - * if the sequence number and rollover counter in the rdbx are - * non-zero, then use the srtp_index_guess(...) function, otherwise, just - * set the rollover counter to zero (since the srtp_index_guess(...) - * function might incorrectly guess that the rollover counter is - * 0xffffffff) - */ + /* + * if the sequence number and rollover counter in the rdbx are + * non-zero, then use the srtp_index_guess(...) function, otherwise, just + * set the rollover counter to zero (since the srtp_index_guess(...) + * function might incorrectly guess that the rollover counter is + * 0xffffffff) + */ #ifdef NO_64BIT_MATH /* seq_num_median = 0x8000 */ if (high32(rdbx->index) > 0 || low32(rdbx->index) > seq_num_median) #else diff --git a/third_party/libsrtp/src/crypto/test/.cvsignore b/third_party/libsrtp/src/crypto/test/.cvsignore deleted file mode 100644 --- a/third_party/libsrtp/src/crypto/test/.cvsignore +++ /dev/null @@ -1,8 +0,0 @@ -aes_calc -cipher_driver -datatypes_driver -env -kernel_driver -rand_gen -sha1_driver -stat_driver diff --git a/third_party/libsrtp/src/crypto/test/aes_calc.c b/third_party/libsrtp/src/crypto/test/aes_calc.c --- a/third_party/libsrtp/src/crypto/test/aes_calc.c +++ b/third_party/libsrtp/src/crypto/test/aes_calc.c @@ -104,37 +104,41 @@ } } /* read in key, checking length */ if (strlen(argv[1]) > AES_MAX_KEY_LEN * 2) { - fprintf(stderr, "error: too many digits in key " - "(should be at most %d hexadecimal digits, found %u)\n", + fprintf(stderr, + "error: too many digits in key " + "(should be at most %d hexadecimal digits, found %u)\n", AES_MAX_KEY_LEN * 2, (unsigned)strlen(argv[1])); exit(1); } len = hex_string_to_octet_string((char *)key, argv[1], AES_MAX_KEY_LEN * 2); /* check that hex string is the right length */ if (len != 32 && len != 48 && len != 64) { - fprintf(stderr, "error: bad number of digits in key " - "(should be 32/48/64 hexadecimal digits, found %d)\n", + fprintf(stderr, + "error: bad number of digits in key " + "(should be 32/48/64 hexadecimal digits, found %d)\n", len); exit(1); } key_len = len / 2; /* read in plaintext, checking length */ if (strlen(argv[2]) > 16 * 2) { - fprintf(stderr, "error: too many digits in plaintext " - "(should be %d hexadecimal digits, found %u)\n", + fprintf(stderr, + "error: too many digits in plaintext " + "(should be %d hexadecimal digits, found %u)\n", 16 * 2, (unsigned)strlen(argv[2])); exit(1); } len = hex_string_to_octet_string((char *)(&data), argv[2], 16 * 2); /* check that hex string is the right length */ if (len < 16 * 2) { - fprintf(stderr, "error: too few digits in plaintext " - "(should be %d hexadecimal digits, found %d)\n", + fprintf(stderr, + "error: too few digits in plaintext " + "(should be %d hexadecimal digits, found %d)\n", 16 * 2, len); exit(1); } if (verbose) { @@ -160,12 +164,13 @@ ciphertext = v128_hex_string(&data); printf("%s\n", ciphertext); if (expected_ciphertext && strcmp(ciphertext, expected_ciphertext) != 0) { - fprintf(stderr, "error: calculated ciphertext %s does not match " - "expected ciphertext %s\n", + fprintf(stderr, + "error: calculated ciphertext %s does not match " + "expected ciphertext %s\n", ciphertext, expected_ciphertext); exit(1); } return 0; diff --git a/third_party/libsrtp/src/crypto/test/cipher_driver.c b/third_party/libsrtp/src/crypto/test/cipher_driver.c --- a/third_party/libsrtp/src/crypto/test/cipher_driver.c +++ b/third_party/libsrtp/src/crypto/test/cipher_driver.c @@ -387,11 +387,11 @@ /* choose a short length */ len = srtp_cipher_rand_u32_for_tests() & 0x01f; /* make sure that len doesn't cause us to overreach the buffer */ if (current + len > end) - len = end - current; + len = (unsigned)(end - current); status = srtp_cipher_encrypt(c, current, &len); if (status) return status; @@ -436,11 +436,11 @@ srtp_cipher_type_t *ctype, int klen) { int i, j; srtp_err_status_t status; - uint8_t *key; + uint8_t *key = NULL; srtp_cipher_t **cipher_array; /* pad klen allocation, to handle aes_icm reading 16 bytes for the 14-byte salt */ int klen_pad = ((klen + 15) >> 4) << 4; @@ -451,15 +451,17 @@ return srtp_err_status_alloc_fail; /* set ca to location of cipher_array */ *ca = cipher_array; - /* allocate key */ - key = srtp_crypto_alloc(klen_pad); - if (key == NULL) { - srtp_crypto_free(cipher_array); - return srtp_err_status_alloc_fail; + /* allocate key , allow zero key for example null cipher */ + if (klen_pad > 0) { + key = srtp_crypto_alloc(klen_pad); + if (key == NULL) { + srtp_crypto_free(cipher_array); + return srtp_err_status_alloc_fail; + } } /* allocate and initialize an array of ciphers */ for (i = 0; i < num_ciphers; i++) { /* allocate cipher */ diff --git a/third_party/libsrtp/src/crypto/test/datatypes_driver.c b/third_party/libsrtp/src/crypto/test/datatypes_driver.c --- a/third_party/libsrtp/src/crypto/test/datatypes_driver.c +++ b/third_party/libsrtp/src/crypto/test/datatypes_driver.c @@ -137,32 +137,32 @@ /* byte_order() prints out byte ordering of datatypes */ void byte_order(void) { - int i; + size_t i; v128_t e; printf("byte ordering of crypto/math datatypes:\n"); for (i = 0; i < sizeof(e); i++) - e.v8[i] = i; + e.v8[i] = (uint8_t)i; printf("v128_t: %s\n", v128_hex_string(&e)); } void test_hex_string_funcs(void) { char hex1[] = "abadcafe"; char hex2[] = "0123456789abcdefqqqqq"; char raw[10]; int len; - len = hex_string_to_octet_string(raw, hex1, strlen(hex1)); + len = hex_string_to_octet_string(raw, hex1, (int)strlen(hex1)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len / 2)); printf("expected length: %u\tstring: %s\n", (unsigned)strlen(hex1), hex1); - len = hex_string_to_octet_string(raw, hex2, strlen(hex2)); + len = hex_string_to_octet_string(raw, hex2, (int)strlen(hex2)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len / 2)); printf("expected length: %d\tstring: %s\n", 16, "0123456789abcdef"); } diff --git a/third_party/libsrtp/src/crypto/test/meson.build b/third_party/libsrtp/src/crypto/test/meson.build --- a/third_party/libsrtp/src/crypto/test/meson.build +++ b/third_party/libsrtp/src/crypto/test/meson.build @@ -5,11 +5,11 @@ 'datatypes_driver', 'kernel_driver', 'env', ] -if not use_openssl and not use_nss +if not use_openssl and not use_nss and not use_mbedtls test_apps += ['sha1_driver'] endif foreach test_name : test_apps test_exe = executable(test_name, @@ -18,11 +18,11 @@ dependencies: [srtp2_deps, syslibs], link_with: libsrtp2_for_tests) test(test_name, test_exe, args: ['-v']) endforeach -if not use_openssl and not use_nss +if not use_openssl and not use_nss and not use_mbedtls test_exe = executable('aes_calc', 'aes_calc.c', '../../test/getopt_s.c', '../../test/util.c', include_directories: [config_incs, crypto_incs, srtp2_incs, test_incs], dependencies: [srtp2_deps, syslibs], link_with: libsrtp2_for_tests) diff --git a/third_party/libsrtp/src/crypto/test/sha1_driver.c b/third_party/libsrtp/src/crypto/test/sha1_driver.c --- a/third_party/libsrtp/src/crypto/test/sha1_driver.c +++ b/third_party/libsrtp/src/crypto/test/sha1_driver.c @@ -141,11 +141,11 @@ } struct hex_sha1_test_case_t { unsigned bit_len; char hex_data[MAX_HASH_DATA_LEN * 2]; - char hex_hash[40]; + char hex_hash[40 + 1]; }; srtp_err_status_t sha1_add_test_cases(void) { int i; @@ -216,104 +216,135 @@ "041c512b5eed791f80d3282f3a28df263bb1df95e1239a7650e5670fc2187919", "e88cdcd233d99184a6fd260b8fca1b7f7687aee0" }, { 264, "17e81f6ae8c2e5579d69dafa6e070e7111461552d314b691e7a3e7a4feb3fae418", "010def22850deb1168d525e8c84c28116cb8a269" }, - { 272, "d15976b23a1d712ad28fad04d805f572026b54dd64961fda94d5355a0cc9862" - "0cf77", + { 272, + "d15976b23a1d712ad28fad04d805f572026b54dd64961fda94d5355a0cc9862" + "0cf77", "aeaa40ba1717ed5439b1e6ea901b294ba500f9ad" }, - { 280, "09fce4d434f6bd32a44e04b848ff50ec9f642a8a85b37a264dc73f130f22838" - "443328f", + { 280, + "09fce4d434f6bd32a44e04b848ff50ec9f642a8a85b37a264dc73f130f22838" + "443328f", "c6433791238795e34f080a5f1f1723f065463ca0" }, - { 288, "f17af27d776ec82a257d8d46d2b46b639462c56984cc1be9c1222eadb8b2659" - "4a25c709d", + { 288, + "f17af27d776ec82a257d8d46d2b46b639462c56984cc1be9c1222eadb8b2659" + "4a25c709d", "e21e22b89c1bb944a32932e6b2a2f20d491982c3" }, - { 296, "b13ce635d6f8758143ffb114f2f601cb20b6276951416a2f94fbf4ad081779d" - "79f4f195b22", + { 296, + "b13ce635d6f8758143ffb114f2f601cb20b6276951416a2f94fbf4ad081779d" + "79f4f195b22", "575323a9661f5d28387964d2ba6ab92c17d05a8a" }, - { 304, "5498793f60916ff1c918dde572cdea76da8629ba4ead6d065de3dfb48de94d2" - "34cc1c5002910", + { 304, + "5498793f60916ff1c918dde572cdea76da8629ba4ead6d065de3dfb48de94d2" + "34cc1c5002910", "feb44494af72f245bfe68e86c4d7986d57c11db7" }, - { 312, "498a1e0b39fa49582ae688cd715c86fbaf8a81b8b11b4d1594c49c902d197c8" - "ba8a621fd6e3be5", + { 312, + "498a1e0b39fa49582ae688cd715c86fbaf8a81b8b11b4d1594c49c902d197c8" + "ba8a621fd6e3be5", "cff2290b3648ba2831b98dde436a72f9ebf51eee" }, - { 320, "3a36ae71521f9af628b3e34dcb0d4513f84c78ee49f10416a98857150b8b15c" - "b5c83afb4b570376e", + { 320, + "3a36ae71521f9af628b3e34dcb0d4513f84c78ee49f10416a98857150b8b15c" + "b5c83afb4b570376e", "9b4efe9d27b965905b0c3dab67b8d7c9ebacd56c" }, - { 328, "dcc76b40ae0ea3ba253e92ac50fcde791662c5b6c948538cffc2d95e9de99ca" - "c34dfca38910db2678f", + { 328, + "dcc76b40ae0ea3ba253e92ac50fcde791662c5b6c948538cffc2d95e9de99ca" + "c34dfca38910db2678f", "afedb0ff156205bcd831cbdbda43db8b0588c113" }, - { 336, "5b5ec6ec4fd3ad9c4906f65c747fd4233c11a1736b6b228b92e90cddabb0c7c" - "2fcf9716d3fad261dff33", + { 336, + "5b5ec6ec4fd3ad9c4906f65c747fd4233c11a1736b6b228b92e90cddabb0c7c" + "2fcf9716d3fad261dff33", "8deb1e858f88293a5e5e4d521a34b2a4efa70fc4" }, - { 344, "df48a37b29b1d6de4e94717d60cdb4293fcf170bba388bddf7a9035a15d433f" - "20fd697c3e4c8b8c5f590ab", + { 344, + "df48a37b29b1d6de4e94717d60cdb4293fcf170bba388bddf7a9035a15d433f" + "20fd697c3e4c8b8c5f590ab", "95cbdac0f74afa69cebd0e5c7defbc6faf0cbeaf" }, - { 352, "1f179b3b82250a65e1b0aee949e218e2f45c7a8dbfd6ba08de05c55acfc226b" - "48c68d7f7057e5675cd96fcfc", + { 352, + "1f179b3b82250a65e1b0aee949e218e2f45c7a8dbfd6ba08de05c55acfc226b" + "48c68d7f7057e5675cd96fcfc", "f0307bcb92842e5ae0cd4f4f14f3df7f877fbef2" }, - { 360, "ee3d72da3a44d971578972a8e6780ce64941267e0f7d0179b214fa97855e179" - "0e888e09fbe3a70412176cb3b54", + { 360, + "ee3d72da3a44d971578972a8e6780ce64941267e0f7d0179b214fa97855e179" + "0e888e09fbe3a70412176cb3b54", "7b13bb0dbf14964bd63b133ac85e22100542ef55" }, - { 368, "d4d4c7843d312b30f610b3682254c8be96d5f6684503f8fbfbcd15774fc1b08" - "4d3741afb8d24aaa8ab9c104f7258", + { 368, + "d4d4c7843d312b30f610b3682254c8be96d5f6684503f8fbfbcd15774fc1b08" + "4d3741afb8d24aaa8ab9c104f7258", "c314d2b6cf439be678d2a74e890d96cfac1c02ed" }, - { 376, "32c094944f5936a190a0877fb9178a7bf60ceae36fd530671c5b38c5dbd5e6a" - "6c0d615c2ac8ad04b213cc589541cf6", + { 376, + "32c094944f5936a190a0877fb9178a7bf60ceae36fd530671c5b38c5dbd5e6a" + "6c0d615c2ac8ad04b213cc589541cf6", "4d0be361e410b47a9d67d8ce0bb6a8e01c53c078" }, - { 384, "e5d3180c14bf27a5409fa12b104a8fd7e9639609bfde6ee82bbf9648be2546d" - "29688a65e2e3f3da47a45ac14343c9c02", + { 384, + "e5d3180c14bf27a5409fa12b104a8fd7e9639609bfde6ee82bbf9648be2546d" + "29688a65e2e3f3da47a45ac14343c9c02", "e5353431ffae097f675cbf498869f6fbb6e1c9f2" }, - { 392, "e7b6e4b69f724327e41e1188a37f4fe38b1dba19cbf5a7311d6e32f1038e97a" - "b506ee05aebebc1eed09fc0e357109818b9", + { 392, + "e7b6e4b69f724327e41e1188a37f4fe38b1dba19cbf5a7311d6e32f1038e97a" + "b506ee05aebebc1eed09fc0e357109818b9", "b8720a7068a085c018ab18961de2765aa6cd9ac4" }, - { 400, "bc880cb83b8ac68ef2fedc2da95e7677ce2aa18b0e2d8b322701f67af7d5e7a" - "0d96e9e33326ccb7747cfff0852b961bfd475", + { 400, + "bc880cb83b8ac68ef2fedc2da95e7677ce2aa18b0e2d8b322701f67af7d5e7a" + "0d96e9e33326ccb7747cfff0852b961bfd475", "b0732181568543ba85f2b6da602b4b065d9931aa" }, - { 408, "235ea9c2ba7af25400f2e98a47a291b0bccdaad63faa2475721fda5510cc7da" - "d814bce8dabb611790a6abe56030b798b75c944", + { 408, + "235ea9c2ba7af25400f2e98a47a291b0bccdaad63faa2475721fda5510cc7da" + "d814bce8dabb611790a6abe56030b798b75c944", "9c22674cf3222c3ba921672694aafee4ce67b96b" }, - { 416, "07e3e29fed63104b8410f323b975fd9fba53f636af8c4e68a53fb202ca35dd9" - "ee07cb169ec5186292e44c27e5696a967f5e67709", + { 416, + "07e3e29fed63104b8410f323b975fd9fba53f636af8c4e68a53fb202ca35dd9" + "ee07cb169ec5186292e44c27e5696a967f5e67709", "d128335f4cecca9066cdae08958ce656ff0b4cfc" }, - { 424, "65d2a1dd60a517eb27bfbf530cf6a5458f9d5f4730058bd9814379547f34241" - "822bf67e6335a6d8b5ed06abf8841884c636a25733f", + { 424, + "65d2a1dd60a517eb27bfbf530cf6a5458f9d5f4730058bd9814379547f34241" + "822bf67e6335a6d8b5ed06abf8841884c636a25733f", "0b67c57ac578de88a2ae055caeaec8bb9b0085a0" }, - { 432, "dcc86b3bd461615bab739d8daafac231c0f462e819ad29f9f14058f3ab5b759" - "41d4241ea2f17ebb8a458831b37a9b16dead4a76a9b0e", + { 432, + "dcc86b3bd461615bab739d8daafac231c0f462e819ad29f9f14058f3ab5b759" + "41d4241ea2f17ebb8a458831b37a9b16dead4a76a9b0e", "c766f912a89d4ccda88e0cce6a713ef5f178b596" }, - { 440, "4627d54f0568dc126b62a8c35fb46a9ac5024400f2995e51635636e1afc4373" - "dbb848eb32df23914230560b82477e9c3572647a7f2bb92", + { 440, + "4627d54f0568dc126b62a8c35fb46a9ac5024400f2995e51635636e1afc4373" + "dbb848eb32df23914230560b82477e9c3572647a7f2bb92", "9aa3925a9dcb177b15ccff9b78e70cf344858779" }, - { 448, "ba531affd4381168ef24d8b275a84d9254c7f5cc55fded53aa8024b2c5c5c8a" - "a7146fe1d1b83d62b70467e9a2e2cb67b3361830adbab28d7", + { 448, + "ba531affd4381168ef24d8b275a84d9254c7f5cc55fded53aa8024b2c5c5c8a" + "a7146fe1d1b83d62b70467e9a2e2cb67b3361830adbab28d7", "4811fa30042fc076acf37c8e2274d025307e5943" }, - { 456, "8764dcbcf89dcf4282eb644e3d568bdccb4b13508bfa7bfe0ffc05efd1390be" - "22109969262992d377691eb4f77f3d59ea8466a74abf57b2ef4", + { 456, + "8764dcbcf89dcf4282eb644e3d568bdccb4b13508bfa7bfe0ffc05efd1390be" + "22109969262992d377691eb4f77f3d59ea8466a74abf57b2ef4", "6743018450c9730761ee2b130df9b91c1e118150" }, - { 464, "497d9df9ddb554f3d17870b1a31986c1be277bc44feff713544217a9f579623" - "d18b5ffae306c25a45521d2759a72c0459b58957255ab592f3be4", + { 464, + "497d9df9ddb554f3d17870b1a31986c1be277bc44feff713544217a9f579623" + "d18b5ffae306c25a45521d2759a72c0459b58957255ab592f3be4", "71ad4a19d37d92a5e6ef3694ddbeb5aa61ada645" }, - { 472, "72c3c2e065aefa8d9f7a65229e818176eef05da83f835107ba90ec2e95472e7" - "3e538f783b416c04654ba8909f26a12db6e5c4e376b7615e4a25819", + { 472, + "72c3c2e065aefa8d9f7a65229e818176eef05da83f835107ba90ec2e95472e7" + "3e538f783b416c04654ba8909f26a12db6e5c4e376b7615e4a25819", "a7d9dc68dacefb7d6116186048cb355cc548e11d" }, - { 480, "7cc9894454d0055ab5069a33984e2f712bef7e3124960d33559f5f3b81906bb" - "66fe64da13c153ca7f5cabc89667314c32c01036d12ecaf5f9a78de98", + { 480, + "7cc9894454d0055ab5069a33984e2f712bef7e3124960d33559f5f3b81906bb" + "66fe64da13c153ca7f5cabc89667314c32c01036d12ecaf5f9a78de98", "142e429f0522ba5abf5131fa81df82d355b96909" }, - { 488, "74e8404d5a453c5f4d306f2cfa338ca65501c840ddab3fb82117933483afd69" - "13c56aaf8a0a0a6b2a342fc3d9dc7599f4a850dfa15d06c61966d74ea59", + { 488, + "74e8404d5a453c5f4d306f2cfa338ca65501c840ddab3fb82117933483afd69" + "13c56aaf8a0a0a6b2a342fc3d9dc7599f4a850dfa15d06c61966d74ea59", "ef72db70dcbcab991e9637976c6faf00d22caae9" }, - { 496, "46fe5ed326c8fe376fcc92dc9e2714e2240d3253b105adfbb256ff7a19bc409" - "75c604ad7c0071c4fd78a7cb64786e1bece548fa4833c04065fe593f6fb10", + { 496, + "46fe5ed326c8fe376fcc92dc9e2714e2240d3253b105adfbb256ff7a19bc409" + "75c604ad7c0071c4fd78a7cb64786e1bece548fa4833c04065fe593f6fb10", "f220a7457f4588d639dc21407c942e9843f8e26b" }, - { 504, "836dfa2524d621cf07c3d2908835de859e549d35030433c796b81272fd8bc03" - "48e8ddbc7705a5ad1fdf2155b6bc48884ac0cd376925f069a37849c089c864" - "5", + { 504, + "836dfa2524d621cf07c3d2908835de859e549d35030433c796b81272fd8bc03" + "48e8ddbc7705a5ad1fdf2155b6bc48884ac0cd376925f069a37849c089c864" + "5", "ddd2117b6e309c233ede85f962a0c2fc215e5c69" }, - { 512, "7e3a4c325cb9c52b88387f93d01ae86d42098f5efa7f9457388b5e74b6d28b2" - "438d42d8b64703324d4aa25ab6aad153ae30cd2b2af4d5e5c00a8a2d0220c61" - "16", + { 512, + "7e3a4c325cb9c52b88387f93d01ae86d42098f5efa7f9457388b5e74b6d28b2" + "438d42d8b64703324d4aa25ab6aad153ae30cd2b2af4d5e5c00a8a2d0220c61" + "16", "a3054427cdb13f164a610b348702724c808a0dcc" } }; for (i = 0; i < 65; i++) { err = hash_test_case_add(&sha1_test_case_list, tc[i].hex_data, diff --git a/third_party/libsrtp/src/include/config.h b/third_party/libsrtp/src/include/config.h deleted file mode 100644 --- a/third_party/libsrtp/src/include/config.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -/* empty file; config done via Makefile.in & configure.in */ diff --git a/third_party/libsrtp/src/include/srtp.h b/third_party/libsrtp/src/include/srtp.h --- a/third_party/libsrtp/src/include/srtp.h +++ b/third_party/libsrtp/src/include/srtp.h @@ -92,10 +92,27 @@ * @brief the maximum number of octets added by srtp_protect(). */ #define SRTP_MAX_TRAILER_LEN (SRTP_MAX_TAG_LEN + SRTP_MAX_MKI_LEN) /** + * SRTP_SRCTP_INDEX_LEN is the size the SRTCP index which is + * 4 bytes + */ +#define SRTP_SRCTP_INDEX_LEN 4 + +/** + * SRTP_MAX_SRTCP_TRAILER_LEN is the maximum length of the SRTCP trailer + * (index, authentication tag and MKI) supported by libSRTP. This value is + * the maximum number of octets that will be added to an RTCP packet by + * srtp_protect_rtcp(). + * + * @brief the maximum number of octets added by srtp_protect(). + */ +#define SRTP_MAX_SRTCP_TRAILER_LEN \ + (SRTP_SRCTP_INDEX_LEN + SRTP_MAX_TAG_LEN + SRTP_MAX_MKI_LEN) + +/** * SRTP_MAX_NUM_MASTER_KEYS is the maximum number of Master keys for * MKI supported by libSRTP. * */ #define SRTP_MAX_NUM_MASTER_KEYS 16 @@ -612,11 +629,11 @@ * @return * - srtp_err_status_ok if the stream deallocation succeeded. * - [other] otherwise. * */ -srtp_err_status_t srtp_remove_stream(srtp_t session, unsigned int ssrc); +srtp_err_status_t srtp_remove_stream(srtp_t session, uint32_t ssrc); /** * @brief srtp_update() updates all streams in the session. * * The function call srtp_update(session, policy) updates @@ -1165,11 +1182,11 @@ srtp_profile_aes128_cm_sha1_80 = 1, srtp_profile_aes128_cm_sha1_32 = 2, srtp_profile_null_sha1_80 = 5, srtp_profile_null_sha1_32 = 6, srtp_profile_aead_aes_128_gcm = 7, - srtp_profile_aead_aes_256_gcm = 8, + srtp_profile_aead_aes_256_gcm = 8 } srtp_profile_t; /** * @brief srtp_crypto_policy_set_from_profile_for_rtp() sets a crypto policy * structure to the appropriate value for RTP based on an srtp_profile_t @@ -1287,11 +1304,11 @@ * @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 * boundary. * - * @warning This function assumes that it can write SRTP_MAX_TRAILER_LEN+4 + * @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. @@ -1328,11 +1345,11 @@ * @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 * boundary. * - * @warning This function assumes that it can write SRTP_MAX_TRAILER_LEN+4 + * @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. diff --git a/third_party/libsrtp/src/include/srtp2/meson.build b/third_party/libsrtp/src/include/srtp2/meson.build --- a/third_party/libsrtp/src/include/srtp2/meson.build +++ b/third_party/libsrtp/src/include/srtp2/meson.build @@ -3,6 +3,5 @@ foreach h : public_headers configure_file(input: h, output: '@BASENAME@.h', copy: true) endforeach -public_incs = include_directories('.') diff --git a/third_party/libsrtp/src/include/srtp_priv.h b/third_party/libsrtp/src/include/srtp_priv.h --- a/third_party/libsrtp/src/include/srtp_priv.h +++ b/third_party/libsrtp/src/include/srtp_priv.h @@ -64,10 +64,11 @@ #define SRTP_VER_STRING PACKAGE_STRING #define SRTP_VERSION PACKAGE_VERSION typedef struct srtp_stream_ctx_t_ srtp_stream_ctx_t; typedef srtp_stream_ctx_t *srtp_stream_t; +typedef struct srtp_stream_list_ctx_t_ *srtp_stream_list_t; /* * the following declarations are libSRTP internal functions */ @@ -95,16 +96,10 @@ unsigned char *key, srtp_master_key_t **keys, const unsigned int max_master_keys); /* - * srtp_stream_init(s, p) initializes the srtp_stream_t s to - * use the policy at the location p - */ -srtp_err_status_t srtp_stream_init(srtp_stream_t srtp, const srtp_policy_t *p); - -/* * libsrtp internal datatypes */ typedef enum direction_t { dir_unknown = 0, dir_srtp_sender = 1, @@ -147,18 +142,25 @@ direction_t direction; int allow_repeat_tx; int *enc_xtn_hdr; int enc_xtn_hdr_count; uint32_t pending_roc; - struct srtp_stream_ctx_t_ *next; /* linked list of streams */ + /* + The next and prev pointers are here to allow for a stream list to be + implemented as an intrusive doubly-linked list (the former being the + default). Other stream list implementations can ignore these fields or use + them for some other purpose specific to the stream list implementation. + */ + struct srtp_stream_ctx_t_ *next; + struct srtp_stream_ctx_t_ *prev; } strp_stream_ctx_t_; /* * an srtp_ctx_t holds a stream list and a service description */ typedef struct srtp_ctx_t_ { - struct srtp_stream_ctx_t_ *stream_list; /* linked list of streams */ + srtp_stream_list_t stream_list; /* linked list of streams */ struct srtp_stream_ctx_t_ *stream_template; /* act as template for other */ /* streams */ void *user_data; /* user custom data */ } srtp_ctx_t_; diff --git a/third_party/libsrtp/src/include/stream_list_priv.h b/third_party/libsrtp/src/include/stream_list_priv.h new file mode 100644 --- /dev/null +++ b/third_party/libsrtp/src/include/stream_list_priv.h @@ -0,0 +1,122 @@ +/* + * stream_list_priv.h + * + * list of SRTP streams, keyed by SSRC + * + * Alba Mendez + */ +/* + * + * Copyright (c) 2001-2017, Cisco Systems, Inc. + * Copyright (c) 2022, Dolby Laboratories, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef SRTP_STREAM_LIST_PRIV_H +#define SRTP_STREAM_LIST_PRIV_H + +#include "srtp_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * srtp_stream_list_t holds a list of srtp_stream_t, each identified + * by their SSRC. + * + * the API was extracted to allow downstreams to override its + * implementation by defining the `SRTP_NO_STREAM_LIST` preprocessor + * directive, which removes the default implementation of these + * functions. if this is done, the `next` & `prev` fields are free for + * the implementation to use. + * + * this is still an internal interface; there is no stability + * guarantee--downstreams should watch this file for changes in + * signatures or semantics. + */ + +/** + * allocate and initialize a stream list instance + */ +srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr); + +/** + * deallocate a stream list instance + * + * the list must be empty or else an error is returned. + */ +srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list); + +/** + * insert a stream into the list + * + * returns srtp_err_status_alloc_fail if insertion failed due to unavailable + * capacity in the list. if operation succeeds, srtp_err_status_ok is returned + * + * if another stream with the same SSRC already exists in the list, + * behavior is undefined. if the SSRC field is mutated while the + * stream is inserted, further operations have undefined behavior + */ +srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list, + srtp_stream_t stream); + +/* + * look up the stream corresponding to the specified SSRC and return it. + * if no such SSRC is found, NULL is returned. + */ +srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc); + +/** + * remove the stream from the list. + * + * The stream to be removed is referenced "by value", i.e., by the pointer to be + * removed from the list. This pointer is obtained using `srtp_stream_list_get` + * or as callback parameter in `srtp_stream_list_for_each`. + */ +void srtp_stream_list_remove(srtp_stream_list_t list, srtp_stream_t stream); + +/** + * iterate through all stored streams. while iterating, it is allowed to delete + * the current element; any other mutation to the list is undefined behavior. + * returning non-zero from callback aborts the iteration. + */ +void srtp_stream_list_for_each(srtp_stream_list_t list, + int (*callback)(srtp_stream_t, void *), + void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* SRTP_STREAM_LIST_PRIV_H */ diff --git a/third_party/libsrtp/src/srtp/srtp.c b/third_party/libsrtp/src/srtp/srtp.c --- a/third_party/libsrtp/src/srtp/srtp.c +++ b/third_party/libsrtp/src/srtp/srtp.c @@ -44,10 +44,11 @@ // Leave this as the top level import. Ensures the existence of defines #include "config.h" #include "srtp_priv.h" +#include "stream_list_priv.h" #include "crypto_types.h" #include "err.h" #include "alloc.h" /* for srtp_crypto_alloc() */ #ifdef GCM @@ -71,55 +72,78 @@ 0, /* debugging is off by default */ "srtp" /* printable name for module */ }; #define octets_in_rtp_header 12 -#define uint32s_in_rtp_header 3 #define octets_in_rtcp_header 8 -#define uint32s_in_rtcp_header 2 -#define octets_in_rtp_extn_hdr 4 - -static srtp_err_status_t srtp_validate_rtp_header(void *rtp_hdr, - int *pkt_octet_len) +#define octets_in_rtp_xtn_hdr 4 + +static uint32_t srtp_get_rtp_hdr_len(const srtp_hdr_t *hdr) +{ + return octets_in_rtp_header + 4 * hdr->cc; +} + +/* + * Returns the location of the header extention cast too a srtp_hdr_xtnd_t + * struct. Will always return a value and assumes that the caller has already + * verified that a header extension is present by checking the x bit of + * srtp_hdr_t. + */ +static srtp_hdr_xtnd_t *srtp_get_rtp_xtn_hdr(srtp_hdr_t *hdr) { - srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - int rtp_header_len; - - if (*pkt_octet_len < octets_in_rtp_header) + uint32_t rtp_xtn_hdr_start = srtp_get_rtp_hdr_len(hdr); + return (srtp_hdr_xtnd_t *)((uint8_t *)hdr + rtp_xtn_hdr_start); +} + +/* + * Returns the length of the extension header including the extension header + * header so will return a minium of 4. Assumes the srtp_hdr_xtnd_t is a valid + * pointer and that the caller has already verified that a header extension is + * valid by checking the x bit of the RTP header. + */ +static uint32_t srtp_get_rtp_xtn_hdr_len(const srtp_hdr_xtnd_t *xtn_hdr) +{ + return (ntohs(xtn_hdr->length) + 1) * 4; +} + +static srtp_err_status_t srtp_validate_rtp_header(const void *rtp_hdr, + uint32_t pkt_octet_len) +{ + const srtp_hdr_t *hdr = (const srtp_hdr_t *)rtp_hdr; + uint32_t rtp_header_len; + + if (pkt_octet_len < octets_in_rtp_header) return srtp_err_status_bad_param; /* Check RTP header length */ - rtp_header_len = octets_in_rtp_header + 4 * hdr->cc; - if (hdr->x == 1) - rtp_header_len += octets_in_rtp_extn_hdr; - - if (*pkt_octet_len < rtp_header_len) + rtp_header_len = srtp_get_rtp_hdr_len(hdr); + if (pkt_octet_len < rtp_header_len) return srtp_err_status_bad_param; - /* Verifing profile length. */ + /* Verifying profile length. */ if (hdr->x == 1) { - srtp_hdr_xtnd_t *xtn_hdr = - (srtp_hdr_xtnd_t *)((uint32_t *)hdr + uint32s_in_rtp_header + - hdr->cc); - int profile_len = ntohs(xtn_hdr->length); - rtp_header_len += profile_len * 4; - /* profile length counts the number of 32-bit words */ - if (*pkt_octet_len < rtp_header_len) + if (pkt_octet_len < rtp_header_len + octets_in_rtp_xtn_hdr) + return srtp_err_status_bad_param; + + rtp_header_len += srtp_get_rtp_xtn_hdr_len( + (const srtp_hdr_xtnd_t *)((const uint8_t *)hdr + rtp_header_len)); + if (pkt_octet_len < rtp_header_len) return srtp_err_status_bad_param; } + return srtp_err_status_ok; } -const char *srtp_get_version_string() +const char *srtp_get_version_string(void) { /* * Simply return the autotools generated string */ return SRTP_VER_STRING; } -unsigned int srtp_get_version() +unsigned int srtp_get_version(void) { unsigned int major = 0, minor = 0, micro = 0; unsigned int rv = 0; int parse_rv; @@ -146,12 +170,13 @@ rv |= (minor & 0xFF) << 16; rv |= micro & 0xFF; return rv; } -srtp_err_status_t srtp_stream_dealloc(srtp_stream_ctx_t *stream, - const srtp_stream_ctx_t *stream_template) +static srtp_err_status_t srtp_stream_dealloc( + srtp_stream_ctx_t *stream, + const srtp_stream_ctx_t *stream_template) { srtp_err_status_t status; unsigned int i = 0; srtp_session_keys_t *session_keys = NULL; srtp_session_keys_t *template_session_keys = NULL; @@ -171,12 +196,12 @@ } else { template_session_keys = NULL; } /* - * deallocate cipher, if it is not the same as that in template - */ + * deallocate cipher, if it is not the same as that in template + */ if (template_session_keys && session_keys->rtp_cipher == template_session_keys->rtp_cipher) { /* do nothing */ } else if (session_keys->rtp_cipher) { status = srtp_cipher_dealloc(session_keys->rtp_cipher); @@ -276,21 +301,62 @@ srtp_crypto_free(stream); return srtp_err_status_ok; } +/* try to insert stream in list or deallocate it */ +static srtp_err_status_t srtp_insert_or_dealloc_stream(srtp_stream_list_t list, + srtp_stream_t stream, + srtp_stream_t template) +{ + srtp_err_status_t status = srtp_stream_list_insert(list, stream); + /* on failure, ownership wasn't transferred and we need to deallocate */ + if (status) { + srtp_stream_dealloc(stream, template); + } + return status; +} + +struct remove_and_dealloc_streams_data { + srtp_err_status_t status; + srtp_stream_list_t list; + srtp_stream_t template; +}; + +static int remove_and_dealloc_streams_cb(srtp_stream_t stream, void *data) +{ + struct remove_and_dealloc_streams_data *d = + (struct remove_and_dealloc_streams_data *)data; + srtp_stream_list_remove(d->list, stream); + d->status = srtp_stream_dealloc(stream, d->template); + if (d->status) { + return 1; + } + return 0; +} + +static srtp_err_status_t srtp_remove_and_dealloc_streams( + srtp_stream_list_t list, + srtp_stream_t template) +{ + struct remove_and_dealloc_streams_data data = { srtp_err_status_ok, list, + template }; + srtp_stream_list_for_each(list, remove_and_dealloc_streams_cb, &data); + return data.status; +} + static srtp_err_status_t srtp_valid_policy(const srtp_policy_t *p) { if (p != NULL && p->deprecated_ekt != NULL) { return srtp_err_status_bad_param; } return srtp_err_status_ok; } -srtp_err_status_t srtp_stream_alloc(srtp_stream_ctx_t **str_ptr, - const srtp_policy_t *p) +static srtp_err_status_t srtp_stream_alloc(srtp_stream_ctx_t **str_ptr, + const srtp_policy_t *p) { srtp_stream_ctx_t *str; srtp_err_status_t stat; unsigned int i = 0; srtp_session_keys_t *session_keys = NULL; @@ -450,13 +516,14 @@ * * the only unique data in a cloned stream is the replay database and * the SSRC */ -srtp_err_status_t srtp_stream_clone(const srtp_stream_ctx_t *stream_template, - uint32_t ssrc, - srtp_stream_ctx_t **str_ptr) +static srtp_err_status_t srtp_stream_clone( + const srtp_stream_ctx_t *stream_template, + uint32_t ssrc, + srtp_stream_ctx_t **str_ptr) { srtp_err_status_t status; srtp_stream_ctx_t *str; unsigned int i = 0; srtp_session_keys_t *session_keys = NULL; @@ -549,10 +616,11 @@ str->enc_xtn_hdr = stream_template->enc_xtn_hdr; str->enc_xtn_hdr_count = stream_template->enc_xtn_hdr_count; /* defensive coding */ str->next = NULL; + str->prev = NULL; return srtp_err_status_ok; } /* * key derivation functions, internal to libSRTP @@ -792,11 +860,12 @@ default: return 0; } } -unsigned int srtp_validate_policy_master_keys(const srtp_policy_t *policy) +static unsigned int srtp_validate_policy_master_keys( + const srtp_policy_t *policy) { unsigned long i = 0; if (policy->key == NULL) { if (policy->num_master_keys <= 0) @@ -896,11 +965,11 @@ unsigned char *key = master_key->key; /* If RTP or RTCP have a key length > AES-128, assume matching kdf. */ /* TODO: kdf algorithm, master key length, and master salt length should * be part of srtp_policy_t. - */ + */ session_keys = &srtp->session_keys[current_mki_index]; /* initialize key limit to maximum value */ #ifdef NO_64BIT_MATH { @@ -935,10 +1004,20 @@ rtcp_keylen = srtp_cipher_get_key_length(session_keys->rtcp_cipher); rtp_base_key_len = base_key_length(session_keys->rtp_cipher->type, rtp_keylen); rtp_salt_len = rtp_keylen - rtp_base_key_len; + /* + * We assume that the `key` buffer provided by the caller has a length + * equal to the greater of `rtp_keylen` and `rtcp_keylen`. Since we are + * about to read `input_keylen` bytes from it, we need to check that we will + * not overrun. + */ + if ((rtp_keylen < input_keylen) && (rtcp_keylen < input_keylen)) { + return srtp_err_status_bad_param; + } + if (rtp_keylen > kdf_keylen) { kdf_keylen = 46; /* AES-CTR mode is always used for KDF */ } if (rtcp_keylen > kdf_keylen) { @@ -1242,12 +1321,12 @@ return srtp_err_status_init_fail; return srtp_err_status_ok; } -srtp_err_status_t srtp_stream_init(srtp_stream_ctx_t *srtp, - const srtp_policy_t *p) +static srtp_err_status_t srtp_stream_init(srtp_stream_ctx_t *srtp, + const srtp_policy_t *p) { srtp_err_status_t err; err = srtp_valid_policy(p); if (err != srtp_err_status_ok) { @@ -1321,12 +1400,12 @@ * reports the events that are reported by the callbacks */ void srtp_event_reporter(srtp_event_data_t *data) { - srtp_err_report(srtp_err_level_warning, "srtp: in stream 0x%x: ", - data->ssrc); + srtp_err_report(srtp_err_level_warning, + "srtp: in stream 0x%x: ", data->ssrc); switch (data->event) { case event_ssrc_collision: srtp_err_report(srtp_err_level_warning, "\tSSRC collision\n"); break; @@ -1406,11 +1485,11 @@ srtp_session_keys_t *session_keys) { srtp_err_status_t status; uint8_t keystream[257]; /* Maximum 2 bytes header + 255 bytes data. */ int keystream_pos; - uint8_t *xtn_hdr_data = ((uint8_t *)xtn_hdr) + octets_in_rtp_extn_hdr; + uint8_t *xtn_hdr_data = ((uint8_t *)xtn_hdr) + octets_in_rtp_xtn_hdr; uint8_t *xtn_hdr_end = xtn_hdr_data + (ntohs(xtn_hdr->length) * sizeof(uint32_t)); if (ntohs(xtn_hdr->profile_specific) == 0xbede) { /* RFC 5285, section 4.2. One-Byte Header */ @@ -1519,11 +1598,11 @@ */ static void srtp_calc_aead_iv(srtp_session_keys_t *session_keys, v128_t *iv, srtp_xtd_seq_num_t *seq, - srtp_hdr_t *hdr) + const srtp_hdr_t *hdr) { v128_t in; v128_t salt; #ifdef NO_64BIT_MATH @@ -1557,28 +1636,20 @@ * Finally, apply tyhe SALT to the input */ v128_xor(iv, &in, &salt); } -srtp_session_keys_t *srtp_get_session_keys(srtp_stream_ctx_t *stream, - uint8_t *hdr, - const unsigned int *pkt_octet_len, - unsigned int *mki_size) +static srtp_session_keys_t *srtp_get_session_keys(srtp_stream_ctx_t *stream, + const uint8_t *hdr, + unsigned int pkt_octet_len, + unsigned int *mki_size, + unsigned int tag_len) { - unsigned int base_mki_start_location = *pkt_octet_len; + unsigned int base_mki_start_location = pkt_octet_len; unsigned int mki_start_location = 0; - unsigned int tag_len = 0; unsigned int i = 0; - // Determine the authentication tag size - if (stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_128 || - stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_256) { - tag_len = 0; - } else { - tag_len = srtp_auth_get_tag_length(stream->session_keys[0].rtp_auth); - } - if (tag_len > base_mki_start_location) { *mki_size = 0; return NULL; } @@ -1599,10 +1670,48 @@ *mki_size = 0; return NULL; } +static srtp_session_keys_t *srtp_get_session_keys_rtp( + srtp_stream_ctx_t *stream, + const uint8_t *hdr, + unsigned int pkt_octet_len, + unsigned int *mki_size) +{ + unsigned int tag_len = 0; + + // Determine the authentication tag size + if (stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_128 || + stream->session_keys[0].rtp_cipher->algorithm == SRTP_AES_GCM_256) { + tag_len = 0; + } else { + tag_len = srtp_auth_get_tag_length(stream->session_keys[0].rtp_auth); + } + + return srtp_get_session_keys(stream, hdr, pkt_octet_len, mki_size, tag_len); +} + +static srtp_session_keys_t *srtp_get_session_keys_rtcp( + srtp_stream_ctx_t *stream, + const uint8_t *hdr, + unsigned int pkt_octet_len, + unsigned int *mki_size) +{ + unsigned int tag_len = 0; + + // Determine the authentication tag size + if (stream->session_keys[0].rtcp_cipher->algorithm == SRTP_AES_GCM_128 || + stream->session_keys[0].rtcp_cipher->algorithm == SRTP_AES_GCM_256) { + tag_len = 0; + } else { + tag_len = srtp_auth_get_tag_length(stream->session_keys[0].rtcp_auth); + } + + return srtp_get_session_keys(stream, hdr, pkt_octet_len, mki_size, tag_len); +} + static srtp_err_status_t srtp_estimate_index(srtp_rdbx_t *rdbx, uint32_t roc, srtp_xtd_seq_num_t *est, srtp_sequence_number_t seq, int *delta) @@ -1673,11 +1782,11 @@ } return srtp_err_status_ok; } -static srtp_err_status_t srtp_get_est_pkt_index(srtp_hdr_t *hdr, +static srtp_err_status_t srtp_get_est_pkt_index(const srtp_hdr_t *hdr, srtp_stream_ctx_t *stream, srtp_xtd_seq_num_t *est, int *delta) { srtp_err_status_t result = srtp_err_status_ok; @@ -1711,11 +1820,11 @@ unsigned int *pkt_octet_len, srtp_session_keys_t *session_keys, unsigned int use_mki) { srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ int enc_octet_len = 0; /* number of octets in encrypted portion */ srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ int delta; /* delta of local pkt idx and that in hdr */ srtp_err_status_t status; uint32_t tag_len; @@ -1751,34 +1860,43 @@ * find starting point for encryption and length of data to be * encrypted - the encrypted portion starts after the rtp header * extension, if present; otherwise, it starts after the last csrc, * if any are present */ - enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; + enc_start = (uint8_t *)hdr + srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; - enc_start += (ntohs(xtn_hdr->length) + 1); + xtn_hdr = srtp_get_rtp_xtn_hdr(hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(xtn_hdr); } /* note: the passed size is without the auth tag */ - if (!((uint8_t *)enc_start <= (uint8_t *)hdr + *pkt_octet_len)) + if (!(enc_start <= (uint8_t *)hdr + *pkt_octet_len)) return srtp_err_status_parse_err; - enc_octet_len = - (int)(*pkt_octet_len - ((uint8_t *)enc_start - (uint8_t *)hdr)); + enc_octet_len = (int)(*pkt_octet_len - (enc_start - (uint8_t *)hdr)); if (enc_octet_len < 0) return srtp_err_status_parse_err; /* * estimate the packet index using the start of the replay window * and the sequence number from the header */ - delta = srtp_rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq)); - status = srtp_rdbx_check(&stream->rtp_rdbx, delta); - if (status) { - if (status != srtp_err_status_replay_fail || !stream->allow_repeat_tx) { - return status; /* we've been asked to reuse an index */ + status = srtp_get_est_pkt_index(hdr, stream, &est, &delta); + + if (status && (status != srtp_err_status_pkt_idx_adv)) + return status; + + if (status == srtp_err_status_pkt_idx_adv) { + srtp_rdbx_set_roc_seq(&stream->rtp_rdbx, (uint32_t)(est >> 16), + (uint16_t)(est & 0xFFFF)); + stream->pending_roc = 0; + srtp_rdbx_add_index(&stream->rtp_rdbx, 0); + } else { + status = srtp_rdbx_check(&stream->rtp_rdbx, delta); + if (status) { + if (status != srtp_err_status_replay_fail || + !stream->allow_repeat_tx) + return status; /* we've been asked to reuse an index */ } - } else { srtp_rdbx_add_index(&stream->rtp_rdbx, delta); } #ifdef NO_64BIT_MATH debug_print2(mod_srtp, "estimated packet index: %08x%08x", high32(est), @@ -1823,30 +1941,29 @@ } /* * Set the AAD over the RTP header */ - aad_len = (uint8_t *)enc_start - (uint8_t *)hdr; + aad_len = (uint32_t)(enc_start - (uint8_t *)hdr); status = srtp_cipher_set_aad(session_keys->rtp_cipher, (uint8_t *)hdr, aad_len); if (status) { return (srtp_err_status_cipher_fail); } /* Encrypt the payload */ - status = srtp_cipher_encrypt(session_keys->rtp_cipher, (uint8_t *)enc_start, + status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, (unsigned int *)&enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } /* * If we're doing GCM, we need to get the tag * and append that to the output */ - status = - srtp_cipher_get_tag(session_keys->rtp_cipher, - (uint8_t *)enc_start + enc_octet_len, &tag_len); + status = srtp_cipher_get_tag(session_keys->rtp_cipher, + enc_start + enc_octet_len, &tag_len); if (status) { return (srtp_err_status_cipher_fail); } mki_location = (uint8_t *)hdr + *pkt_octet_len + tag_len; @@ -1873,14 +1990,15 @@ int delta, srtp_xtd_seq_num_t est, void *srtp_hdr, unsigned int *pkt_octet_len, srtp_session_keys_t *session_keys, - unsigned int mki_size) + unsigned int mki_size, + int advance_packet_index) { srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */ v128_t iv; srtp_err_status_t status; int tag_len; unsigned int aad_len; @@ -1924,23 +2042,22 @@ * 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 = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; + enc_start = (uint8_t *)hdr + srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; - enc_start += (ntohs(xtn_hdr->length) + 1); + xtn_hdr = srtp_get_rtp_xtn_hdr(hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(xtn_hdr); } - if (!((uint8_t *)enc_start <= - (uint8_t *)hdr + (*pkt_octet_len - tag_len - mki_size))) + if (!(enc_start <= (uint8_t *)hdr + (*pkt_octet_len - tag_len - mki_size))) return srtp_err_status_parse_err; /* * We pass the tag down to the cipher when doing GCM mode */ enc_octet_len = (unsigned int)(*pkt_octet_len - mki_size - - ((uint8_t *)enc_start - (uint8_t *)hdr)); + (enc_start - (uint8_t *)hdr)); /* * Sanity check the encrypted payload length against * the tag size. It must always be at least as large * as the tag length. @@ -1968,11 +2085,11 @@ } /* * Set the AAD for AES-GCM, which is the RTP header */ - aad_len = (uint8_t *)enc_start - (uint8_t *)hdr; + aad_len = (uint32_t)(enc_start - (uint8_t *)hdr); status = srtp_cipher_set_aad(session_keys->rtp_cipher, (uint8_t *)hdr, aad_len); if (status) { return (srtp_err_status_cipher_fail); } @@ -2032,23 +2149,34 @@ srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) { return status; } - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set stream (the pointer used in this function) */ stream = new_stream; } /* * the message authentication function passed, so add the packet * index into the replay database */ - srtp_rdbx_add_index(&stream->rtp_rdbx, delta); + if (advance_packet_index) { + uint32_t roc_to_set = (uint32_t)(est >> 16); + uint16_t seq_to_set = (uint16_t)(est & 0xFFFF); + srtp_rdbx_set_roc_seq(&stream->rtp_rdbx, roc_to_set, seq_to_set); + stream->pending_roc = 0; + srtp_rdbx_add_index(&stream->rtp_rdbx, 0); + } else { + 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 */ @@ -2069,12 +2197,12 @@ int *pkt_octet_len, unsigned int use_mki, unsigned int mki_index) { srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *auth_start; /* pointer to start of auth. portion */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *auth_start; /* pointer to start of auth. portion */ int enc_octet_len = 0; /* number of octets in encrypted portion */ srtp_xtd_seq_num_t est; /* estimated xtd_seq_num_t of *hdr */ int delta; /* delta of local pkt idx and that in hdr */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ srtp_err_status_t status; @@ -2083,18 +2211,15 @@ uint32_t prefix_len; srtp_hdr_xtnd_t *xtn_hdr = NULL; unsigned int mki_size = 0; srtp_session_keys_t *session_keys = NULL; uint8_t *mki_location = NULL; - int advance_packet_index = 0; debug_print0(mod_srtp, "function srtp_protect"); - /* we assume the hdr is 32-bit aligned to start */ - /* Verify RTP header */ - status = srtp_validate_rtp_header(rtp_hdr, pkt_octet_len); + status = srtp_validate_rtp_header(rtp_hdr, *pkt_octet_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) @@ -2116,13 +2241,16 @@ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) return status; - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set direction to outbound */ new_stream->direction = dir_srtp_sender; /* set stream (the pointer used in this function) */ @@ -2193,20 +2321,19 @@ * if any are present * * if we're not providing confidentiality, set enc_start to NULL */ if (stream->rtp_services & sec_serv_conf) { - enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; + enc_start = (uint8_t *)hdr + srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; - enc_start += (ntohs(xtn_hdr->length) + 1); + xtn_hdr = srtp_get_rtp_xtn_hdr(hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(xtn_hdr); } /* note: the passed size is without the auth tag */ - if (!((uint8_t *)enc_start <= (uint8_t *)hdr + *pkt_octet_len)) + if (!(enc_start <= (uint8_t *)hdr + *pkt_octet_len)) return srtp_err_status_parse_err; - enc_octet_len = - (int)(*pkt_octet_len - ((uint8_t *)enc_start - (uint8_t *)hdr)); + enc_octet_len = (int)(*pkt_octet_len - (enc_start - (uint8_t *)hdr)); if (enc_octet_len < 0) return srtp_err_status_parse_err; } else { enc_start = NULL; } @@ -2218,11 +2345,11 @@ * if we're providing authentication, set the auth_start and auth_tag * pointers to the proper locations; otherwise, set auth_start to NULL * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { - auth_start = (uint32_t *)hdr; + auth_start = (uint8_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len + mki_size; } else { auth_start = NULL; auth_tag = NULL; } @@ -2234,14 +2361,11 @@ status = srtp_get_est_pkt_index(hdr, stream, &est, &delta); if (status && (status != srtp_err_status_pkt_idx_adv)) return status; - if (status == srtp_err_status_pkt_idx_adv) - advance_packet_index = 1; - - if (advance_packet_index) { + if (status == srtp_err_status_pkt_idx_adv) { srtp_rdbx_set_roc_seq(&stream->rtp_rdbx, (uint32_t)(est >> 16), (uint16_t)(est & 0xFFFF)); stream->pending_roc = 0; srtp_rdbx_add_index(&stream->rtp_rdbx, 0); } else { @@ -2338,13 +2462,12 @@ } } /* if we're encrypting, exor keystream into the message */ if (enc_start) { - status = - srtp_cipher_encrypt(session_keys->rtp_cipher, (uint8_t *)enc_start, - (unsigned int *)&enc_octet_len); + status = srtp_cipher_encrypt(session_keys->rtp_cipher, enc_start, + (unsigned int *)&enc_octet_len); if (status) return srtp_err_status_cipher_fail; } /* @@ -2356,11 +2479,11 @@ status = srtp_auth_start(session_keys->rtp_auth); if (status) return status; /* run auth func over packet */ - status = srtp_auth_update(session_keys->rtp_auth, (uint8_t *)auth_start, + status = srtp_auth_update(session_keys->rtp_auth, auth_start, *pkt_octet_len); if (status) return status; /* run auth func over ROC, put result into auth_tag */ @@ -2397,12 +2520,12 @@ void *srtp_hdr, int *pkt_octet_len, unsigned int use_mki) { srtp_hdr_t *hdr = (srtp_hdr_t *)srtp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *auth_start; /* pointer to start of auth. portion */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *auth_start; /* pointer to start of auth. portion */ unsigned int 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 */ int delta; /* delta of local pkt idx and that in hdr */ v128_t iv; @@ -2417,14 +2540,12 @@ uint32_t roc_to_set = 0; uint16_t seq_to_set = 0; debug_print0(mod_srtp, "function srtp_unprotect"); - /* we assume the hdr is 32-bit aligned to start */ - /* Verify RTP header */ - status = srtp_validate_rtp_header(srtp_hdr, pkt_octet_len); + status = srtp_validate_rtp_header(srtp_hdr, *pkt_octet_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) @@ -2489,13 +2610,13 @@ debug_print(mod_srtp, "estimated u_packet index: %016" PRIx64, est); #endif /* Determine if MKI is being used and what session keys should be used */ if (use_mki) { - session_keys = srtp_get_session_keys( - stream, (uint8_t *)hdr, (const unsigned int *)pkt_octet_len, - &mki_size); + session_keys = + srtp_get_session_keys_rtp(stream, (const uint8_t *)hdr, + (unsigned int)*pkt_octet_len, &mki_size); if (session_keys == NULL) return srtp_err_status_bad_mki; } else { session_keys = &stream->session_keys[0]; @@ -2507,11 +2628,11 @@ */ 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, (unsigned int *)pkt_octet_len, session_keys, - mki_size); + mki_size, advance_packet_index); } /* get tag length from stream */ tag_len = srtp_auth_get_tag_length(session_keys->rtp_auth); @@ -2571,31 +2692,31 @@ * if any are present * * if we're not providing confidentiality, set enc_start to NULL */ if (stream->rtp_services & sec_serv_conf) { - enc_start = (uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc; + enc_start = (uint8_t *)hdr + srtp_get_rtp_hdr_len(hdr); if (hdr->x == 1) { - xtn_hdr = (srtp_hdr_xtnd_t *)enc_start; - enc_start += (ntohs(xtn_hdr->length) + 1); + xtn_hdr = srtp_get_rtp_xtn_hdr(hdr); + enc_start += srtp_get_rtp_xtn_hdr_len(xtn_hdr); } - if (!((uint8_t *)enc_start <= + if (!(enc_start <= (uint8_t *)hdr + (*pkt_octet_len - tag_len - mki_size))) return srtp_err_status_parse_err; enc_octet_len = (uint32_t)(*pkt_octet_len - tag_len - mki_size - - ((uint8_t *)enc_start - (uint8_t *)hdr)); + (enc_start - (uint8_t *)hdr)); } else { enc_start = NULL; } /* * if we're providing authentication, set the auth_start and auth_tag * pointers to the proper locations; otherwise, set auth_start to NULL * to indicate that no authentication is needed */ if (stream->rtp_services & sec_serv_auth) { - auth_start = (uint32_t *)hdr; + auth_start = (uint8_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len; } else { auth_start = NULL; auth_tag = NULL; } @@ -2626,11 +2747,11 @@ status = srtp_auth_start(session_keys->rtp_auth); if (status) return status; /* now compute auth function over packet */ - status = srtp_auth_update(session_keys->rtp_auth, (uint8_t *)auth_start, + status = srtp_auth_update(session_keys->rtp_auth, auth_start, *pkt_octet_len - tag_len - mki_size); if (status) return status; /* run auth func over ROC, then write tmp tag */ @@ -2674,12 +2795,12 @@ } } /* if we're decrypting, add keystream into ciphertext */ if (enc_start) { - status = srtp_cipher_decrypt(session_keys->rtp_cipher, - (uint8_t *)enc_start, &enc_octet_len); + status = srtp_cipher_decrypt(session_keys->rtp_cipher, enc_start, + &enc_octet_len); if (status) return srtp_err_status_cipher_fail; } /* @@ -2715,16 +2836,20 @@ * stream, and some implementations will want to not return * failure here */ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); - if (status) + if (status) { return status; - - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + } + + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set stream (the pointer used in this function) */ stream = new_stream; } @@ -2747,11 +2872,11 @@ *pkt_octet_len -= mki_size; return srtp_err_status_ok; } -srtp_err_status_t srtp_init() +srtp_err_status_t srtp_init(void) { srtp_err_status_t status; /* initialize crypto kernel */ status = srtp_crypto_kernel_init(); @@ -2764,11 +2889,11 @@ return status; return srtp_err_status_ok; } -srtp_err_status_t srtp_shutdown() +srtp_err_status_t srtp_shutdown(void) { srtp_err_status_t status; /* shut down crypto kernel */ status = srtp_crypto_kernel_shutdown(); @@ -2778,59 +2903,44 @@ /* shutting down crypto kernel frees the srtp debug module as well */ return srtp_err_status_ok; } -/* - * srtp_get_stream(ssrc) returns a pointer to the stream corresponding - * to ssrc, or NULL if no stream exists for that ssrc - * - * this is an internal function - */ - srtp_stream_ctx_t *srtp_get_stream(srtp_t srtp, uint32_t ssrc) { - srtp_stream_ctx_t *stream; - - /* walk down list until ssrc is found */ - stream = srtp->stream_list; - while (stream != NULL) { - if (stream->ssrc == ssrc) - return stream; - stream = stream->next; - } - - /* we haven't found our ssrc, so return a null */ - return NULL; + return srtp_stream_list_get(srtp->stream_list, ssrc); } srtp_err_status_t srtp_dealloc(srtp_t session) { - srtp_stream_ctx_t *stream; srtp_err_status_t status; /* * we take a conservative deallocation strategy - if we encounter an * error deallocating a stream, then we stop trying to deallocate * memory and just return an error */ - /* walk list of streams, deallocating as we go */ - stream = session->stream_list; - while (stream != NULL) { - srtp_stream_t next = stream->next; - status = srtp_stream_dealloc(stream, session->stream_template); - if (status) - return status; - stream = next; + /* deallocate streams */ + status = srtp_remove_and_dealloc_streams(session->stream_list, + session->stream_template); + if (status) { + return status; } /* deallocate stream template, if there is one */ if (session->stream_template != NULL) { status = srtp_stream_dealloc(session->stream_template, NULL); - if (status) + if (status) { return status; + } + } + + /* deallocate stream list */ + status = srtp_stream_list_dealloc(session->stream_list); + if (status) { + return status; } /* deallocate session context */ srtp_crypto_free(session); @@ -2889,12 +2999,15 @@ } session->stream_template = tmp; session->stream_template->direction = dir_srtp_receiver; break; case (ssrc_specific): - tmp->next = session->stream_list; - session->stream_list = tmp; + status = srtp_insert_or_dealloc_stream(session->stream_list, tmp, + session->stream_template); + if (status) { + return status; + } break; case (ssrc_undefined): default: srtp_stream_dealloc(tmp, NULL); return srtp_err_status_bad_param; @@ -2922,17 +3035,27 @@ ctx = (srtp_ctx_t *)srtp_crypto_alloc(sizeof(srtp_ctx_t)); if (ctx == NULL) return srtp_err_status_alloc_fail; *session = ctx; + ctx->stream_template = NULL; + ctx->stream_list = NULL; + ctx->user_data = NULL; + + /* allocate stream list */ + stat = srtp_stream_list_alloc(&ctx->stream_list); + if (stat) { + /* clean up everything */ + srtp_dealloc(*session); + *session = NULL; + return stat; + } + /* * loop over elements in the policy list, allocating and * initializing a stream for each element */ - ctx->stream_template = NULL; - ctx->stream_list = NULL; - ctx->user_data = NULL; while (policy != NULL) { stat = srtp_add_stream(ctx, policy); if (stat) { /* clean up everything */ srtp_dealloc(*session); @@ -2947,32 +3070,24 @@ return srtp_err_status_ok; } srtp_err_status_t srtp_remove_stream(srtp_t session, uint32_t ssrc) { - srtp_stream_ctx_t *stream, *last_stream; + srtp_stream_ctx_t *stream; srtp_err_status_t status; /* sanity check arguments */ if (session == NULL) return srtp_err_status_bad_param; - /* find stream in list; complain if not found */ - last_stream = stream = session->stream_list; - while ((stream != NULL) && (ssrc != stream->ssrc)) { - last_stream = stream; - stream = stream->next; - } - if (stream == NULL) + /* find and remove stream from the list */ + stream = srtp_stream_list_get(session->stream_list, ssrc); + if (stream == NULL) { return srtp_err_status_no_ctx; - - /* remove stream from the list */ - if (last_stream == stream) - /* stream was first in list */ - session->stream_list = stream->next; - else - last_stream->next = stream->next; + } + + srtp_stream_list_remove(session->stream_list, stream); /* deallocate the stream */ status = srtp_stream_dealloc(stream, session->stream_template); if (status) return status; @@ -3005,16 +3120,74 @@ policy = policy->next; } return srtp_err_status_ok; } +struct update_template_stream_data { + srtp_err_status_t status; + srtp_t session; + srtp_stream_t new_stream_template; + srtp_stream_list_t new_stream_list; +}; + +static int update_template_stream_cb(srtp_stream_t stream, void *raw_data) +{ + struct update_template_stream_data *data = + (struct update_template_stream_data *)raw_data; + srtp_t session = data->session; + uint32_t ssrc = stream->ssrc; + srtp_xtd_seq_num_t old_index; + srtp_rdb_t old_rtcp_rdb; + + /* old / non-template streams are copied unchanged */ + if (stream->session_keys[0].rtp_auth != + session->stream_template->session_keys[0].rtp_auth) { + srtp_stream_list_remove(session->stream_list, stream); + data->status = srtp_insert_or_dealloc_stream( + data->new_stream_list, stream, session->stream_template); + if (data->status) { + return 1; + } + return 0; + } + + /* save old extendard seq */ + old_index = stream->rtp_rdbx.index; + old_rtcp_rdb = stream->rtcp_rdb; + + /* remove stream */ + data->status = srtp_remove_stream(session, ssrc); + if (data->status) { + return 1; + } + + /* allocate and initialize a new stream */ + data->status = srtp_stream_clone(data->new_stream_template, ssrc, &stream); + if (data->status) { + return 1; + } + + /* add new stream to the head of the new_stream_list */ + data->status = srtp_insert_or_dealloc_stream(data->new_stream_list, stream, + data->new_stream_template); + if (data->status) { + return 1; + } + + /* restore old extended seq */ + stream->rtp_rdbx.index = old_index; + stream->rtcp_rdb = old_rtcp_rdb; + + return 0; +} + static srtp_err_status_t update_template_streams(srtp_t session, const srtp_policy_t *policy) { srtp_err_status_t status; srtp_stream_t new_stream_template; - srtp_stream_t new_stream_list = NULL; + srtp_stream_list_t new_stream_list; status = srtp_valid_policy(policy); if (status != srtp_err_status_ok) { return status; } @@ -3034,81 +3207,41 @@ if (status) { srtp_crypto_free(new_stream_template); return status; } - /* for all old templated streams */ - for (;;) { - srtp_stream_t stream; - uint32_t ssrc; - srtp_xtd_seq_num_t old_index; - srtp_rdb_t old_rtcp_rdb; - - stream = session->stream_list; - while ((stream != NULL) && - (stream->session_keys[0].rtp_auth != - session->stream_template->session_keys[0].rtp_auth)) { - stream = stream->next; - } - if (stream == NULL) { - /* no more templated streams */ - break; - } - - /* save old extendard seq */ - ssrc = stream->ssrc; - old_index = stream->rtp_rdbx.index; - old_rtcp_rdb = stream->rtcp_rdb; - - /* remove stream */ - status = srtp_remove_stream(session, ssrc); - if (status) { - /* free new allocations */ - while (new_stream_list != NULL) { - srtp_stream_t next = new_stream_list->next; - srtp_stream_dealloc(new_stream_list, new_stream_template); - new_stream_list = next; - } - srtp_stream_dealloc(new_stream_template, NULL); - return status; - } - - /* allocate and initialize a new stream */ - status = srtp_stream_clone(new_stream_template, ssrc, &stream); - if (status) { - /* free new allocations */ - while (new_stream_list != NULL) { - srtp_stream_t next = new_stream_list->next; - srtp_stream_dealloc(new_stream_list, new_stream_template); - new_stream_list = next; - } - srtp_stream_dealloc(new_stream_template, NULL); - return status; - } - - /* add new stream to the head of the new_stream_list */ - stream->next = new_stream_list; - new_stream_list = stream; - - /* restore old extended seq */ - stream->rtp_rdbx.index = old_index; - stream->rtcp_rdb = old_rtcp_rdb; + /* allocate new stream list */ + status = srtp_stream_list_alloc(&new_stream_list); + if (status) { + srtp_crypto_free(new_stream_template); + return status; } - /* dealloc old template */ + + /* process streams */ + struct update_template_stream_data data = { srtp_err_status_ok, session, + new_stream_template, + new_stream_list }; + srtp_stream_list_for_each(session->stream_list, update_template_stream_cb, + &data); + if (data.status) { + /* free new allocations */ + srtp_remove_and_dealloc_streams(new_stream_list, new_stream_template); + srtp_stream_list_dealloc(new_stream_list); + srtp_stream_dealloc(new_stream_template, NULL); + return data.status; + } + + /* dealloc old list / template */ + srtp_remove_and_dealloc_streams(session->stream_list, + session->stream_template); + srtp_stream_list_dealloc(session->stream_list); srtp_stream_dealloc(session->stream_template, NULL); - /* set new template */ + + /* set new list / template */ session->stream_template = new_stream_template; - /* add new list */ - if (new_stream_list) { - srtp_stream_t tail = new_stream_list; - while (tail->next) { - tail = tail->next; - } - tail->next = session->stream_list; - session->stream_list = new_stream_list; - } - return status; + session->stream_list = new_stream_list; + return srtp_err_status_ok; } static srtp_err_status_t update_stream(srtp_t session, const srtp_policy_t *policy) { @@ -3260,11 +3393,12 @@ /* * corresponds to RFC 4568 */ p->cipher_type = SRTP_NULL_CIPHER; - p->cipher_key_len = 16; + p->cipher_key_len = + SRTP_AES_ICM_128_KEY_LEN_WSALT; /* 128 bit key, 112 bit salt */ p->auth_type = SRTP_HMAC_SHA1; p->auth_key_len = 20; p->auth_tag_len = 10; p->sec_serv = sec_serv_auth; } @@ -3274,11 +3408,12 @@ /* * Should only be used for testing */ p->cipher_type = SRTP_NULL_CIPHER; - p->cipher_key_len = 16; + p->cipher_key_len = + SRTP_AES_ICM_128_KEY_LEN_WSALT; /* 128 bit key, 112 bit salt */ p->auth_type = SRTP_NULL_AUTH; p->auth_key_len = 0; p->auth_tag_len = 0; p->sec_serv = sec_serv_none; } @@ -3481,11 +3616,11 @@ */ static srtp_err_status_t srtp_calc_aead_iv_srtcp( srtp_session_keys_t *session_keys, v128_t *iv, uint32_t seq_num, - srtcp_hdr_t *hdr) + const srtcp_hdr_t *hdr) { v128_t in; v128_t salt; memset(&in, 0, sizeof(v128_t)); @@ -3523,20 +3658,19 @@ /* * This code handles AEAD ciphers for outgoing RTCP. We currently support * AES-GCM mode with 128 or 256 bit keys. */ static srtp_err_status_t srtp_protect_rtcp_aead( - srtp_t ctx, srtp_stream_ctx_t *stream, void *rtcp_hdr, unsigned int *pkt_octet_len, srtp_session_keys_t *session_keys, unsigned int use_mki) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *trailer_p; /* pointer to start of trailer */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *trailer_p; /* pointer to start of trailer */ uint32_t trailer; /* trailer value */ unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ srtp_err_status_t status; uint32_t tag_len; @@ -3550,17 +3684,17 @@ /* * set encryption start and encryption length - if we're not * providing confidentiality, set enc_start to NULL */ - enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header; + enc_start = (uint8_t *)hdr + octets_in_rtcp_header; enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; /* NOTE: hdr->length is not usable - it refers to only the first * RTCP report in the compound packet! */ - trailer_p = (uint32_t *)((char *)enc_start + enc_octet_len + tag_len); + trailer_p = 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; @@ -3643,20 +3777,20 @@ 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, - (uint8_t *)enc_start, &enc_octet_len); + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, + &enc_octet_len); if (status) { return srtp_err_status_cipher_fail; } /* * Get the tag and append that to the output */ - status = srtp_cipher_get_tag(session_keys->rtcp_cipher, - (uint8_t *)auth_tag, &tag_len); + status = + srtp_cipher_get_tag(session_keys->rtcp_cipher, auth_tag, &tag_len); if (status) { return (srtp_err_status_cipher_fail); } enc_octet_len += tag_len; } else { @@ -3670,12 +3804,12 @@ return srtp_err_status_cipher_fail; } /* * Get the tag and append that to the output */ - status = srtp_cipher_get_tag(session_keys->rtcp_cipher, - (uint8_t *)auth_tag, &tag_len); + status = + srtp_cipher_get_tag(session_keys->rtcp_cipher, auth_tag, &tag_len); if (status) { return (srtp_err_status_cipher_fail); } enc_octet_len += tag_len; } @@ -3702,12 +3836,12 @@ unsigned int *pkt_octet_len, srtp_session_keys_t *session_keys, unsigned int use_mki) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *trailer_p; /* pointer to start of trailer */ + uint8_t *enc_start; /* pointer to start of encrypted portion */ + uint8_t *trailer_p; /* pointer to start of trailer */ uint32_t trailer; /* trailer value */ unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ srtp_err_status_t status; int tag_len; @@ -3730,12 +3864,12 @@ /* 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 = (uint32_t *)((char *)hdr + *pkt_octet_len - - sizeof(srtcp_trailer_t) - mki_size); + trailer_p = + (uint8_t *)hdr + *pkt_octet_len - sizeof(srtcp_trailer_t) - mki_size; memcpy(&trailer, trailer_p, sizeof(trailer)); /* * We pass the tag down to the cipher when doing GCM mode */ @@ -3743,11 +3877,11 @@ sizeof(srtcp_trailer_t) + mki_size); auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len - mki_size - sizeof(srtcp_trailer_t); if (*((unsigned char *)trailer_p) & SRTCP_E_BYTE_BIT) { - enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header; + enc_start = (uint8_t *)hdr + octets_in_rtcp_header; } else { enc_octet_len = 0; enc_start = NULL; /* this indicates that there's no encryption */ } @@ -3781,12 +3915,13 @@ if (enc_start) { /* * 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, (uint8_t *)hdr, - octets_in_rtcp_header); + status = + srtp_cipher_set_aad(session_keys->rtcp_cipher, (const uint8_t *)hdr, + octets_in_rtcp_header); if (status) { return (srtp_err_status_cipher_fail); } } else { /* @@ -3812,22 +3947,22 @@ 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, - (uint8_t *)enc_start, &enc_octet_len); + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, + &enc_octet_len); if (status) { return status; } } else { /* * Still need to run the cipher to check the tag */ tmp_len = tag_len; - status = srtp_cipher_decrypt(session_keys->rtcp_cipher, - (uint8_t *)auth_tag, &tmp_len); + status = + srtp_cipher_decrypt(session_keys->rtcp_cipher, auth_tag, &tmp_len); if (status) { return status; } } @@ -3871,13 +4006,16 @@ srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) { return status; } - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set stream (the pointer used in this function) */ stream = new_stream; } @@ -3899,13 +4037,13 @@ int *pkt_octet_len, unsigned int use_mki, unsigned int mki_index) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)rtcp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *auth_start; /* pointer to start of auth. portion */ - uint32_t *trailer_p; /* pointer to start of trailer */ + 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 */ unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ srtp_err_status_t status; int tag_len; @@ -3913,12 +4051,10 @@ uint32_t prefix_len; uint32_t seq_num; unsigned int mki_size = 0; srtp_session_keys_t *session_keys = NULL; - /* we assume the hdr is 32-bit aligned to start */ - /* check the packet length - it must at least contain a full header */ if (*pkt_octet_len < octets_in_rtcp_header) return srtp_err_status_bad_param; /* @@ -3937,13 +4073,16 @@ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) return status; - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set stream (the pointer used in this function) */ stream = new_stream; } else { /* no template stream, so we return an error */ @@ -3975,11 +4114,11 @@ * Check if this is an AEAD stream (GCM mode). If so, then dispatch * the request to our AEAD handler. */ if (session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_128 || session_keys->rtp_cipher->algorithm == SRTP_AES_GCM_256) { - return srtp_protect_rtcp_aead(ctx, stream, rtcp_hdr, + return srtp_protect_rtcp_aead(stream, rtcp_hdr, (unsigned int *)pkt_octet_len, session_keys, use_mki); } /* get tag length from stream context */ @@ -3987,19 +4126,19 @@ /* * set encryption start and encryption length - if we're not * providing confidentiality, set enc_start to NULL */ - enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header; + enc_start = (uint8_t *)hdr + octets_in_rtcp_header; enc_octet_len = *pkt_octet_len - octets_in_rtcp_header; /* 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 = (uint32_t *)((char *)enc_start + enc_octet_len); + trailer_p = enc_start + enc_octet_len; if (stream->rtcp_services & sec_serv_conf) { trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */ } else { enc_start = NULL; @@ -4015,11 +4154,11 @@ /* * set the auth_start and auth_tag pointers to the proper locations * (note that srtpc *always* provides authentication, unlike srtp) */ /* Note: This would need to change for optional mikey data */ - auth_start = (uint32_t *)hdr; + auth_start = (uint8_t *)hdr; auth_tag = (uint8_t *)hdr + *pkt_octet_len + sizeof(srtcp_trailer_t) + mki_size; /* * check sequence number for overruns, and copy it into the packet @@ -4082,12 +4221,12 @@ 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, - (uint8_t *)enc_start, &enc_octet_len); + status = srtp_cipher_encrypt(session_keys->rtcp_cipher, enc_start, + &enc_octet_len); if (status) return srtp_err_status_cipher_fail; } /* initialize auth func context */ @@ -4098,11 +4237,11 @@ /* * run auth func over packet (including trailer), and write the * result at auth_tag */ status = - srtp_auth_compute(session_keys->rtcp_auth, (uint8_t *)auth_start, + srtp_auth_compute(session_keys->rtcp_auth, auth_start, (*pkt_octet_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; @@ -4127,13 +4266,13 @@ void *srtcp_hdr, int *pkt_octet_len, unsigned int use_mki) { srtcp_hdr_t *hdr = (srtcp_hdr_t *)srtcp_hdr; - uint32_t *enc_start; /* pointer to start of encrypted portion */ - uint32_t *auth_start; /* pointer to start of auth. portion */ - uint32_t *trailer_p; /* pointer to start of trailer */ + 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 */ unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */ uint8_t *auth_tag = NULL; /* location of auth_tag within packet */ uint8_t tmp_tag[SRTP_MAX_TAG_LEN]; srtp_err_status_t status; @@ -4145,12 +4284,10 @@ int e_bit_in_packet; /* whether the E-bit was found in the packet */ int sec_serv_confidentiality; /* whether confidentiality was requested */ unsigned int mki_size = 0; srtp_session_keys_t *session_keys = NULL; - /* we assume the hdr is 32-bit aligned to start */ - if (*pkt_octet_len < 0) return srtp_err_status_bad_param; /* * check that the length value is sane; we'll check again once we @@ -4184,13 +4321,12 @@ /* * Determine if MKI is being used and what session keys should be used */ if (use_mki) { - session_keys = srtp_get_session_keys( - stream, (uint8_t *)hdr, (const unsigned int *)pkt_octet_len, - &mki_size); + session_keys = srtp_get_session_keys_rtcp( + stream, (uint8_t *)hdr, (unsigned int)*pkt_octet_len, &mki_size); if (session_keys == NULL) return srtp_err_status_bad_mki; } else { session_keys = &stream->session_keys[0]; @@ -4230,31 +4366,30 @@ *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 = (uint32_t *)((char *)hdr + *pkt_octet_len - - (tag_len + mki_size + sizeof(srtcp_trailer_t))); + trailer_p = (uint8_t *)hdr + *pkt_octet_len - + (tag_len + mki_size + sizeof(srtcp_trailer_t)); memcpy(&trailer, trailer_p, sizeof(trailer)); - e_bit_in_packet = - (*((unsigned char *)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 = (uint32_t *)hdr + uint32s_in_rtcp_header; + enc_start = (uint8_t *)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 = (uint32_t *)hdr; + auth_start = (uint8_t *)hdr; /* * 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 @@ -4305,12 +4440,12 @@ status = srtp_auth_start(session_keys->rtcp_auth); if (status) return status; /* run auth func over packet, put result into tmp_tag */ - status = srtp_auth_compute(session_keys->rtcp_auth, (uint8_t *)auth_start, - auth_len, tmp_tag); + status = srtp_auth_compute(session_keys->rtcp_auth, auth_start, auth_len, + tmp_tag); debug_print(mod_srtp, "srtcp computed tag: %s", srtp_octet_string_hex_string(tmp_tag, tag_len)); if (status) return srtp_err_status_auth_fail; @@ -4334,12 +4469,12 @@ 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, - (uint8_t *)enc_start, &enc_octet_len); + status = srtp_cipher_decrypt(session_keys->rtcp_cipher, enc_start, + &enc_octet_len); if (status) return srtp_err_status_cipher_fail; } /* decrease the packet length by the length of the auth tag and seq_num */ @@ -4384,13 +4519,16 @@ status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream); if (status) return status; - /* add new stream to the head of the stream_list */ - new_stream->next = ctx->stream_list; - ctx->stream_list = new_stream; + /* add new stream to the list */ + status = srtp_insert_or_dealloc_stream(ctx->stream_list, new_stream, + ctx->stream_template); + if (status) { + return status; + } /* set stream (the pointer used in this function) */ stream = new_stream; } @@ -4567,49 +4705,66 @@ } return srtp_err_status_ok; } +struct get_protect_trailer_length_data { + uint32_t found_stream; /* whether at least one matching stream was found */ + uint32_t length; /* maximum trailer length found so far */ + uint32_t is_rtp; + uint32_t use_mki; + uint32_t mki_index; +}; + +static int get_protect_trailer_length_cb(srtp_stream_t stream, void *raw_data) +{ + struct get_protect_trailer_length_data *data = + (struct get_protect_trailer_length_data *)raw_data; + uint32_t temp_length; + + if (stream_get_protect_trailer_length(stream, data->is_rtp, data->use_mki, + data->mki_index, + &temp_length) == srtp_err_status_ok) { + data->found_stream = 1; + if (temp_length > data->length) { + data->length = temp_length; + } + } + + return 0; +} + srtp_err_status_t get_protect_trailer_length(srtp_t session, uint32_t is_rtp, uint32_t use_mki, uint32_t mki_index, uint32_t *length) { srtp_stream_ctx_t *stream; + struct get_protect_trailer_length_data data = { 0, 0, is_rtp, use_mki, + mki_index }; if (session == NULL) { return srtp_err_status_bad_param; } - if (session->stream_template == NULL && session->stream_list == NULL) { - return srtp_err_status_bad_param; - } - - *length = 0; - stream = session->stream_template; if (stream != NULL) { + data.found_stream = 1; stream_get_protect_trailer_length(stream, is_rtp, use_mki, mki_index, - length); + &data.length); } - stream = session->stream_list; - - while (stream != NULL) { - uint32_t temp_length; - if (stream_get_protect_trailer_length(stream, is_rtp, use_mki, - mki_index, &temp_length) == - srtp_err_status_ok) { - if (temp_length > *length) { - *length = temp_length; - } - } - stream = stream->next; + srtp_stream_list_for_each(session->stream_list, + get_protect_trailer_length_cb, &data); + + if (!data.found_stream) { + return srtp_err_status_bad_param; } + *length = data.length; return srtp_err_status_ok; } srtp_err_status_t srtp_get_protect_trailer_length(srtp_t session, uint32_t use_mki, @@ -4647,11 +4802,11 @@ */ static srtp_log_handler_func_t *srtp_log_handler = NULL; static void *srtp_log_handler_data = NULL; -void srtp_err_handler(srtp_err_reporting_level_t level, const char *msg) +static void srtp_err_handler(srtp_err_reporting_level_t level, const char *msg) { if (srtp_log_handler) { srtp_log_level_t log_level = srtp_log_level_error; switch (level) { case srtp_err_level_error: @@ -4719,5 +4874,94 @@ *roc = srtp_rdbx_get_roc(&stream->rtp_rdbx); return srtp_err_status_ok; } + +#ifndef SRTP_NO_STREAM_LIST + +/* in the default implementation, we have an intrusive doubly-linked list */ +typedef struct srtp_stream_list_ctx_t_ { + /* a stub stream that just holds pointers to the beginning and end of the + * list */ + srtp_stream_ctx_t data; +} srtp_stream_list_ctx_t_; + +srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr) +{ + srtp_stream_list_t list = + srtp_crypto_alloc(sizeof(srtp_stream_list_ctx_t_)); + if (list == NULL) { + return srtp_err_status_alloc_fail; + } + + list->data.next = NULL; + list->data.prev = NULL; + + *list_ptr = list; + return srtp_err_status_ok; +} + +srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list) +{ + /* list must be empty */ + if (list->data.next) { + return srtp_err_status_fail; + } + srtp_crypto_free(list); + return srtp_err_status_ok; +} + +srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list, + srtp_stream_t stream) +{ + /* insert at the head of the list */ + stream->next = list->data.next; + if (stream->next != NULL) { + stream->next->prev = stream; + } + list->data.next = stream; + stream->prev = &(list->data); + + return srtp_err_status_ok; +} + +srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc) +{ + /* walk down list until ssrc is found */ + srtp_stream_t stream = list->data.next; + while (stream != NULL) { + if (stream->ssrc == ssrc) { + return stream; + } + stream = stream->next; + } + + /* we haven't found our ssrc, so return a null */ + return NULL; +} + +void srtp_stream_list_remove(srtp_stream_list_t list, + srtp_stream_t stream_to_remove) +{ + (void)list; + + stream_to_remove->prev->next = stream_to_remove->next; + if (stream_to_remove->next != NULL) { + stream_to_remove->next->prev = stream_to_remove->prev; + } +} + +void srtp_stream_list_for_each(srtp_stream_list_t list, + int (*callback)(srtp_stream_t, void *), + void *data) +{ + srtp_stream_t stream = list->data.next; + while (stream != NULL) { + srtp_stream_t tmp = stream; + stream = stream->next; + if (callback(tmp, data)) + break; + } +} + +#endif diff --git a/third_party/libsrtp/src/test/.cvsignore b/third_party/libsrtp/src/test/.cvsignore deleted file mode 100644 --- a/third_party/libsrtp/src/test/.cvsignore +++ /dev/null @@ -1,13 +0,0 @@ -aes_calc -cipher_driver -datatypes_driver -dtls_srtp_driver -kernel_driver -rand_gen -rdbx_driver -replay_driver -roc_driver -rtpw -sha1_driver -srtp_driver -stat_driver diff --git a/third_party/libsrtp/src/test/cutest.h b/third_party/libsrtp/src/test/cutest.h --- a/third_party/libsrtp/src/test/cutest.h +++ b/third_party/libsrtp/src/test/cutest.h @@ -257,20 +257,19 @@ test_current_failures__++; test_current_already_logged__++; } if (test_verbose_level__ >= verbose_level) { - size_t n = 0; va_list args; printf(" "); if (file != NULL) - n += printf("%s:%d: Check ", file, line); + printf("%s:%d: Check ", file, line); va_start(args, fmt); - n += vprintf(fmt, args); + vprintf(fmt, args); va_end(args); printf("... "); test_print_in_color__(result_color, result_str); printf("\n"); @@ -466,11 +465,12 @@ break; case SIGTERM: signame = "SIGTERM"; break; default: - sprintf(tmp, "signal %d", WTERMSIG(exit_code)); + snprintf(tmp, sizeof(tmp), "signal %d", + WTERMSIG(exit_code)); signame = tmp; break; } test_error__("Test interrupted by %s", signame); } else { diff --git a/third_party/libsrtp/src/test/meson.build b/third_party/libsrtp/src/test/meson.build --- a/third_party/libsrtp/src/test/meson.build +++ b/third_party/libsrtp/src/test/meson.build @@ -52,11 +52,11 @@ is_parallel: false, workdir: meson.current_build_dir()) endif rtpw_test_gcm_sh = find_program('rtpw_test_gcm.sh', required: false) - if (use_openssl or use_nss) and rtpw_test_gcm_sh.found() + if (use_openssl or use_nss or use_mbedtls) and rtpw_test_gcm_sh.found() test('rtpw_test_gcm', rtpw_test_gcm_sh, args: ['-w', words_txt], depends: rtpw_exe, is_parallel: false, workdir: meson.current_build_dir()) diff --git a/third_party/libsrtp/src/test/rdbx_driver.c b/third_party/libsrtp/src/test/rdbx_driver.c --- a/third_party/libsrtp/src/test/rdbx_driver.c +++ b/third_party/libsrtp/src/test/rdbx_driver.c @@ -141,11 +141,11 @@ srtp_err_status_t rdbx_check_add(srtp_rdbx_t *rdbx, uint32_t idx) { int delta; srtp_xtd_seq_num_t est; - delta = srtp_index_guess(&rdbx->index, &est, idx); + delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); if (srtp_rdbx_check(rdbx, delta) != srtp_err_status_ok) { printf("replay_check failed at index %u\n", idx); return srtp_err_status_algo_fail; } @@ -174,11 +174,11 @@ { int delta; srtp_xtd_seq_num_t est; srtp_err_status_t status; - delta = srtp_index_guess(&rdbx->index, &est, idx); + delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); status = srtp_rdbx_check(rdbx, delta); if (status == srtp_err_status_ok) { printf("delta: %d ", delta); printf("replay_check failed at index %u (false positive)\n", idx); @@ -192,11 +192,11 @@ { int delta; srtp_xtd_seq_num_t est; srtp_err_status_t rstat; - delta = srtp_index_guess(&rdbx->index, &est, idx); + delta = srtp_index_guess(&rdbx->index, &est, (srtp_sequence_number_t)idx); rstat = srtp_rdbx_check(rdbx, delta); if ((rstat != srtp_err_status_ok) && (rstat != srtp_err_status_replay_old)) { printf("replay_check_add_unordered failed at index %u\n", idx); @@ -331,11 +331,11 @@ } failures = 0; timer = clock(); for (i = 0; (int)i < num_trials; i++) { - delta = srtp_index_guess(&rdbx.index, &est, i); + delta = srtp_index_guess(&rdbx.index, &est, (srtp_sequence_number_t)i); if (srtp_rdbx_check(&rdbx, delta) != srtp_err_status_ok) ++failures; else if (srtp_rdbx_add_index(&rdbx, delta) != srtp_err_status_ok) ++failures; diff --git a/third_party/libsrtp/src/test/replay_driver.c b/third_party/libsrtp/src/test/replay_driver.c --- a/third_party/libsrtp/src/test/replay_driver.c +++ b/third_party/libsrtp/src/test/replay_driver.c @@ -130,11 +130,11 @@ } return srtp_err_status_ok; } -srtp_err_status_t test_rdb_db() +srtp_err_status_t test_rdb_db(void) { srtp_rdb_t rdb; uint32_t idx, ircvd; ut_connection utc; srtp_err_status_t err; @@ -249,31 +249,24 @@ double rdb_check_adds_per_second(void) { uint32_t i; srtp_rdb_t rdb; clock_t timer; - int failures = 0; /* count number of failures */ if (srtp_rdb_init(&rdb) != srtp_err_status_ok) { printf("rdb_init failed\n"); exit(1); } timer = clock(); for (i = 0; i < REPLAY_NUM_TRIALS; i += 3) { - if (srtp_rdb_check(&rdb, i + 2) != srtp_err_status_ok) - ++failures; - if (srtp_rdb_add_index(&rdb, i + 2) != srtp_err_status_ok) - ++failures; - if (srtp_rdb_check(&rdb, i + 1) != srtp_err_status_ok) - ++failures; - if (srtp_rdb_add_index(&rdb, i + 1) != srtp_err_status_ok) - ++failures; - if (srtp_rdb_check(&rdb, i) != srtp_err_status_ok) - ++failures; - if (srtp_rdb_add_index(&rdb, i) != srtp_err_status_ok) - ++failures; + srtp_rdb_check(&rdb, i + 2); + srtp_rdb_add_index(&rdb, i + 2); + srtp_rdb_check(&rdb, i + 1); + srtp_rdb_add_index(&rdb, i + 1); + srtp_rdb_check(&rdb, i); + srtp_rdb_add_index(&rdb, i); } timer = clock() - timer; return (double)CLOCKS_PER_SEC * REPLAY_NUM_TRIALS / timer; } diff --git a/third_party/libsrtp/src/test/roc_driver.c b/third_party/libsrtp/src/test/roc_driver.c --- a/third_party/libsrtp/src/test/roc_driver.c +++ b/third_party/libsrtp/src/test/roc_driver.c @@ -143,11 +143,11 @@ return srtp_err_status_algo_fail; } /* now update local srtp_xtd_seq_num_t as necessary */ if (delta > 0) - srtp_index_advance(&local, delta); + srtp_index_advance(&local, (srtp_sequence_number_t)delta); if (ref != est) { #if ROC_VERBOSE printf(" *bad estimate*\n"); #endif diff --git a/third_party/libsrtp/src/test/rtp.h b/third_party/libsrtp/src/test/rtp.h --- a/third_party/libsrtp/src/test/rtp.h +++ b/third_party/libsrtp/src/test/rtp.h @@ -121,18 +121,18 @@ int srtp_sender_init( rtp_sender_t rtp_ctx, /* structure to be init'ed */ struct sockaddr_in name, /* socket name */ srtp_sec_serv_t security_services, /* sec. servs. to be used */ unsigned char *input_key /* master key/salt in hex */ - ); +); int srtp_receiver_init( rtp_receiver_t rtp_ctx, /* structure to be init'ed */ struct sockaddr_in name, /* socket name */ srtp_sec_serv_t security_services, /* sec. servs. to be used */ unsigned char *input_key /* master key/salt in hex */ - ); +); int rtp_sender_init_srtp(rtp_sender_t sender, const srtp_policy_t *policy); int rtp_sender_deinit_srtp(rtp_sender_t sender); diff --git a/third_party/libsrtp/src/test/rtp.c b/third_party/libsrtp/src/test/rtp.c --- a/third_party/libsrtp/src/test/rtp.c +++ b/third_party/libsrtp/src/test/rtp.c @@ -129,14 +129,13 @@ stat = srtp_unprotect(receiver->srtp_ctx, &receiver->message.header, &octets_recvd); if (stat) { fprintf(stderr, "error: srtp unprotection failed with code %d%s\n", stat, - stat == srtp_err_status_replay_fail - ? " (replay check failed)" - : stat == srtp_err_status_auth_fail ? " (auth check failed)" - : ""); + stat == srtp_err_status_replay_fail ? " (replay check failed)" + : stat == srtp_err_status_auth_fail ? " (auth check failed)" + : ""); return -1; } strncpy(msg, receiver->message.body, octets_recvd); return octets_recvd; diff --git a/third_party/libsrtp/src/test/rtp_decoder.h b/third_party/libsrtp/src/test/rtp_decoder.h --- a/third_party/libsrtp/src/test/rtp_decoder.h +++ b/third_party/libsrtp/src/test/rtp_decoder.h @@ -60,11 +60,11 @@ typedef struct rtp_decoder_ctx_t { srtp_policy_t policy; srtp_ctx_t *srtp_ctx; rtp_decoder_mode_t mode; - int rtp_offset; + size_t rtp_offset; struct timeval start_tv; int frame_nr; int error_cnt; int rtp_cnt; int rtcp_cnt; @@ -100,11 +100,12 @@ void rtp_decoder_dealloc(rtp_decoder_t rtp_ctx); int rtp_decoder_init(rtp_decoder_t dcdr, srtp_policy_t policy, rtp_decoder_mode_t mode, - int rtp_packet_offset); + size_t rtp_packet_offset, + uint32_t roc); int rtp_decoder_deinit(rtp_decoder_t decoder); void rtp_decoder_srtp_log_handler(srtp_log_level_t level, const char *msg, diff --git a/third_party/libsrtp/src/test/rtp_decoder.c b/third_party/libsrtp/src/test/rtp_decoder.c --- a/third_party/libsrtp/src/test/rtp_decoder.c +++ b/third_party/libsrtp/src/test/rtp_decoder.c @@ -94,49 +94,50 @@ static struct srtp_crypto_suite srtp_crypto_suites[] = { #if 0 {.can_name = "F8_128_HMAC_SHA1_32", .gcm_on = 0, .key_size = 128, .tag_size = 4}, #endif - {.can_name = "AES_CM_128_HMAC_SHA1_32", - .gcm_on = 0, - .key_size = 128, - .tag_size = 4 }, - {.can_name = "AES_CM_128_HMAC_SHA1_80", - .gcm_on = 0, - .key_size = 128, - .tag_size = 10 }, - {.can_name = "AES_192_CM_HMAC_SHA1_32", - .gcm_on = 0, - .key_size = 192, - .tag_size = 4 }, - {.can_name = "AES_192_CM_HMAC_SHA1_80", - .gcm_on = 0, - .key_size = 192, - .tag_size = 10 }, - {.can_name = "AES_256_CM_HMAC_SHA1_32", - .gcm_on = 0, - .key_size = 256, - .tag_size = 4 }, - {.can_name = "AES_256_CM_HMAC_SHA1_80", - .gcm_on = 0, - .key_size = 256, - .tag_size = 10 }, - {.can_name = "AEAD_AES_128_GCM", - .gcm_on = 1, - .key_size = 128, - .tag_size = 16 }, - {.can_name = "AEAD_AES_256_GCM", - .gcm_on = 1, - .key_size = 256, - .tag_size = 16 }, - {.can_name = NULL } + { .can_name = "AES_CM_128_HMAC_SHA1_32", + .gcm_on = 0, + .key_size = 128, + .tag_size = 4 }, + { .can_name = "AES_CM_128_HMAC_SHA1_80", + .gcm_on = 0, + .key_size = 128, + .tag_size = 10 }, + { .can_name = "AES_192_CM_HMAC_SHA1_32", + .gcm_on = 0, + .key_size = 192, + .tag_size = 4 }, + { .can_name = "AES_192_CM_HMAC_SHA1_80", + .gcm_on = 0, + .key_size = 192, + .tag_size = 10 }, + { .can_name = "AES_256_CM_HMAC_SHA1_32", + .gcm_on = 0, + .key_size = 256, + .tag_size = 4 }, + { .can_name = "AES_256_CM_HMAC_SHA1_80", + .gcm_on = 0, + .key_size = 256, + .tag_size = 10 }, + { .can_name = "AEAD_AES_128_GCM", + .gcm_on = 1, + .key_size = 128, + .tag_size = 16 }, + { .can_name = "AEAD_AES_256_GCM", + .gcm_on = 1, + .key_size = 256, + .tag_size = 16 }, + { .can_name = NULL } }; void rtp_decoder_srtp_log_handler(srtp_log_level_t level, const char *msg, void *data) { + (void)data; char level_char = '?'; switch (level) { case srtp_log_level_error: level_char = 'e'; break; @@ -171,14 +172,16 @@ int b64_input = 0; char key[MAX_KEY_LEN]; struct bpf_program fp; char filter_exp[MAX_FILTER] = ""; char pcap_file[MAX_FILE] = "-"; - int rtp_packet_offset = DEFAULT_RTP_OFFSET; + size_t rtp_packet_offset = DEFAULT_RTP_OFFSET; rtp_decoder_t dec; - srtp_policy_t policy = { { 0 } }; + srtp_policy_t policy = { 0 }; rtp_decoder_mode_t mode = mode_rtp; + srtp_ssrc_t ssrc = { ssrc_any_inbound, 0 }; + uint32_t roc = 0; srtp_err_status_t status; int len; int expected_len; int do_list_mods = 0; @@ -200,11 +203,11 @@ exit(1); } /* check args */ while (1) { - c = getopt_s(argc, argv, "b:k:gt:ae:ld:f:s:m:p:o:"); + c = getopt_s(argc, argv, "b:k:gt:ae:ld:f:c:m:p:o:s:r:"); if (c == -1) { break; } switch (c) { case 'b': @@ -254,11 +257,11 @@ strcpy(filter_exp, optarg_s); break; case 'l': do_list_mods = 1; break; - case 's': + case 'c': for (i_scsp = &srtp_crypto_suites[0]; i_scsp->can_name != NULL; i_scsp++) { if (strcasecmp(i_scsp->can_name, optarg_s) == 0) { break; } @@ -295,10 +298,17 @@ strcpy(pcap_file, optarg_s); break; case 'o': rtp_packet_offset = atoi(optarg_s); break; + case 's': + ssrc.type = ssrc_specific; + ssrc.value = strtol(optarg_s, NULL, 0); + break; + case 'r': + roc = atoi(optarg_s); + break; default: usage(argv[0]); } } @@ -538,18 +548,20 @@ expected_len = policy.rtp.cipher_key_len * 2; len = hex_string_to_octet_string(key, input_key, expected_len); } /* check that hex string is the right length */ if (len < expected_len) { - fprintf(stderr, "error: too few digits in key/salt " - "(should be %d digits, found %d)\n", + fprintf(stderr, + "error: too few digits in key/salt " + "(should be %d digits, found %d)\n", expected_len, len); exit(1); } - if (strlen(input_key) > policy.rtp.cipher_key_len * 2) { - fprintf(stderr, "error: too many digits in key/salt " - "(should be %d hexadecimal digits, found %u)\n", + if (strlen(input_key) > (size_t)policy.rtp.cipher_key_len * 2) { + fprintf(stderr, + "error: too many digits in key/salt " + "(should be %d hexadecimal digits, found %u)\n", policy.rtp.cipher_key_len * 2, (unsigned)strlen(input_key)); exit(1); } int key_octets = (scs.key_size / 8); @@ -563,10 +575,17 @@ fprintf(stderr, "error: neither encryption or authentication were selected\n"); exit(1); } + policy.ssrc = ssrc; + + if (roc != 0 && policy.ssrc.type != ssrc_specific) { + fprintf(stderr, "error: setting ROC (-r) requires -s \n"); + exit(1); + } + pcap_handle = pcap_open_offline(pcap_file, errbuf); if (!pcap_handle) { fprintf(stderr, "libpcap failed to open file '%s'\n", errbuf); exit(1); @@ -586,11 +605,11 @@ if (dec == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } fprintf(stderr, "Starting decoder\n"); - if (rtp_decoder_init(dec, policy, mode, rtp_packet_offset)) { + if (rtp_decoder_init(dec, policy, mode, rtp_packet_offset, roc)) { fprintf(stderr, "error: init failed\n"); exit(1); } pcap_loop(pcap_handle, 0, rtp_decoder_handle_pkt, (u_char *)dec); @@ -618,27 +637,31 @@ void usage(char *string) { fprintf( stderr, - "usage: %s [-d ]* [[-k][-b] ] [-a][-t][-e] [-s " - "] [-m ]\n" + "usage: %s [-d ]* [[-k][-b] ] [-a][-t][-e] [-c " + "] [-m ] [-s [-r ]]\n" "or %s -l\n" "where -a use message authentication\n" " -e use encryption (use 128 or 256 for key size)\n" " -g Use AES-GCM mode (must be used with -e)\n" " -t Tag size to use (in GCM mode use 8 or 16)\n" " -k sets the srtp master key given in hexadecimal\n" " -b sets the srtp master key given in base64\n" " -l list debug modules\n" " -f \"\" to filter only the desired SRTP packets\n" " -d turn on debugging for module \n" - " -s \"\" to set both key and tag size based\n" + " -c \"\" to set both key and tag size based\n" " on RFC4568-style crypto suite specification\n" " -m set the mode to be one of [rtp]|rtcp|rtcp-mux\n" " -p path to pcap file (defaults to stdin)\n" - " -o byte offset of RTP packet in capture (defaults to 42)\n", + " -o byte offset of RTP packet in capture (defaults to 42)\n" + " -s restrict decrypting to the given SSRC (in host byte " + "order)\n" + " -r initial rollover counter, requires -s " + "(defaults to 0)\n", string, string); exit(1); } rtp_decoder_t rtp_decoder_alloc(void) @@ -660,11 +683,12 @@ } int rtp_decoder_init(rtp_decoder_t dcdr, srtp_policy_t policy, rtp_decoder_mode_t mode, - int rtp_packet_offset) + size_t rtp_packet_offset, + uint32_t roc) { dcdr->rtp_offset = rtp_packet_offset; dcdr->srtp_ctx = NULL; dcdr->start_tv.tv_usec = 0; dcdr->start_tv.tv_sec = 0; @@ -672,29 +696,34 @@ dcdr->error_cnt = 0; dcdr->rtp_cnt = 0; dcdr->rtcp_cnt = 0; dcdr->mode = mode; dcdr->policy = policy; - dcdr->policy.ssrc.type = ssrc_any_inbound; if (srtp_create(&dcdr->srtp_ctx, &dcdr->policy)) { return 1; } + + if (policy.ssrc.type == ssrc_specific && roc != 0) { + if (srtp_set_stream_roc(dcdr->srtp_ctx, policy.ssrc.value, roc)) { + return 1; + } + } return 0; } /* * decodes key as base64 */ void hexdump(const void *ptr, size_t size) { - int i, j; + size_t i, j; const unsigned char *cptr = ptr; for (i = 0; i < size; i += 16) { - fprintf(stdout, "%04x ", i); + fprintf(stdout, "%04x ", (unsigned int)i); for (j = 0; j < 16 && i + j < size; j++) { fprintf(stdout, "%02x ", cptr[i + j]); } fprintf(stdout, "\n"); } @@ -762,9 +791,9 @@ return; } dcdr->rtcp_cnt++; } timersub(&hdr->ts, &dcdr->start_tv, &delta); - fprintf(stdout, "%02ld:%02ld.%06ld\n", delta.tv_sec / 60, delta.tv_sec % 60, - (long)delta.tv_usec); + fprintf(stdout, "%02ld:%02d.%06ld\n", (long)(delta.tv_sec / 60), + (int)(delta.tv_sec % 60), (long)delta.tv_usec); hexdump(&message, octets_recvd); } diff --git a/third_party/libsrtp/src/test/rtpw.c b/third_party/libsrtp/src/test/rtpw.c --- a/third_party/libsrtp/src/test/rtpw.c +++ b/third_party/libsrtp/src/test/rtpw.c @@ -283,11 +283,21 @@ /* get port from arg */ port = atoi(argv[optind_s++]); /* set address */ -#ifdef HAVE_INET_ATON +#ifdef HAVE_INET_PTON + if (0 == inet_pton(AF_INET, address, &rcvr_addr)) { + fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], + address); + exit(1); + } + if (rcvr_addr.s_addr == INADDR_NONE) { + fprintf(stderr, "%s: address error", argv[0]); + exit(1); + } +#elif HAVE_INET_ATON if (0 == inet_aton(address, &rcvr_addr)) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } @@ -471,18 +481,20 @@ expected_len = policy.rtp.cipher_key_len * 2; len = hex_string_to_octet_string(key, input_key, expected_len); } /* check that hex string is the right length */ if (len < expected_len) { - fprintf(stderr, "error: too few digits in key/salt " - "(should be %d digits, found %d)\n", + fprintf(stderr, + "error: too few digits in key/salt " + "(should be %d digits, found %d)\n", expected_len, len); exit(1); } if ((int)strlen(input_key) > policy.rtp.cipher_key_len * 2) { - fprintf(stderr, "error: too many digits in key/salt " - "(should be %d hexadecimal digits, found %u)\n", + fprintf(stderr, + "error: too many digits in key/salt " + "(should be %d hexadecimal digits, found %u)\n", policy.rtp.cipher_key_len * 2, (unsigned)strlen(input_key)); exit(1); } printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); diff --git a/third_party/libsrtp/src/test/rtpw_test.sh b/third_party/libsrtp/src/test/rtpw_test.sh --- a/third_party/libsrtp/src/test/rtpw_test.sh +++ b/third_party/libsrtp/src/test/rtpw_test.sh @@ -64,17 +64,17 @@ key=Ky7cUDT2GnI0XKWYbXv9AYmqbcLsqzL9mvdN9t/G ARGS="-b $key -a -e 128" -# First, we run "killall" to get rid of all existing rtpw processes. +# First, we run "pkill" to get rid of all existing rtpw processes. # This step also enables this script to clean up after itself; if this # script is interrupted after the rtpw processes are started but before # they are killed, those processes will linger. Re-running the script # will get rid of them. -killall rtpw 2>/dev/null +pkill -x rtpw 2>/dev/null if test -n $MESON_EXE_WRAPPER || test -x $RTPW; then echo $0 ": starting rtpw receiver process... " diff --git a/third_party/libsrtp/src/test/rtpw_test_gcm.sh b/third_party/libsrtp/src/test/rtpw_test_gcm.sh --- a/third_party/libsrtp/src/test/rtpw_test_gcm.sh +++ b/third_party/libsrtp/src/test/rtpw_test_gcm.sh @@ -60,17 +60,17 @@ RTPW=./rtpw$EXE [ -n "$MESON_EXE_WRAPPER" ] && RTPW="$MESON_EXE_WRAPPER $RTPW" DEST_PORT=9999 DURATION=3 -# First, we run "killall" to get rid of all existing rtpw processes. +# First, we run "pkill" to get rid of all existing rtpw processes. # This step also enables this script to clean up after itself; if this # script is interrupted after the rtpw processes are started but before # they are killed, those processes will linger. Re-running the script # will get rid of them. -killall rtpw 2>/dev/null +pkill -x rtpw 2>/dev/null if test -n $MESON_EXE_WRAPPER || test -x $RTPW; then GCMARGS128="-k 01234567890123456789012345678901234567890123456789012345 -g -e 128" echo $0 ": starting GCM mode 128-bit rtpw receiver process... " diff --git a/third_party/libsrtp/src/test/srtp_driver.c b/third_party/libsrtp/src/test/srtp_driver.c --- a/third_party/libsrtp/src/test/srtp_driver.c +++ b/third_party/libsrtp/src/test/srtp_driver.c @@ -47,10 +47,11 @@ #include /* for malloc(), free() */ #include /* for print(), fflush() */ #include "getopt_s.h" /* for local getopt() */ #include "srtp_priv.h" +#include "stream_list_priv.h" #include "util.h" #ifdef HAVE_NETINET_IN_H #include #elif defined HAVE_WINSOCK2_H @@ -91,10 +92,12 @@ srtp_err_status_t srtp_test_protect_trailer_length(void); srtp_err_status_t srtp_test_protect_rtcp_trailer_length(void); +srtp_err_status_t srtp_test_out_of_order_after_rollover(void); + srtp_err_status_t srtp_test_get_roc(void); srtp_err_status_t srtp_test_set_receiver_roc(void); srtp_err_status_t srtp_test_set_sender_roc(void); @@ -117,19 +120,23 @@ srtp_err_status_t srtp_session_print_policy(srtp_t srtp); srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy); char *srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len); +char *srtp_rtcp_packet_to_string(srtcp_hdr_t *hdr, int pkt_octet_len); double mips_estimate(int num_trials, int *ignore); +srtp_err_status_t srtp_stream_list_test(void); + #define TEST_MKI_ID_SIZE 4 extern uint8_t test_key[46]; extern uint8_t test_key_2[46]; extern uint8_t test_mki_id[TEST_MKI_ID_SIZE]; extern uint8_t test_mki_id_2[TEST_MKI_ID_SIZE]; +extern uint8_t test_key_gcm[28]; // clang-format off srtp_master_key_t master_key_1 = { test_key, test_mki_id, @@ -148,25 +155,28 @@ }; // clang-format on void usage(char *prog_name) { - printf("usage: %s [ -t ][ -c ][ -v ][ -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" - " -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" + " -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); exit(1); } void log_handler(srtp_log_level_t level, const char *msg, void *data) { char level_char = '?'; + (void)data; switch (level) { case srtp_log_level_error: level_char = 'e'; break; case srtp_log_level_warning: @@ -211,22 +221,24 @@ int q; unsigned do_timing_test = 0; unsigned do_rejection_test = 0; unsigned do_codec_timing = 0; unsigned do_validation = 0; + unsigned do_stream_list = 0; unsigned do_list_mods = 0; unsigned do_log_stdout = 0; srtp_err_status_t status; + const size_t hdr_size = 12; /* * verify that the compiler has interpreted the header data * structure srtp_hdr_t correctly */ - if (sizeof(srtp_hdr_t) != 12) { + if (sizeof(srtp_hdr_t) != hdr_size) { printf("error: srtp_hdr_t has incorrect size" - "(size is %ld bytes, expected 12)\n", - (long)sizeof(srtp_hdr_t)); + "(size is %ld bytes, expected %ld)\n", + (long)sizeof(srtp_hdr_t), (long)hdr_size); exit(1); } /* initialize srtp library */ status = srtp_init(); @@ -244,11 +256,11 @@ exit(1); } /* process input arguments */ while (1) { - q = getopt_s(argc, argv, "trcvold:"); + q = getopt_s(argc, argv, "trcvsold:"); if (q == -1) { break; } switch (q) { case 't': @@ -260,10 +272,14 @@ case 'c': do_codec_timing = 1; break; case 'v': do_validation = 1; + do_stream_list = 1; + break; + case 's': + do_stream_list = 1; break; case 'o': do_log_stdout = 1; break; case 'l': @@ -280,11 +296,11 @@ usage(argv[0]); } } if (!do_validation && !do_timing_test && !do_codec_timing && - !do_list_mods && !do_rejection_test) { + !do_list_mods && !do_rejection_test && !do_stream_list) { usage(argv[0]); } if (do_log_stdout) { status = srtp_install_log_handler(log_handler, NULL); @@ -557,10 +573,18 @@ } else { printf("failed\n"); exit(1); } + printf("testing srtp_test_out_of_order_after_rollover()..."); + if (srtp_test_out_of_order_after_rollover() == srtp_err_status_ok) { + printf("passed\n"); + } else { + printf("failed\n"); + exit(1); + } + printf("testing srtp_test_get_roc()..."); if (srtp_test_get_roc() == srtp_err_status_ok) { printf("passed\n"); } else { printf("failed\n"); @@ -582,10 +606,20 @@ printf("failed\n"); exit(1); } } + if (do_stream_list) { + printf("testing srtp_stream_list..."); + if (srtp_stream_list_test() == srtp_err_status_ok) { + printf("passed\n"); + } else { + printf("failed\n"); + exit(1); + } + } + if (do_timing_test) { const srtp_policy_t **policy = policy_array; /* loop over policies, run timing test for each */ while (*policy != NULL) { @@ -716,10 +750,51 @@ *pkt_len = bytes_in_hdr + pkt_octet_len; return hdr; } +srtcp_hdr_t *srtp_create_rtcp_test_packet(int pkt_octet_len, + uint32_t ssrc, + int *pkt_len) +{ + int i; + uint8_t *buffer; + srtcp_hdr_t *hdr; + int 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; + } + + 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->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; + } + + *pkt_len = bytes_in_hdr + pkt_octet_len; + + return hdr; +} + static srtp_hdr_t *srtp_create_test_packet_extended(int pkt_octet_len, uint32_t ssrc, uint16_t seq, uint32_t ts, int *pkt_len) @@ -973,11 +1048,11 @@ return srtp_protect_mki(srtp_sender, hdr, len, 1, mki_index); } } srtp_err_status_t srtp_test_call_protect_rtcp(srtp_t srtp_sender, - srtp_hdr_t *hdr, + srtcp_hdr_t *hdr, int *len, int mki_index) { if (mki_index == -1) { return srtp_protect_rtcp(srtp_sender, hdr, len); @@ -997,11 +1072,11 @@ return srtp_unprotect_mki(srtp_sender, hdr, len, use_mki); } } srtp_err_status_t srtp_test_call_unprotect_rtcp(srtp_t srtp_sender, - srtp_hdr_t *hdr, + srtcp_hdr_t *hdr, int *len, int use_mki) { if (use_mki == -1) { return srtp_unprotect_rtcp(srtp_sender, hdr, len); @@ -1106,12 +1181,13 @@ err_check(srtp_get_protect_trailer_length(srtp_sender, use_mki, mki_index, &tag_length)); pkt_end = (uint8_t *)hdr + msg_len + tag_length; for (i = 0; i < 4; i++) { if (pkt_end[i] != 0xff) { - fprintf(stdout, "overwrite in srtp_protect() function " - "(expected %x, found %x in trailing octet %d)\n", + fprintf(stdout, + "overwrite in srtp_protect() function " + "(expected %x, found %x in trailing octet %d)\n", 0xff, ((uint8_t *)hdr)[i], i); free(hdr); free(hdr2); return srtp_err_status_algo_fail; } @@ -1203,11 +1279,11 @@ if (status != srtp_err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); free(hdr2); free(rcvr_policy); - return status; + return srtp_err_status_algo_fail; } else { printf("passed\n"); } printf("testing for false positives in auth check..."); @@ -1222,15 +1298,16 @@ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ status = srtp_test_call_unprotect(srtp_rcvr, hdr, &len, use_mki); if (status != srtp_err_status_auth_fail) { + printf("failed with error code %d\n", status); printf("failed\n"); free(hdr); free(hdr2); free(rcvr_policy); - return status; + return srtp_err_status_algo_fail; } else { printf("passed\n"); } } @@ -1247,11 +1324,11 @@ { int i; srtp_t srtcp_sender; srtp_t srtcp_rcvr; srtp_err_status_t status = srtp_err_status_ok; - srtp_hdr_t *hdr, *hdr2; + srtcp_hdr_t *hdr, *hdr2; uint8_t hdr_enc[64]; uint8_t *pkt_end; int msg_len_octets, msg_len_enc, msg_len; int len, len2; uint32_t tag_length; @@ -1276,57 +1353,58 @@ ssrc = 0xdecafbad; } else { ssrc = policy->ssrc.value; } msg_len_octets = 28; - hdr = srtp_create_test_packet(msg_len_octets, ssrc, &len); + hdr = srtp_create_rtcp_test_packet(msg_len_octets, ssrc, &len); /* save message len */ msg_len = len; if (hdr == NULL) { return srtp_err_status_alloc_fail; } - hdr2 = srtp_create_test_packet(msg_len_octets, ssrc, &len2); + hdr2 = srtp_create_rtcp_test_packet(msg_len_octets, ssrc, &len2); if (hdr2 == NULL) { free(hdr); return srtp_err_status_alloc_fail; } debug_print(mod_driver, "before protection:\n%s", - srtp_packet_to_string(hdr, len)); + srtp_rtcp_packet_to_string(hdr, len)); #if PRINT_REFERENCE_PACKET debug_print(mod_driver, "reference packet before protection:\n%s", octet_string_hex_string((uint8_t *)hdr, len)); #endif err_check(srtp_test_call_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); debug_print(mod_driver, "after protection:\n%s", - srtp_packet_to_string(hdr, len)); + srtp_rtcp_packet_to_string(hdr, len)); #if PRINT_REFERENCE_PACKET debug_print(mod_driver, "after protection:\n%s", octet_string_hex_string((uint8_t *)hdr, len)); #endif /* save protected message and length */ memcpy(hdr_enc, hdr, len); msg_len_enc = len; /* - * check for overrun of the srtp_protect() function + * check for overrun of the srtp_protect_rtcp() function * * The packet is followed by a value of 0xfffff; if the value of the * data following the packet is different, then we know that the * protect function is overwriting the end of the packet. */ srtp_get_protect_rtcp_trailer_length(srtcp_sender, use_mki, mki_index, &tag_length); pkt_end = (uint8_t *)hdr + msg_len + tag_length; for (i = 0; i < 4; i++) { if (pkt_end[i] != 0xff) { - fprintf(stdout, "overwrite in srtp_protect_rtcp() function " - "(expected %x, found %x in trailing octet %d)\n", + fprintf(stdout, + "overwrite in srtp_protect_rtcp() function " + "(expected %x, found %x in trailing octet %d)\n", 0xff, ((uint8_t *)hdr)[i], i); free(hdr); free(hdr2); return srtp_err_status_algo_fail; } @@ -1379,13 +1457,13 @@ err_check(srtp_create(&srtcp_rcvr, rcvr_policy)); err_check(srtp_test_call_unprotect_rtcp(srtcp_rcvr, hdr, &len, use_mki)); debug_print(mod_driver, "after unprotection:\n%s", - srtp_packet_to_string(hdr, len)); - - /* verify that the unprotected packet matches the origial one */ + srtp_rtcp_packet_to_string(hdr, len)); + + /* verify that the unprotected packet matches the original one */ for (i = 0; i < len; i++) { if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) { fprintf(stdout, "mismatch at octet %d\n", i); status = srtp_err_status_algo_fail; } @@ -1411,35 +1489,33 @@ if (status != srtp_err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); free(hdr2); free(rcvr_policy); - return status; + return srtp_err_status_algo_fail; } else { printf("passed\n"); } printf("testing for false positives in auth check..."); - /* increment sequence number in header */ - hdr->seq++; - /* apply protection */ err_check( srtp_test_call_protect_rtcp(srtcp_sender, hdr, &len, mki_index)); /* flip bits in packet */ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ status = srtp_test_call_unprotect_rtcp(srtcp_rcvr, hdr, &len, use_mki); if (status != srtp_err_status_auth_fail) { + printf("failed with error code %d\n", status); printf("failed\n"); free(hdr); free(hdr2); free(rcvr_policy); - return status; + return srtp_err_status_algo_fail; } else { printf("passed\n"); } } @@ -1450,105 +1526,97 @@ free(hdr2); free(rcvr_policy); return srtp_err_status_ok; } +struct srtp_session_print_stream_data { + // set by callback to indicate failure + srtp_err_status_t status; + // indicates if it is the template stream or a regular stream + int is_template; +}; + +int srtp_session_print_stream(srtp_stream_t stream, void *raw_data) +{ + static const char *serv_descr[4] = { "none", "confidentiality", + "authentication", + "confidentiality and authentication" }; + static const char *direction[3] = { "unknown", "outbound", "inbound" }; + + struct srtp_session_print_stream_data *data = + (struct srtp_session_print_stream_data *)raw_data; + srtp_session_keys_t *session_keys = &stream->session_keys[0]; + char ssrc_text[32]; + + if (!data->is_template && stream->rtp_services > sec_serv_conf_and_auth) { + data->status = srtp_err_status_bad_param; + return 1; + } + + if (data->is_template) { + snprintf(ssrc_text, sizeof(ssrc_text), "any %s", + direction[stream->direction]); + } else { + snprintf(ssrc_text, sizeof(ssrc_text), "0x%08x", stream->ssrc); + } + + printf("# SSRC: %s\r\n" + "# rtp cipher: %s\r\n" + "# rtp auth: %s\r\n" + "# rtp services: %s\r\n" + "# rtcp cipher: %s\r\n" + "# rtcp auth: %s\r\n" + "# rtcp services: %s\r\n" + "# window size: %lu\r\n" + "# tx rtx allowed:%s\r\n", + ssrc_text, session_keys->rtp_cipher->type->description, + session_keys->rtp_auth->type->description, + serv_descr[stream->rtp_services], + session_keys->rtcp_cipher->type->description, + session_keys->rtcp_auth->type->description, + serv_descr[stream->rtcp_services], + srtp_rdbx_get_window_size(&stream->rtp_rdbx), + stream->allow_repeat_tx ? "true" : "false"); + + printf("# Encrypted extension headers: "); + if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) { + int *enc_xtn_hdr = stream->enc_xtn_hdr; + int count = stream->enc_xtn_hdr_count; + while (count > 0) { + printf("%d ", *enc_xtn_hdr); + enc_xtn_hdr++; + count--; + } + printf("\n"); + } else { + printf("none\n"); + } + + return 0; +} + srtp_err_status_t srtp_session_print_policy(srtp_t srtp) { - char *serv_descr[4] = { "none", "confidentiality", "authentication", - "confidentiality and authentication" }; - char *direction[3] = { "unknown", "outbound", "inbound" }; - srtp_stream_t stream; - srtp_session_keys_t *session_keys = NULL; + struct srtp_session_print_stream_data data = { srtp_err_status_ok, 0 }; /* sanity checking */ if (srtp == NULL) { return srtp_err_status_fail; } /* if there's a template stream, print it out */ if (srtp->stream_template != NULL) { - stream = srtp->stream_template; - session_keys = &stream->session_keys[0]; - printf("# SSRC: any %s\r\n" - "# rtp cipher: %s\r\n" - "# rtp auth: %s\r\n" - "# rtp services: %s\r\n" - "# rtcp cipher: %s\r\n" - "# rtcp auth: %s\r\n" - "# rtcp services: %s\r\n" - "# window size: %lu\r\n" - "# tx rtx allowed:%s\r\n", - direction[stream->direction], - session_keys->rtp_cipher->type->description, - session_keys->rtp_auth->type->description, - serv_descr[stream->rtp_services], - session_keys->rtcp_cipher->type->description, - session_keys->rtcp_auth->type->description, - serv_descr[stream->rtcp_services], - srtp_rdbx_get_window_size(&stream->rtp_rdbx), - stream->allow_repeat_tx ? "true" : "false"); - - printf("# Encrypted extension headers: "); - if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) { - int *enc_xtn_hdr = stream->enc_xtn_hdr; - int count = stream->enc_xtn_hdr_count; - while (count > 0) { - printf("%d ", *enc_xtn_hdr); - enc_xtn_hdr++; - count--; - } - printf("\n"); - } else { - printf("none\n"); - } + data.is_template = 1; + srtp_session_print_stream(srtp->stream_template, &data); } /* loop over streams in session, printing the policy of each */ - stream = srtp->stream_list; - while (stream != NULL) { - if (stream->rtp_services > sec_serv_conf_and_auth) { - return srtp_err_status_bad_param; - } - session_keys = &stream->session_keys[0]; - - printf("# SSRC: 0x%08x\r\n" - "# rtp cipher: %s\r\n" - "# rtp auth: %s\r\n" - "# rtp services: %s\r\n" - "# rtcp cipher: %s\r\n" - "# rtcp auth: %s\r\n" - "# rtcp services: %s\r\n" - "# window size: %lu\r\n" - "# tx rtx allowed:%s\r\n", - stream->ssrc, session_keys->rtp_cipher->type->description, - session_keys->rtp_auth->type->description, - serv_descr[stream->rtp_services], - session_keys->rtcp_cipher->type->description, - session_keys->rtcp_auth->type->description, - serv_descr[stream->rtcp_services], - srtp_rdbx_get_window_size(&stream->rtp_rdbx), - stream->allow_repeat_tx ? "true" : "false"); - - printf("# Encrypted extension headers: "); - if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) { - int *enc_xtn_hdr = stream->enc_xtn_hdr; - int count = stream->enc_xtn_hdr_count; - while (count > 0) { - printf("%d ", *enc_xtn_hdr); - enc_xtn_hdr++; - count--; - } - printf("\n"); - } else { - printf("none\n"); - } - - /* advance to next stream in the list */ - stream = stream->next; - } - return srtp_err_status_ok; + data.is_template = 0; + srtp_stream_list_for_each(srtp->stream_list, srtp_session_print_stream, + &data); + + return data.status; } srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy) { srtp_err_status_t status; @@ -1592,25 +1660,54 @@ if ((hdr == NULL) || (pkt_octet_len > MTU)) { return NULL; } /* write packet into string */ - sprintf(packet_string, "(s)rtp packet: {\n" - " version:\t%d\n" - " p:\t\t%d\n" - " x:\t\t%d\n" - " cc:\t\t%d\n" - " m:\t\t%d\n" - " pt:\t\t%x\n" - " seq:\t\t%x\n" - " ts:\t\t%x\n" - " ssrc:\t%x\n" - " data:\t%s\n" - "} (%d octets in total)\n", - hdr->version, hdr->p, hdr->x, hdr->cc, hdr->m, hdr->pt, hdr->seq, - hdr->ts, hdr->ssrc, octet_string_hex_string(data, hex_len), - pkt_octet_len); + snprintf(packet_string, sizeof(packet_string), + "(s)rtp packet: {\n" + " version:\t%d\n" + " p:\t\t%d\n" + " x:\t\t%d\n" + " cc:\t\t%d\n" + " m:\t\t%d\n" + " pt:\t\t%x\n" + " seq:\t\t%x\n" + " ts:\t\t%x\n" + " ssrc:\t%x\n" + " data:\t%s\n" + "} (%d octets in total)\n", + hdr->version, hdr->p, hdr->x, hdr->cc, hdr->m, hdr->pt, hdr->seq, + hdr->ts, hdr->ssrc, octet_string_hex_string(data, hex_len), + pkt_octet_len); + + return packet_string; +} + +char *srtp_rtcp_packet_to_string(srtcp_hdr_t *hdr, int pkt_octet_len) +{ + int octets_in_rtcp_header = 8; + uint8_t *data = ((uint8_t *)hdr) + octets_in_rtcp_header; + int hex_len = pkt_octet_len - octets_in_rtcp_header; + + /* sanity checking */ + if ((hdr == NULL) || (pkt_octet_len > MTU)) { + return NULL; + } + + /* write packet into string */ + snprintf(packet_string, sizeof(packet_string), + "(s)rtcp packet: {\n" + " version:\t%d\n" + " p:\t\t%d\n" + " rc:\t\t%d\n" + " pt:\t\t%x\n" + " len:\t\t%x\n" + " ssrc:\t%x\n" + " data:\t%s\n" + "} (%d octets in total)\n", + hdr->version, hdr->p, hdr->rc, hdr->pt, hdr->len, hdr->ssrc, + octet_string_hex_string(data, hex_len), pkt_octet_len); return packet_string; } /* @@ -1648,11 +1745,11 @@ * srtp_validate() verifies the correctness of libsrtp by comparing * some computed packets against some pre-computed reference values. * These packets were made with the default SRTP policy. */ -srtp_err_status_t srtp_validate() +srtp_err_status_t srtp_validate(void) { // clang-format off uint8_t srtp_plaintext_ref[28] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, @@ -1808,11 +1905,11 @@ * some computed packets against some pre-computed reference values. * These packets were made with a policy that applies null encryption * and HMAC authentication. */ -srtp_err_status_t srtp_validate_null() +srtp_err_status_t srtp_validate_null(void) { // clang-format off uint8_t srtp_plaintext_ref[28] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, @@ -1966,19 +2063,13 @@ #ifdef GCM /* * srtp_validate_gcm() verifies the correctness of libsrtp by comparing * an computed packet against the known ciphertext for the plaintext. */ -srtp_err_status_t srtp_validate_gcm() +srtp_err_status_t srtp_validate_gcm(void) { // clang-format off - unsigned char test_key_gcm[28] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab - }; uint8_t rtp_plaintext_ref[28] = { 0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab @@ -2113,10 +2204,16 @@ status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len); if (status || (len != 24)) { return status; } + debug_print(mod_driver, "srtcp plain:\n %s", + octet_string_hex_string(srtcp_ciphertext, len)); + debug_print(mod_driver, "srtcp plain reference:\n %s", + octet_string_hex_string(rtcp_plaintext_ref, + sizeof(rtcp_plaintext_ref))); + if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) { return srtp_err_status_fail; } status = srtp_dealloc(srtp_snd); @@ -2134,11 +2231,11 @@ #endif /* * Test vectors taken from RFC 6904, Appendix A */ -srtp_err_status_t srtp_validate_encrypted_extensions_headers() +srtp_err_status_t srtp_validate_encrypted_extensions_headers(void) { // clang-format off unsigned char test_key_ext_headers[30] = { 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39, @@ -2257,11 +2354,11 @@ #ifdef GCM /* * Headers of test vectors taken from RFC 6904, Appendix A */ -srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm() +srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm(void) { // clang-format off unsigned char test_key_ext_headers[30] = { 0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39, @@ -2380,11 +2477,11 @@ * srtp_validate_aes_256() verifies the correctness of libsrtp by comparing * some computed packets against some pre-computed reference values. * These packets were made with the AES-CM-256/HMAC-SHA-1-80 policy. */ -srtp_err_status_t srtp_validate_aes_256() +srtp_err_status_t srtp_validate_aes_256(void) { // clang-format off unsigned char aes_256_test_key[46] = { 0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76, 0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29, @@ -2539,11 +2636,11 @@ } return srtp_err_status_ok; } -srtp_err_status_t srtp_test_empty_payload() +srtp_err_status_t srtp_test_empty_payload(void) { srtp_t srtp_snd, srtp_recv; srtp_err_status_t status; int len; srtp_policy_t policy; @@ -2615,11 +2712,11 @@ return srtp_err_status_ok; } #ifdef GCM -srtp_err_status_t srtp_test_empty_payload_gcm() +srtp_err_status_t srtp_test_empty_payload_gcm(void) { srtp_t srtp_snd, srtp_recv; srtp_err_status_t status; int len; srtp_policy_t policy; @@ -2691,11 +2788,11 @@ return srtp_err_status_ok; } #endif // GCM -srtp_err_status_t srtp_test_remove_stream() +srtp_err_status_t srtp_test_remove_stream(void) { srtp_err_status_t status; srtp_policy_t *policy_list, policy; srtp_t session; srtp_stream_t stream; @@ -2804,11 +2901,11 @@ * As stated in https://tools.ietf.org/html/rfc3711#section-3.3.1 * the value of the ROC must not be reset after a rekey, this test * atempts to prove that srtp_update does not reset the ROC. */ -srtp_err_status_t srtp_test_update() +srtp_err_status_t srtp_test_update(void) { srtp_err_status_t status; uint32_t ssrc = 0x12121212; int msg_len_octets = 32; int protected_msg_len_octets; @@ -2821,20 +2918,20 @@ srtp_crypto_policy_set_rtcp_default(&policy.rtcp); policy.deprecated_ekt = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.next = NULL; - policy.ssrc.type = ssrc_any_outbound; policy.key = test_key; /* create a send and recive ctx with defualt profile and test_key */ - status = srtp_create(&srtp_recv, &policy); + policy.ssrc.type = ssrc_any_outbound; + status = srtp_create(&srtp_snd, &policy); if (status) return status; policy.ssrc.type = ssrc_any_inbound; - status = srtp_create(&srtp_snd, &policy); + status = srtp_create(&srtp_recv, &policy); if (status) return status; /* protect and unprotect two msg's that will cause the ROC to be equal to 1 */ @@ -2976,10 +3073,13 @@ srtp_policy_t policy_mki; #ifdef GCM srtp_policy_t policy_aes_gcm; srtp_policy_t policy_aes_gcm_mki; +#else + (void)srtp_send_aes_gcm; + (void)srtp_send_aes_gcm_mki; #endif // GCM memset(&policy, 0, sizeof(policy)); srtp_crypto_policy_set_rtp_default(&policy.rtp); srtp_crypto_policy_set_rtcp_default(&policy.rtcp); @@ -3046,11 +3146,11 @@ #endif // GCM return srtp_err_status_ok; } -srtp_err_status_t srtp_test_protect_trailer_length() +srtp_err_status_t srtp_test_protect_trailer_length(void) { srtp_t srtp_send; srtp_t srtp_send_mki; srtp_t srtp_send_aes_gcm; srtp_t srtp_send_aes_gcm_mki; @@ -3103,11 +3203,11 @@ #endif return srtp_err_status_ok; } -srtp_err_status_t srtp_test_protect_rtcp_trailer_length() +srtp_err_status_t srtp_test_protect_rtcp_trailer_length(void) { srtp_t srtp_send; srtp_t srtp_send_mki; srtp_t srtp_send_aes_gcm; srtp_t srtp_send_aes_gcm_mki; @@ -3161,11 +3261,229 @@ #endif return srtp_err_status_ok; } -srtp_err_status_t srtp_test_get_roc() +srtp_err_status_t srtp_test_out_of_order_after_rollover(void) +{ + srtp_err_status_t status; + + srtp_policy_t sender_policy; + srtp_t sender_session; + + srtp_policy_t receiver_policy; + srtp_t receiver_session; + + const uint32_t num_pkts = 5; + srtp_hdr_t *pkts[5]; + int pkt_len_octets[5]; + + uint32_t i; + uint32_t stream_roc; + + /* Create sender */ + memset(&sender_policy, 0, sizeof(sender_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp); + sender_policy.key = test_key_gcm; +#else + srtp_crypto_policy_set_rtp_default(&sender_policy.rtp); + srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp); + sender_policy.key = test_key; +#endif + sender_policy.ssrc.type = ssrc_specific; + sender_policy.ssrc.value = 0xcafebabe; + sender_policy.window_size = 128; + + status = srtp_create(&sender_session, &sender_policy); + if (status) { + return status; + } + + /* Create the receiver */ + memset(&receiver_policy, 0, sizeof(receiver_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp); + receiver_policy.key = test_key_gcm; +#else + srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp); + srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp); + receiver_policy.key = test_key; +#endif + receiver_policy.ssrc.type = ssrc_specific; + receiver_policy.ssrc.value = sender_policy.ssrc.value; + receiver_policy.window_size = 128; + + status = srtp_create(&receiver_session, &receiver_policy); + if (status) { + return status; + } + + /* 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 0) { + return srtp_err_status_fail; + } + + 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 0) { + return srtp_err_status_fail; + } + + 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + /* 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]); + if (status) { + return status; + } + status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 0) { + return srtp_err_status_fail; + } + + status = srtp_unprotect(receiver_session, pkts[2], &pkt_len_octets[2]); + if (status) { + return status; + } + status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + status = srtp_unprotect(receiver_session, pkts[4], &pkt_len_octets[4]); + if (status) { + return status; + } + status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + status = srtp_unprotect(receiver_session, pkts[3], &pkt_len_octets[3]); + if (status) { + return status; + } + status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + status = srtp_unprotect(receiver_session, pkts[1], &pkt_len_octets[1]); + if (status) { + return status; + } + status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value, + &stream_roc); + if (status) { + return status; + } + if (stream_roc != 1) { + return srtp_err_status_fail; + } + + /* Cleanup */ + status = srtp_dealloc(sender_session); + if (status) { + return status; + } + + status = srtp_dealloc(receiver_session); + if (status) { + return status; + } + + for (i = 0; i < num_pkts; i++) { + free(pkts[i]); + } + + return srtp_err_status_ok; +} + +srtp_err_status_t srtp_test_get_roc(void) { srtp_err_status_t status; srtp_policy_t policy; srtp_t session; srtp_hdr_t *pkt; @@ -3245,33 +3563,42 @@ unsigned char *recv_pkt_2; uint32_t i; uint32_t ts; uint16_t seq; + uint16_t stride; int msg_len_octets = 32; int protected_msg_len_octets_1; int protected_msg_len_octets_2; /* Create sender */ memset(&sender_policy, 0, sizeof(sender_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp); + sender_policy.key = test_key_gcm; +#else srtp_crypto_policy_set_rtp_default(&sender_policy.rtp); srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp); + sender_policy.key = test_key; +#endif sender_policy.ssrc.type = ssrc_specific; sender_policy.ssrc.value = 0xcafebabe; - sender_policy.key = test_key; sender_policy.window_size = 128; status = srtp_create(&sender_session, &sender_policy); if (status) { return status; } /* Create and protect packets */ + i = 0; seq = 0; ts = 0; - for (i = 0; i < packets; i++) { + stride = 0x4000; + while (i < packets) { srtp_hdr_t *tmp_pkt; int tmp_len; tmp_pkt = srtp_create_test_packet_extended( msg_len_octets, sender_policy.ssrc.value, seq, ts, &tmp_len); @@ -3279,11 +3606,16 @@ free(tmp_pkt); if (status) { return status; } - seq++; + while (stride > (packets - i) && stride > 1) { + stride >>= 1; + } + + i += stride; + seq += stride; ts++; } /* Create the first packet to decrypt and test for ROC change */ pkt_1 = srtp_create_test_packet_extended(msg_len_octets, @@ -3305,15 +3637,21 @@ return status; } /* Create the receiver */ memset(&receiver_policy, 0, sizeof(receiver_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp); + receiver_policy.key = test_key_gcm; +#else srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp); srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp); + receiver_policy.key = test_key; +#endif receiver_policy.ssrc.type = ssrc_specific; receiver_policy.ssrc.value = sender_policy.ssrc.value; - receiver_policy.key = test_key; receiver_policy.window_size = 128; status = srtp_create(&receiver_session, &receiver_policy); if (status) { return status; @@ -3391,15 +3729,21 @@ int msg_len_octets = 32; int protected_msg_len_octets; /* Create sender */ memset(&sender_policy, 0, sizeof(sender_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp); + sender_policy.key = test_key_gcm; +#else srtp_crypto_policy_set_rtp_default(&sender_policy.rtp); srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp); + sender_policy.key = test_key; +#endif sender_policy.ssrc.type = ssrc_specific; sender_policy.ssrc.value = 0xcafebabe; - sender_policy.key = test_key; sender_policy.window_size = 128; status = srtp_create(&sender_session, &sender_policy); if (status) { return status; @@ -3422,15 +3766,21 @@ return status; } /* Create the receiver */ memset(&receiver_policy, 0, sizeof(receiver_policy)); +#ifdef GCM + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp); + srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp); + receiver_policy.key = test_key_gcm; +#else srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp); srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp); + receiver_policy.key = test_key; +#endif receiver_policy.ssrc.type = ssrc_specific; receiver_policy.ssrc.value = sender_policy.ssrc.value; - receiver_policy.key = test_key; receiver_policy.window_size = 128; status = srtp_create(&receiver_session, &receiver_policy); if (status) { return status; @@ -3471,11 +3821,11 @@ free(recv_pkt); return srtp_err_status_ok; } -srtp_err_status_t srtp_test_set_receiver_roc() +srtp_err_status_t srtp_test_set_receiver_roc(void) { int packets; uint32_t roc; srtp_err_status_t status; @@ -3527,14 +3877,19 @@ status = test_set_receiver_roc(packets + 60000, roc); if (status) { return status; } + status = test_set_receiver_roc(packets + 65535, roc); + if (status) { + return status; + } + return srtp_err_status_ok; } -srtp_err_status_t srtp_test_set_sender_roc() +srtp_err_status_t srtp_test_set_sender_roc(void) { uint32_t roc; uint16_t seq; srtp_err_status_t status; @@ -3593,10 +3948,17 @@ 0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6, 0xc3, 0x17, 0xf2, 0xda, 0xbe, 0x35, 0x77, 0x93, 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6 }; +unsigned char test_key_gcm[28] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab +}; + unsigned char test_mki_id[TEST_MKI_ID_SIZE] = { 0xe1, 0xf9, 0x7a, 0x0d }; unsigned char test_mki_id_2[TEST_MKI_ID_SIZE] = { @@ -3665,24 +4027,24 @@ }; const srtp_policy_t hmac_only_policy = { { ssrc_any_outbound, 0 }, /* SSRC */ { - SRTP_NULL_CIPHER, /* cipher type */ - 0, /* cipher key length in octets */ - SRTP_HMAC_SHA1, /* authentication func type */ - 20, /* auth key length in octets */ - 4, /* auth tag length in octets */ - sec_serv_auth /* security services flag */ + SRTP_NULL_CIPHER, /* cipher type */ + SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_HMAC_SHA1, /* authentication func type */ + 20, /* auth key length in octets */ + 4, /* auth tag length in octets */ + sec_serv_auth /* security services flag */ }, { - SRTP_NULL_CIPHER, /* cipher type */ - 0, /* cipher key length in octets */ - SRTP_HMAC_SHA1, /* authentication func type */ - 20, /* auth key length in octets */ - 4, /* auth tag length in octets */ - sec_serv_auth /* security services flag */ + SRTP_NULL_CIPHER, /* cipher type */ + SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_HMAC_SHA1, /* authentication func type */ + 20, /* auth key length in octets */ + 4, /* auth tag length in octets */ + sec_serv_auth /* security services flag */ }, NULL, (srtp_master_key_t **)test_keys, 2, /* Number of Master keys associated with the policy */ NULL, /* indicates that EKT is not in use */ @@ -3820,24 +4182,24 @@ #endif const srtp_policy_t null_policy = { { ssrc_any_outbound, 0 }, /* SSRC */ { - SRTP_NULL_CIPHER, /* cipher type */ - 0, /* cipher key length in octets */ - SRTP_NULL_AUTH, /* authentication func type */ - 0, /* auth key length in octets */ - 0, /* auth tag length in octets */ - sec_serv_none /* security services flag */ + SRTP_NULL_CIPHER, /* cipher type */ + SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 0, /* auth tag length in octets */ + sec_serv_none /* security services flag */ }, { - SRTP_NULL_CIPHER, /* cipher type */ - 0, /* cipher key length in octets */ - SRTP_NULL_AUTH, /* authentication func type */ - 0, /* auth key length in octets */ - 0, /* auth tag length in octets */ - sec_serv_none /* security services flag */ + SRTP_NULL_CIPHER, /* cipher type */ + SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_NULL_AUTH, /* authentication func type */ + 0, /* auth key length in octets */ + 0, /* auth tag length in octets */ + sec_serv_none /* security services flag */ }, NULL, (srtp_master_key_t **)test_keys, 2, /* indicates the number of Master keys */ NULL, /* indicates that EKT is not in use */ @@ -3915,10 +4277,42 @@ NULL, /* no encrypted extension headers */ 0, /* list of encrypted extension headers is empty */ NULL }; +const srtp_policy_t aes_256_hmac_32_policy = { + { ssrc_any_outbound, 0 }, /* SSRC */ + { + /* SRTP policy */ + SRTP_AES_ICM_256, /* cipher type */ + SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_HMAC_SHA1, /* authentication func type */ + 20, /* auth key length in octets */ + 4, /* auth tag length in octets */ + sec_serv_conf_and_auth /* security services flag */ + }, + { + /* SRTCP policy */ + SRTP_AES_ICM_256, /* cipher type */ + SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */ + SRTP_HMAC_SHA1, /* authentication func type */ + 20, /* auth key length in octets */ + 10, /* auth tag length in octets. + 80 bits per RFC 3711. */ + sec_serv_conf_and_auth /* security services flag */ + }, + NULL, + (srtp_master_key_t **)test_256_keys, + 2, /* indicates the number of Master keys */ + NULL, /* indicates that EKT is not in use */ + 128, /* replay window size */ + 0, /* retransmission not allowed */ + NULL, /* no encrypted extension headers */ + 0, /* list of encrypted extension headers is empty */ + NULL +}; + char ekt_test_policy = 'x'; const srtp_policy_t hmac_only_with_ekt_policy = { { ssrc_any_outbound, 0 }, /* SSRC */ { @@ -3969,10 +4363,11 @@ &aes256_gcm_8_policy, &aes256_gcm_8_cauth_policy, #endif &null_policy, &aes_256_hmac_policy, + &aes_256_hmac_32_policy, NULL }; // clang-format on // clang-format off @@ -4010,5 +4405,242 @@ 0, /* retransmission not allowed */ NULL, /* no encrypted extension headers */ 0, /* list of encrypted extension headers is empty */ NULL }; + +static srtp_stream_t stream_list_test_create_stream(uint32_t ssrc) +{ + srtp_stream_t stream = malloc(sizeof(srtp_stream_ctx_t)); + stream->ssrc = ssrc; + return stream; +} + +static void stream_list_test_free_stream(srtp_stream_t stream) +{ + free(stream); +} + +int stream_list_test_count_cb(srtp_stream_t stream, void *data) +{ + int *count = (int *)data; + (*count)++; + (void)stream; + return 0; +} + +struct remove_one_data { + uint32_t ssrc; + srtp_stream_list_t list; +}; + +int stream_list_test_remove_one_cb(srtp_stream_t stream, void *data) +{ + struct remove_one_data *d = (struct remove_one_data *)data; + if (stream->ssrc == d->ssrc) { + srtp_stream_list_remove(d->list, stream); + stream_list_test_free_stream(stream); + return 1; + } + return 0; +} + +int stream_list_test_remove_all_cb(srtp_stream_t stream, void *data) +{ + srtp_stream_list_t *list = (srtp_stream_list_t *)data; + srtp_stream_list_remove(*list, stream); + stream_list_test_free_stream(stream); + return 0; +} + +srtp_err_status_t srtp_stream_list_test(void) +{ + srtp_stream_list_t list; + + if (srtp_stream_list_alloc(&list)) { + return srtp_err_status_fail; + } + + /* add 4 streams*/ + if (srtp_stream_list_insert(list, stream_list_test_create_stream(1))) { + return srtp_err_status_fail; + } + if (srtp_stream_list_insert(list, stream_list_test_create_stream(2))) { + return srtp_err_status_fail; + } + if (srtp_stream_list_insert(list, stream_list_test_create_stream(3))) { + return srtp_err_status_fail; + } + if (srtp_stream_list_insert(list, stream_list_test_create_stream(4))) { + return srtp_err_status_fail; + } + + /* find */ + if (srtp_stream_list_get(list, 3) == NULL) { + return srtp_err_status_fail; + } + if (srtp_stream_list_get(list, 1) == NULL) { + return srtp_err_status_fail; + } + if (srtp_stream_list_get(list, 2) == NULL) { + return srtp_err_status_fail; + } + if (srtp_stream_list_get(list, 4) == NULL) { + return srtp_err_status_fail; + } + + /* find not in list */ + if (srtp_stream_list_get(list, 5)) { + return srtp_err_status_fail; + } + + /* for each */ + int count = 0; + srtp_stream_list_for_each(list, stream_list_test_count_cb, &count); + if (count != 4) { + return srtp_err_status_fail; + } + + /* remove */ + srtp_stream_t stream = srtp_stream_list_get(list, 3); + if (stream == NULL) { + return srtp_err_status_fail; + } + srtp_stream_list_remove(list, stream); + stream_list_test_free_stream(stream); + + /* find after remove */ + if (srtp_stream_list_get(list, 3)) { + return srtp_err_status_fail; + } + + /* recount */ + count = 0; + srtp_stream_list_for_each(list, stream_list_test_count_cb, &count); + if (count != 3) { + return srtp_err_status_fail; + } + + /* remove one in for each */ + struct remove_one_data data = { 2, list }; + srtp_stream_list_for_each(list, stream_list_test_remove_one_cb, &data); + + /* find after remove */ + if (srtp_stream_list_get(list, 2)) { + return srtp_err_status_fail; + } + + /* recount */ + count = 0; + srtp_stream_list_for_each(list, stream_list_test_count_cb, &count); + if (count != 2) { + return srtp_err_status_fail; + } + + /* destroy non empty list */ + if (srtp_stream_list_dealloc(list) == srtp_err_status_ok) { + return srtp_err_status_fail; + } + + /* remove all in for each */ + srtp_stream_list_for_each(list, stream_list_test_remove_all_cb, &list); + + /* recount */ + count = 0; + srtp_stream_list_for_each(list, stream_list_test_count_cb, &count); + if (count != 0) { + return srtp_err_status_fail; + } + + /* destroy empty list */ + if (srtp_stream_list_dealloc(list)) { + return srtp_err_status_fail; + } + + return srtp_err_status_ok; +} + +#ifdef SRTP_USE_TEST_STREAM_LIST + +/* + * A srtp_stream_list_ctx_t implementation using a single linked list + * that does not use the internal next / prev fields. + */ + +struct test_list_node { + srtp_stream_t stream; + struct test_list_node *next; +}; +struct srtp_stream_list_ctx_t_ { + struct test_list_node *head; +}; + +srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr) +{ + struct srtp_stream_list_ctx_t_ *l = + malloc(sizeof(struct srtp_stream_list_ctx_t_)); + l->head = NULL; + *list_ptr = l; + return srtp_err_status_ok; +} + +srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list) +{ + struct test_list_node *node = list->head; + if (node) { + return srtp_err_status_fail; + } + free(list); + + return srtp_err_status_ok; +} + +srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list, + srtp_stream_t stream) +{ + struct test_list_node *node = malloc(sizeof(struct test_list_node)); + node->stream = stream; + node->next = list->head; + list->head = node; + + return srtp_err_status_ok; +} + +srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc) +{ + struct test_list_node *node = list->head; + while (node != NULL) { + if (node->stream->ssrc == ssrc) + return node->stream; + node = node->next; + } + return NULL; +} + +void srtp_stream_list_remove(srtp_stream_list_t list, srtp_stream_t stream) +{ + struct test_list_node **node = &(list->head); + while ((*node) != NULL) { + if ((*node)->stream->ssrc == stream->ssrc) { + struct test_list_node *tmp = (*node); + (*node) = tmp->next; + free(tmp); + return; + } + node = &(*node)->next; + } +} + +void srtp_stream_list_for_each(srtp_stream_list_t list, + int (*callback)(srtp_stream_t, void *), + void *data) +{ + struct test_list_node *node = list->head; + while (node != NULL) { + struct test_list_node *tmp = node; + node = node->next; + if (callback(tmp->stream, data)) + break; + } +} + +#endif diff --git a/third_party/libsrtp/src/test/test_srtp.c b/third_party/libsrtp/src/test/test_srtp.c --- a/third_party/libsrtp/src/test/test_srtp.c +++ b/third_party/libsrtp/src/test/test_srtp.c @@ -76,28 +76,27 @@ srtp_calc_aead_iv_srtcp_all_zero_input_yield_zero_output }, { "srtp_calc_aead_iv_srtcp_seq_num_over_0x7FFFFFFF_bad_param()", srtp_calc_aead_iv_srtcp_seq_num_over_0x7FFFFFFF_bad_param }, { "srtp_calc_aead_iv_srtcp_distinct_iv_per_sequence_number()", srtp_calc_aead_iv_srtcp_distinct_iv_per_sequence_number }, - { NULL } /* End of tests */ }; + { 0 } /* End of tests */ }; /* * Implementation. */ -void srtp_calc_aead_iv_srtcp_all_zero_input_yield_zero_output() +void srtp_calc_aead_iv_srtcp_all_zero_input_yield_zero_output(void) { // Preconditions srtp_session_keys_t session_keys; v128_t init_vector; srtcp_hdr_t header; uint32_t sequence_num; // Postconditions srtp_err_status_t status; - const v128_t zero_vector; - memset((v128_t *)&zero_vector, 0, sizeof(v128_t)); + const v128_t zero_vector = { 0 }; // Given memset(&session_keys, 0, sizeof(srtp_session_keys_t)); memset(&init_vector, 0, sizeof(v128_t)); memset(&header, 0, sizeof(srtcp_hdr_t)); @@ -110,11 +109,11 @@ // Then TEST_CHECK(status == srtp_err_status_ok); TEST_CHECK(memcmp(&zero_vector, &init_vector, sizeof(v128_t)) == 0); } -void srtp_calc_aead_iv_srtcp_seq_num_over_0x7FFFFFFF_bad_param() +void srtp_calc_aead_iv_srtcp_seq_num_over_0x7FFFFFFF_bad_param(void) { // Preconditions srtp_session_keys_t session_keys; v128_t init_vector; srtcp_hdr_t header; @@ -142,11 +141,11 @@ * Srtcp IV calculation incorrectly masks high bit of sequence number for * little-endian platforms. * Ensure that for each valid sequence number where the most significant bit is * high that we get an expected and unique IV. */ -void srtp_calc_aead_iv_srtcp_distinct_iv_per_sequence_number() +void srtp_calc_aead_iv_srtcp_distinct_iv_per_sequence_number(void) { #define SAMPLE_COUNT (3) // Preconditions // Test each significant bit high in each full byte. srtp_session_keys_t session_keys; diff --git a/third_party/libsrtp/src/test/ut_sim.c b/third_party/libsrtp/src/test/ut_sim.c --- a/third_party/libsrtp/src/test/ut_sim.c +++ b/third_party/libsrtp/src/test/ut_sim.c @@ -52,10 +52,12 @@ #include "cipher_priv.h" int ut_compar(const void *a, const void *b) { uint8_t r; + (void)a; + (void)b; srtp_cipher_rand_for_tests(&r, sizeof(r)); return r > (UINT8_MAX / 2) ? -1 : 1; } void ut_init(ut_connection *utc) diff --git a/third_party/libsrtp/src/test/util.c b/third_party/libsrtp/src/test/util.c --- a/third_party/libsrtp/src/test/util.c +++ b/third_party/libsrtp/src/test/util.c @@ -99,12 +99,10 @@ case ('F'): return 0xf; default: return -1; /* this flags an error */ } - /* NOTREACHED */ - return -1; /* this keeps compilers from complaining */ } uint8_t nibble_to_hex_char(uint8_t nibble) { char buf[16] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -127,11 +125,11 @@ while (hex_len < len) { tmp = hex_char_to_nibble(hex[0]); if (tmp == -1) { return hex_len; } - x = (tmp << 4); + x = (uint8_t)(tmp << 4); hex_len++; tmp = hex_char_to_nibble(hex[1]); if (tmp == -1) { return hex_len; } @@ -174,11 +172,11 @@ int i; for (i = 0; i < 4; i++) { char *p = strchr(b64chars, in[i]); if (p != NULL) { - sextets[i] = p - b64chars; + sextets[i] = (unsigned char)(p - b64chars); } else { j++; } }