From f2ceb2088cd8241193e575e5a314619310440a92 Mon Sep 17 00:00:00 2001
From: Johan Pascal <johan.pascal@belledonne-communications.com>
Date: Tue, 17 Oct 2023 11:26:45 +0200
Subject: [PATCH] Support for SRTP GCM mode in ZRTP + SRTP AES128-GCM is the
 default mode

---
 coreapi/linphonecore.c                  |  6 ++--
 src/conference/session/audio-stream.cpp | 46 ++++++++++++++++++-------
 tester/call_secure_tester.cpp           | 34 ++++++++++--------
 3 files changed, 56 insertions(+), 30 deletions(-)

diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c
index d9d9c07c76..8dec9570d7 100644
--- a/coreapi/linphonecore.c
+++ b/coreapi/linphonecore.c
@@ -9708,9 +9708,9 @@ void linphone_core_set_srtp_crypto_suites(LinphoneCore *core, const char *suites
 }
 
 const char *linphone_core_get_srtp_crypto_suites(LinphoneCore *core) {
-	return linphone_config_get_string(core->config, "sip", "srtp_crypto_suites",
-	                                  "AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32, AES_256_CM_HMAC_SHA1_80, "
-	                                  "AES_256_CM_HMAC_SHA1_32, AEAD_AES_128_GCM, AEAD_AES_256_GCM");
+	return linphone_config_get_string(
+	    core->config, "sip", "srtp_crypto_suites",
+	    "AEAD_AES_128_GCM, AES_CM_128_HMAC_SHA1_80, AEAD_AES_256_GCM, AES_256_CM_HMAC_SHA1_80");
 }
 
 #ifndef _MSC_VER
