[PATCH] Add media encryption support

David Woodhouse dwmw2 at infradead.org
Wed Mar 11 18:11:03 EDT 2015


From: Jakub Adam <jakub.adam at ktknet.cz>

Part 2 of the outstanding Lync-collab work. This enables SRTP
configuration.

I (dwmw2) have fixed it so it doesn't break the GStreamer 0.10 build,
and tested it with pidgin-sipe against a Lync server.

diff --git a/libpurple/media.c b/libpurple/media.c
index 431ec16..d7ca213 100644
--- a/libpurple/media.c
+++ b/libpurple/media.c
@@ -1256,6 +1256,30 @@ purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMedi
 #endif
 }
 
+void
+purple_media_set_encryption_parameters(PurpleMedia *media, const gchar *sess_id,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	return purple_media_backend_set_encryption_parameters(media->priv->backend,
+			sess_id, cipher, auth, key, key_len);
+#endif
+}
+
+void
+purple_media_set_decryption_parameters(PurpleMedia *media, const gchar *sess_id,
+		const gchar *participant, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len)
+{
+#ifdef USE_VV
+	g_return_if_fail(PURPLE_IS_MEDIA(media));
+	return purple_media_backend_set_decryption_parameters(media->priv->backend,
+			sess_id, participant, cipher, auth, key, key_len);
+#endif
+}
+
 gboolean
 purple_media_codecs_ready(PurpleMedia *media, const gchar *sess_id)
 {
diff --git a/libpurple/media.h b/libpurple/media.h
index 5df1e65..c0a49d8 100644
--- a/libpurple/media.h
+++ b/libpurple/media.h
@@ -360,6 +360,41 @@ gboolean purple_media_candidates_prepared(PurpleMedia *media,
 gboolean purple_media_set_send_codec(PurpleMedia *media, const gchar *sess_id, PurpleMediaCodec *codec);
 
 /**
+ * purple_media_set_encryption_parameters:
+ * @media: The media object to find the session in.
+ * @sess_id: The session id of the session to set parameters of.
+ * @cipher: The cipher to use to encrypt our media in the session.
+ * @auth: The algorithm to use to compute authentication codes for our media
+ *        frames.
+ * @key: The encryption key.
+ * @key_len: Byte length of the encryption key.
+ *
+ * Sets the encryption parameters of our media in the session.
+ */
+void purple_media_set_encryption_parameters(PurpleMedia *media,
+		const gchar *sess_id, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len);
+
+/**
+ * purple_media_set_decryption_parameters:
+ * @media: The media object to find the session in.
+ * @sess_id: The session id of the session to set parameters of.
+ * @participant: The participant of the session to set parameters of.
+ * @cipher: The cipher to use to decrypt media coming from this session's
+ *          participant.
+ * @auth: The algorithm to use for authentication of the media coming from
+ *        the session's participant.
+ * @key: The decryption key.
+ * @key_len: Byte length of the decryption key.
+ *
+ * Sets the decryption parameters for a session participant's media.
+ */
+void purple_media_set_decryption_parameters(PurpleMedia *media,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len);
+
+/**
  * purple_media_codecs_ready:
  * @media: The media object to find the session in.
  * @sess_id: The session id of the session to check.
diff --git a/libpurple/media/backend-fs2.c b/libpurple/media/backend-fs2.c
index b5b3194..47842b5 100644
--- a/libpurple/media/backend-fs2.c
+++ b/libpurple/media/backend-fs2.c
@@ -81,6 +81,13 @@ static GList *purple_media_backend_fs2_get_codecs(PurpleMediaBackend *self,
 static GList *purple_media_backend_fs2_get_local_candidates(
 		PurpleMediaBackend *self,
 		const gchar *sess_id, const gchar *participant);
+static void purple_media_backend_fs2_set_encryption_parameters (
+	PurpleMediaBackend *self, const gchar *sess_id, PurpleMediaCipher cipher,
+	PurpleMediaAuthentication auth, const gchar *key, gsize key_len);
+static void purple_media_backend_fs2_set_decryption_parameters(
+		PurpleMediaBackend *self, const gchar *sess_id,
+		const gchar *participant, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len);
 static gboolean purple_media_backend_fs2_set_remote_codecs(
 		PurpleMediaBackend *self,
 		const gchar *sess_id, const gchar *participant,
@@ -546,6 +553,10 @@ purple_media_backend_iface_init(PurpleMediaBackendIface *iface)
 			purple_media_backend_fs2_get_local_candidates;
 	iface->set_remote_codecs = purple_media_backend_fs2_set_remote_codecs;
 	iface->set_send_codec = purple_media_backend_fs2_set_send_codec;
+	iface->set_encryption_parameters =
+			purple_media_backend_fs2_set_encryption_parameters;
+	iface->set_decryption_parameters =
+			purple_media_backend_fs2_set_decryption_parameters;
 	iface->set_params = purple_media_backend_fs2_set_params;
 	iface->get_available_params = purple_media_backend_fs2_get_available_params;
 	iface->send_dtmf = purple_media_backend_fs2_send_dtmf;
@@ -2472,6 +2483,132 @@ purple_media_backend_fs2_set_remote_codecs(PurpleMediaBackend *self,
 	return TRUE;
 }
 
+#if GST_CHECK_VERSION(1,0,0)
+static GstStructure *
+create_fs2_srtp_structure(PurpleMediaCipher cipher,
+	PurpleMediaAuthentication auth, const gchar *key, gsize key_len)
+{
+	GstStructure *result;
+	GstBuffer *buffer;
+	GstMapInfo info;
+	const gchar *cipher_str;
+	const gchar *auth_str;
+
+	switch (cipher) {
+		case PURPLE_MEDIA_CIPHER_NULL:
+			cipher_str = "null";
+			break;
+		case PURPLE_MEDIA_CIPHER_AES_128_ICM:
+			cipher_str = "aes-128-icm";
+			break;
+		case PURPLE_MEDIA_CIPHER_AES_256_ICM:
+			cipher_str = "aes-256-icm";
+			break;
+		default:
+			purple_debug_error("backend-fs2",
+					"Unknown media cipher (%d)\n", cipher);
+			return NULL;
+	}
+
+	switch (auth) {
+		case PURPLE_MEDIA_AUTHENTICATION_NULL:
+			auth_str = "null";
+			break;
+		case PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_32:
+			auth_str = "hmac-sha1-32";
+			break;
+		case PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_80:
+			auth_str = "hmac-sha1-80";
+			break;
+		default:
+			purple_debug_error("backend-fs2",
+					"Unknown media authentication (%d)\n", auth);
+			g_return_val_if_reached(NULL);
+	}
+
+	buffer = gst_buffer_new_allocate(NULL, key_len, NULL);
+	gst_buffer_map(buffer, &info, GST_MAP_WRITE);
+	memcpy(info.data, key, key_len);
+	gst_buffer_unmap(buffer, &info);
+
+	result = gst_structure_new("FarstreamSRTP",
+			"cipher", G_TYPE_STRING, cipher_str,
+			"auth", G_TYPE_STRING, auth_str,
+			"key", GST_TYPE_BUFFER, buffer,
+			NULL);
+	gst_buffer_unref(buffer);
+
+	return result;
+}
+#endif
+
+static void
+purple_media_backend_fs2_set_encryption_parameters (PurpleMediaBackend *self,
+	const gchar *sess_id, PurpleMediaCipher cipher,
+	PurpleMediaAuthentication auth, const gchar *key, gsize key_len)
+{
+#if !GST_CHECK_VERSION(1,0,0)
+	purple_debug_error("backend-fs2",
+			"Media decryption not supported with GStreamer 0.x\n");
+#else
+	PurpleMediaBackendFs2Session *session;
+	GstStructure *srtp;
+	GError *err = NULL;
+
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
+
+	session = get_session(PURPLE_MEDIA_BACKEND_FS2(self), sess_id);
+	if (!session)
+		return;
+
+	srtp = create_fs2_srtp_structure(cipher, auth, key, key_len);
+	if (!srtp)
+		return;
+
+	if (!fs_session_set_encryption_parameters(session->session, srtp, &err)) {
+		purple_debug_error("backend-fs2",
+				"Error setting encryption parameters: %s\n", err->message);
+		g_error_free(err);
+	}
+
+	gst_structure_free(srtp);
+#endif
+}
+
+static void
+purple_media_backend_fs2_set_decryption_parameters (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len)
+{
+#if !GST_CHECK_VERSION(1,0,0)
+	purple_debug_error("backend-fs2",
+			"Media decryption not supported with GStreamer 0.x\n");
+#else
+	PurpleMediaBackendFs2Stream *stream;
+	GstStructure *srtp;
+	GError *err = NULL;
+
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND_FS2(self));
+	stream = get_stream(PURPLE_MEDIA_BACKEND_FS2(self), sess_id, participant);
+	if (!stream)
+		return;
+
+	srtp = create_fs2_srtp_structure(cipher, auth, key, key_len);
+	if (!srtp)
+		return;
+
+	fs_stream_set_decryption_parameters(stream->stream, srtp, &err);
+	if (err) {
+		purple_debug_error("backend-fs2",
+				"Error setting decryption parameters: %s\n", err->message);
+		g_error_free(err);
+	}
+
+	gst_structure_free(srtp);
+#endif
+}
+
 static gboolean
 purple_media_backend_fs2_set_send_codec(PurpleMediaBackend *self,
 		const gchar *sess_id, PurpleMediaCodec *codec)
diff --git a/libpurple/media/backend-iface.c b/libpurple/media/backend-iface.c
index 618f521..d8a9a17 100644
--- a/libpurple/media/backend-iface.c
+++ b/libpurple/media/backend-iface.c
@@ -190,6 +190,26 @@ purple_media_backend_set_send_codec(PurpleMediaBackend *self,
 			sess_id, codec);
 }
 
+void purple_media_backend_set_encryption_parameters(PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len)
+{
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND(self));
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_encryption_parameters(self,
+			sess_id, cipher, auth, key, key_len);
+}
+
+void
+purple_media_backend_set_decryption_parameters(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len)
+{
+	g_return_if_fail(PURPLE_IS_MEDIA_BACKEND(self));
+	return PURPLE_MEDIA_BACKEND_GET_INTERFACE(self)->set_decryption_parameters(self,
+			sess_id, participant, cipher, auth, key, key_len);
+}
+
 void
 purple_media_backend_set_params(PurpleMediaBackend *self,
 		guint num_params, GParameter *params)
diff --git a/libpurple/media/backend-iface.h b/libpurple/media/backend-iface.h
index 604ad0f..a83dd32 100644
--- a/libpurple/media/backend-iface.h
+++ b/libpurple/media/backend-iface.h
@@ -80,6 +80,13 @@ struct _PurpleMediaBackendIface
 		GList *codecs);
 	gboolean (*set_send_codec) (PurpleMediaBackend *self,
 		const gchar *sess_id, PurpleMediaCodec *codec);
+	void (*set_encryption_parameters) (PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len);
+	void (*set_decryption_parameters) (PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len);
 	void (*set_params) (PurpleMediaBackend *self,
 		guint num_params, GParameter *params);
 	const gchar **(*get_available_params) (void);
@@ -203,6 +210,41 @@ gboolean purple_media_backend_set_send_codec(PurpleMediaBackend *self,
 		const gchar *sess_id, PurpleMediaCodec *codec);
 
 /**
+ * purple_media_backend_set_encryption_parameters:
+ * @self: The media backend the session is in.
+ * @sess_id: The session id of the session to set parameters of.
+ * @cipher: The cipher to use to encrypt our media in the session.
+ * @auth: The algorithm to use to compute authentication codes for our media
+ *        frames.
+ * @key: The encryption key.
+ * @key_len: Byte length of the encryption key.
+ *
+ * Sets the encryption parameters of our media in the session.
+ */
+void purple_media_backend_set_encryption_parameters(PurpleMediaBackend *self,
+		const gchar *sess_id, PurpleMediaCipher cipher,
+		PurpleMediaAuthentication auth, const gchar *key, gsize key_len);
+
+/**
+ * purple_media_backend_set_decryption_parameters:
+ * @self: The media backend the session is in.
+ * @sess_id: The session id of the session to set parameters of.
+ * @participant: The participant of the session to set parameters of.
+ * @cipher: The cipher to use to decrypt media coming from this session's
+ *          participant.
+ * @auth: The algorithm to use for authentication of the media coming from
+ *        the session's participant.
+ * @key: The decryption key.
+ * @key_len: Byte length of the decryption key.
+ *
+ * Sets the decryption parameters for a session participant's media.
+ */
+void purple_media_backend_set_decryption_parameters(PurpleMediaBackend *self,
+		const gchar *sess_id, const gchar *participant,
+		PurpleMediaCipher cipher, PurpleMediaAuthentication auth,
+		const gchar *key, gsize key_len);
+
+/**
  * purple_media_backend_set_params:
  * @self: The media backend to set the parameters on.
  * @num_params: The number of parameters to pass to backend
diff --git a/libpurple/media/enum-types.c b/libpurple/media/enum-types.c
index af6f8ee..f9dd6e0 100644
--- a/libpurple/media/enum-types.c
+++ b/libpurple/media/enum-types.c
@@ -212,3 +212,44 @@ purple_media_state_changed_get_type()
 	return type;
 }
 
+/*
+ * PurpleMediaCipher
+ */
+
+GType
+purple_media_cipher_get_type()
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_CIPHER_NULL,
+				"PURPLE_MEDIA_CIPHER_NULL", "null" },
+			{ PURPLE_MEDIA_CIPHER_AES_128_ICM,
+				"PURPLE_MEDIA_CIPHER_AES_128_ICM", "AES-128-ICM" },
+			{ PURPLE_MEDIA_CIPHER_AES_256_ICM,
+				"PURPLE_MEDIA_CIPHER_AES_256_ICM", "AES-256-ICM" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaCipher", values);
+	}
+	return type;
+}
+
+GType
+purple_media_authentication_get_type(void)
+{
+	static GType type = 0;
+	if (type == 0) {
+		static const GEnumValue values[] = {
+			{ PURPLE_MEDIA_AUTHENTICATION_NULL,
+				"PURPLE_MEDIA_AUTHENTICATION_NULL", "null" },
+			{ PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_32,
+				"PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_32", "HMAC_SHA1_32" },
+			{ PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_80,
+				"PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_80", "HMAC_SHA1_80" },
+			{ 0, NULL, NULL }
+		};
+		type = g_enum_register_static("PurpleMediaAuthentication", values);
+	}
+	return type;
+}
diff --git a/libpurple/media/enum-types.h b/libpurple/media/enum-types.h
index b93e809..851a256 100644
--- a/libpurple/media/enum-types.h
+++ b/libpurple/media/enum-types.h
@@ -135,6 +135,28 @@ typedef enum {
 } PurpleMediaState;
 
 /**
+ * PurpleMediaCipher:
+ *
+ * Media ciphers
+ */
+typedef enum {
+	PURPLE_MEDIA_CIPHER_NULL,
+	PURPLE_MEDIA_CIPHER_AES_128_ICM,
+	PURPLE_MEDIA_CIPHER_AES_256_ICM
+} PurpleMediaCipher;
+
+/**
+ * PurpleMediaAuthentication:
+ *
+ * Media message authentication algorithms
+ */
+typedef enum {
+	PURPLE_MEDIA_AUTHENTICATION_NULL,
+	PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_32,
+	PURPLE_MEDIA_AUTHENTICATION_HMAC_SHA1_80
+} PurpleMediaAuthentication;
+
+/**
  * purple_media_candidate_type_get_type:
  *
  * Gets the media candidate type's GType
@@ -188,6 +210,24 @@ GType purple_media_session_type_get_type(void);
  */
 GType purple_media_state_changed_get_type(void);
 
+/**
+ * purple_media_cipher_get_type:
+ *
+ * Gets the type of the cipher enum
+ *
+ * Returns: The cipher enum's GType
+ */
+GType purple_media_cipher_get_type(void);
+
+/**
+ * purple_media_authentication_get_type:
+ *
+ * Gets the type of the authentication enum
+ *
+ * Returns: The authentication enum's GType
+ */
+GType purple_media_authentication_get_type(void);
+
 G_END_DECLS
 
 #endif  /* _PURPLE_MEDIA_ENUM_TYPES_ */


-- 
dwmw2
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
URL: <https://pidgin.im/pipermail/devel/attachments/20150311/1af30494/attachment.bin>


More information about the Devel mailing list