diff --git a/src/conference/session/audio-stream.cpp b/src/conference/session/audio-stream.cpp
index ac7aa3dc4a..ad5003f6d1 100644
--- a/src/conference/session/audio-stream.cpp
+++ b/src/conference/session/audio-stream.cpp
@@ -133,42 +133,62 @@ void MS2AudioStream::initZrtp() {
 void MS2AudioStream::setZrtpCryptoTypesParameters(MSZrtpParams *params, bool localIsOfferer) {
 	const MSCryptoSuite *srtpSuites = linphone_core_get_srtp_crypto_suites_array(getCCore());
 	if (srtpSuites) {
+		bool aes1 = false;
+		bool aes3 = false;
+		bool hs32 = false;
+		bool hs80 = false;
+		bool gcm = false;
 		for (int i = 0; (srtpSuites[i] != MS_CRYPTO_SUITE_INVALID) && (i < MS_MAX_ZRTP_CRYPTO_TYPES); i++) {
 			switch (srtpSuites[i]) {
 				case MS_AES_128_SHA1_32:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
-					params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
+					if (!aes1) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					if (!hs32) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
+					aes1 = true;
+					hs32 = true;
 					break;
 				case MS_AES_128_SHA1_80_NO_AUTH:
 				case MS_AES_128_SHA1_32_NO_AUTH:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					if (!aes1) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					aes1 = true;
 					break;
 				case MS_AES_128_SHA1_80_SRTP_NO_CIPHER:
 				case MS_AES_128_SHA1_80_SRTCP_NO_CIPHER:
 				case MS_AES_128_SHA1_80_NO_CIPHER:
-					params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					if (!hs80) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					hs80 = true;
 					break;
 				case MS_AES_128_SHA1_80:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
-					params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					if (!aes1) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					if (!hs80) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					hs80 = true;
+					aes1 = true;
 					break;
 				case MS_AES_CM_256_SHA1_80:
 					lWarning() << "Deprecated crypto suite MS_AES_CM_256_SHA1_80, use MS_AES_256_SHA1_80 instead";
 					BCTBX_NO_BREAK;
 				case MS_AES_256_SHA1_80:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
-					params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					if (!aes3) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
+					if (!hs80) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS80;
+					hs80 = true;
+					aes3 = true;
 					break;
 				case MS_AES_256_SHA1_32:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
-					params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
+					if (!aes3) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
+					if (!hs80) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_HS32;
+					hs32 = true;
+					aes3 = true;
 					break;
-				/* AEAD GCM suite not supported by ZRTP for now, just force the cipher setting according to key size */
 				case MS_AEAD_AES_128_GCM:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					if (!aes1) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES1;
+					if (!gcm) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_GCM;
+					gcm = true;
+					aes1 = true;
 					break;
 				case MS_AEAD_AES_256_GCM:
-					params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
+					if (!aes3) params->ciphers[params->ciphersCount++] = MS_ZRTP_CIPHER_AES3;
+					if (!gcm) params->authTags[params->authTagsCount++] = MS_ZRTP_AUTHTAG_GCM;
+					gcm = true;
+					aes1 = true;
 					break;
 				case MS_CRYPTO_SUITE_INVALID:
 					break;
diff --git a/tester/call_secure_tester.cpp b/tester/call_secure_tester.cpp
index d48861b440..63a4392f8e 100644
--- a/tester/call_secure_tester.cpp
+++ b/tester/call_secure_tester.cpp
@@ -208,8 +208,8 @@ ekt_call(MSEKTCipherType ekt_cipher, MSCryptoSuite crypto_suite, bool unmatching
 	    marie, pauline,
 	    ([marie, pauline, ekt_cipher, crypto_suite, unmatching_ekt, update_ekt](LinphoneCall *marieCall,
 	                                                                            LinphoneCall *paulineCall) {
-		    BC_ASSERT_TRUE(srtp_check_call_stats(marieCall, paulineCall, MS_AES_128_SHA1_80,
-		                                         MSSrtpKeySourceSDES)); // Default crypto suite is MS_AES_128_SHA1_80
+		    BC_ASSERT_TRUE(srtp_check_call_stats(marieCall, paulineCall, MS_AEAD_AES_128_GCM,
+		                                         MSSrtpKeySourceSDES)); // Default crypto suite is MS_AEAD_AES_128_GCM
 
 		    MSEKTParametersSet ekt_params;
 		    generate_ekt(&ekt_params, ekt_cipher, crypto_suite, 0x1234);
@@ -326,8 +326,8 @@ static void srtp_call(void) {
 
 	mgr_calling_each_other(
 	    marie, pauline, ([](LinphoneCall *marieCall, LinphoneCall *paulineCall) {
-		    // Default is MS_AES_128_SHA1_80, we use SDES
-		    BC_ASSERT_TRUE(srtp_check_call_stats(marieCall, paulineCall, MS_AES_128_SHA1_80, MSSrtpKeySourceSDES));
+		    // Default is MS_AES_128_GCM, we use SDES
+		    BC_ASSERT_TRUE(srtp_check_call_stats(marieCall, paulineCall, MS_AEAD_AES_128_GCM, MSSrtpKeySourceSDES));
 	    }));
 
 	// Test differents crypto suites : AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32, AES_256_CM_HMAC_SHA1_80,
@@ -389,7 +389,7 @@ static void srtp_call_with_different_crypto_suite(void) {
 	// same test using mgr_calling_each_other so we can check during the call that the correct suite are used
 	LinphoneCoreManager *marie =
 	    linphone_core_manager_new("marie_rc"); // marie_rc does not specify any srtp crypto suite, propose all
-	                                           // availables, default is AES128_SHA1-80
+	                                           // availables, default is AES128_GCM
 	linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP);
 	LinphoneCoreManager *pauline =
 	    linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc");
@@ -1110,25 +1110,31 @@ static void zrtp_authtag_call(void) {
 	ZrtpAlgoString paulineAlgo;
 	ZrtpAlgoRes res;
 
-	// Default is HS80
+	// Default is GCM
 	//  - this is a linphone internal default setting: SRTP crypto suite default is
-	//      AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32, AES_256_CM_HMAC_SHA1_80, AES_256_CM_HMAC_SHA1_32.
-	//      So the default auth tag set by the audio-stream is HS80, HS32
-	//  - default in bzrtp is HS32, HS80
+	//      AEAD_AES_128_GCM, AES_CM_128_HMAC_SHA1_80, AEAD_AES_256_GCM, AES_256_CM_HMAC_SHA1_80
+	//      So the default auth tag set by the audio-stream is GCM
+	//  - default in bzrtp is GCM, HS32, HS80
 	marieAlgo.auth_tag_algo = NULL;
 	paulineAlgo.auth_tag_algo = NULL;
-	res.auth_tag_algo = {MS_ZRTP_AUTHTAG_HS80};
+	res.auth_tag_algo = {MS_ZRTP_AUTHTAG_GCM};
+	BC_ASSERT_EQUAL(zrtp_params_call(marieAlgo, paulineAlgo, res), 0, int, "%d");
+
+	// Call using GCM
+	marieAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_GCM";
+	paulineAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_GCM";
+	res.auth_tag_algo = {MS_ZRTP_AUTHTAG_GCM};
 	BC_ASSERT_EQUAL(zrtp_params_call(marieAlgo, paulineAlgo, res), 0, int, "%d");
 
 	// Call using HS80
-	marieAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_HS32";
-	paulineAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_HS32";
+	marieAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_GCM";
+	paulineAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_GCM";
 	res.auth_tag_algo = {MS_ZRTP_AUTHTAG_HS80};
 	BC_ASSERT_EQUAL(zrtp_params_call(marieAlgo, paulineAlgo, res), 0, int, "%d");
 
 	// Call using HS32
-	marieAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_HS80";
-	paulineAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_HS80";
+	marieAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_GCM";
+	paulineAlgo.auth_tag_algo = "MS_ZRTP_AUTHTAG_HS32, MS_ZRTP_AUTHTAG_HS80, MS_ZRTP_AUTHTAG_GCM";
 	res.auth_tag_algo = {MS_ZRTP_AUTHTAG_HS32};
 	BC_ASSERT_EQUAL(zrtp_params_call(marieAlgo, paulineAlgo, res), 0, int, "%d");
 
-- 
GitLab