Bug#994252: Contacts: Retrieve user S/MIME certificate does not work

Roger Meier r.meier at siemens.com
Tue Sep 14 19:08:49 BST 2021


Package: evolution-ews
Version: 3.36.5-0ubuntu1
Severity: normal
Tags: patch

It's currently not possible to retrieve encryption certificates from GAL when
connecting to o365.

upstream:
- issue: https://gitlab.gnome.org/GNOME/evolution-ews/-/issues/3
- patch: https://gitlab.gnome.org/GNOME/evolution-
ews/uploads/ffa7d7a4934cd6bd8b0f44d8c5a47f8f/ews.patch

The patch has not yet been merged upstream due to hard code freeze.

I've back-ported the patch to evolution-ews 3.38 so it could be shipped with
Debian stable. Would be great if you could integrate that and ship it with
latest Debian stable, so people could benefit already today.



-- System Information:
Debian Release: bullseye/sid
  APT prefers focal-updates
  APT policy: (500, 'focal-updates'), (500, 'focal-security'), (500, 'focal'), (100, 'focal-backports')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.4.0-84-generic (SMP w/8 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE=en_US:en (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages evolution-ews depends on:
ii  evolution                3.36.5-0ubuntu1
ii  evolution-data-server    3.36.5-0ubuntu1
ii  libc6                    2.31-0ubuntu9.2
ii  libcamel-1.2-62          3.36.5-0ubuntu1
ii  libebackend-1.2-10       3.36.5-0ubuntu1
ii  libebook-1.2-20          3.36.5-0ubuntu1
ii  libebook-contacts-1.2-3  3.36.5-0ubuntu1
ii  libecal-2.0-1            3.36.5-0ubuntu1
ii  libedata-book-1.2-26     3.36.5-0ubuntu1
ii  libedata-cal-2.0-1       3.36.5-0ubuntu1
ii  libedataserver-1.2-24    3.36.5-0ubuntu1
ii  libedataserverui-1.2-2   3.36.5-0ubuntu1
ii  libevolution             3.36.5-0ubuntu1
ii  libglib2.0-0             2.64.6-1~ubuntu20.04.4
ii  libgtk-3-0               3.24.20-0ubuntu1
ii  libical3                 3.0.8-1
ii  libmspack0               0.10.1-2
ii  libpango-1.0-0           1.44.7-2ubuntu4
ii  libsoup2.4-1             2.70.0-1
ii  libxml2                  2.9.10+dfsg-5ubuntu0.20.04.1

evolution-ews recommends no packages.

evolution-ews suggests no packages.

-- no debconf information
-------------- next part --------------
>From b1ef96f7daee840c4695a3ffccb3ea843cbd8068 Mon Sep 17 00:00:00 2001
From: Roger Meier <r.meier at siemens.com>
Date: Mon, 13 Sep 2021 16:32:02 +0200
Subject: [PATCH] Contacts: Retrieve user S/MIME certificate

see https://gitlab.gnome.org/GNOME/evolution-ews/-/issues/3
---
 src/EWS/addressbook/e-book-backend-ews.c | 335 +++++++++++++++++++++--
 src/EWS/addressbook/ews-oab-decoder.c    |  54 +++-
 src/EWS/common/e-ews-connection.c        |   8 +-
 src/EWS/common/e-ews-item.c              |  65 +++++
 src/EWS/common/e-ews-item.h              |   5 +
 5 files changed, 431 insertions(+), 36 deletions(-)

diff --git a/src/EWS/addressbook/e-book-backend-ews.c b/src/EWS/addressbook/e-book-backend-ews.c
index 197d49fd..9bf75100 100644
--- a/src/EWS/addressbook/e-book-backend-ews.c
+++ b/src/EWS/addressbook/e-book-backend-ews.c
@@ -60,6 +60,10 @@
 #define X_EWS_CHANGEKEY "X-EWS-CHANGEKEY"
 #define X_EWS_GAL_SHA1 "X-EWS-GAL-SHA1"
 #define X_EWS_PHOTO_CHECK_DATE "X-EWS-PHOTO-CHECK-DATE" /* YYYYMMDD of the last check for photo */
+#define X_EWS_CERT_KIND "X-EWS-CERT-KIND"
+
+#define E_EWS_CERT_KIND_USER "UserSMIMECertificate"
+#define E_EWS_CERT_KIND_MSEX "MSExchangeCertificate"
 
 #define EWS_MAX_FETCH_COUNT 500
 
@@ -69,7 +73,19 @@
 /* passing field uris for PhysicalAddress, PhoneNumbers causes error, so we
  * use Default view to fetch them. Thus the summary props just have attachments
  * and some additional properties that are not return with Default view */
-#define CONTACT_ITEM_PROPS "item:Attachments item:HasAttachments item:Body item:LastModifiedTime contacts:Manager contacts:Department contacts:SpouseName contacts:AssistantName contacts:BusinessHomePage contacts:Birthday"
+#define CONTACT_ITEM_PROPS "item:Attachments "\
+			   "item:HasAttachments "\
+			   "item:Body "\
+			   "item:LastModifiedTime "\
+			   "contacts:Manager "\
+			   "contacts:Department "\
+			   "contacts:SpouseName "\
+			   "contacts:AssistantName "\
+			   "contacts:BusinessHomePage "\
+			   "contacts:Birthday"
+#define CONTACT_ITEM_PROPS_10SP2 CONTACT_ITEM_PROPS " "\
+			   "contacts:UserSMIMECertificate "\
+			   "contacts:MSExchangeCertificate"
 
 struct _EBookBackendEwsPrivate {
 	GRecMutex cnc_lock;
@@ -551,6 +567,238 @@ ebews_populate_photo (EBookBackendEws *bbews,
 	e_contact_photo_free (photo);
 }
 
+static void
+ebews_populate_cert (EBookBackendEws *bbews,
+		     EContact *contact,
+		     EEwsItem *item,
+		     const gchar *kind,
+		     GCancellable *cancellable,
+		     GError **error)
+{
+	EVCardAttribute *attr;
+	EContactCert cert;
+
+	g_return_if_fail (g_str_equal (kind, E_EWS_CERT_KIND_USER) || g_str_equal (kind, E_EWS_CERT_KIND_MSEX));
+
+	/* Support for certificates was added in Exchange 2010 SP2. */
+	if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+		return;
+
+	if (g_str_equal (kind, E_EWS_CERT_KIND_USER))
+		cert.data = (gchar *) e_ews_item_get_user_certificate (item, &cert.length);
+	else
+		cert.data = (gchar *) e_ews_item_get_msexchange_certificate (item, &cert.length);
+
+	if (!cert.data || !cert.length)
+		return;
+
+	attr = e_vcard_attribute_new (NULL, EVC_KEY);
+
+	e_vcard_append_attribute (E_VCARD (contact), attr);
+
+	e_vcard_attribute_add_param_with_value (
+		attr,
+		e_vcard_attribute_param_new (EVC_TYPE),
+		"X509");
+
+	e_vcard_attribute_add_param_with_value (
+		attr,
+		e_vcard_attribute_param_new (EVC_ENCODING),
+		"b");
+
+	e_vcard_attribute_add_param_with_value (
+		attr,
+		e_vcard_attribute_param_new (X_EWS_CERT_KIND),
+		kind);
+
+	e_vcard_attribute_add_value_decoded (attr, cert.data, cert.length);
+}
+
+static void
+ebews_populate_user_cert (EBookBackendEws *bbews,
+			  EContact *contact,
+			  EEwsItem *item,
+			  GCancellable *cancellable,
+			  GError **error)
+{
+	ebews_populate_cert (bbews, contact, item, E_EWS_CERT_KIND_USER, cancellable, error);
+}
+
+static void
+ebews_populate_msex_cert (EBookBackendEws *bbews,
+			  EContact *contact,
+			  EEwsItem *item,
+			  GCancellable *cancellable,
+			  GError **error)
+{
+	ebews_populate_cert (bbews, contact, item, E_EWS_CERT_KIND_MSEX, cancellable, error);
+}
+
+static EVCardAttribute *
+ebews_find_cert_attribute (EContact *contact,
+			   const gchar *kind,
+			   gint fallback_index)
+{
+	GList *link;
+	EVCardAttribute *fallback_attr = NULL;
+
+	for (link = e_vcard_get_attributes (E_VCARD (contact)); link; link = g_list_next (link)) {
+		EVCardAttribute *attr = link->data;
+		const gchar *attr_name;
+
+		attr_name = e_vcard_attribute_get_name (attr);
+
+		if (attr_name && g_ascii_strcasecmp (attr_name, EVC_KEY) == 0) {
+			GList *values;
+			gboolean is_x509 = FALSE;
+
+			for (values = e_vcard_attribute_get_param (attr, EVC_TYPE); values && !is_x509; values = g_list_next (values)) {
+				is_x509 = values->data && g_ascii_strcasecmp ((gchar *) values->data, "X509") == 0;
+			}
+
+			if (!is_x509)
+				continue;
+
+			if (!fallback_attr) {
+				if (!fallback_index) {
+					fallback_attr = attr;
+					fallback_index = -1;
+				} else if (fallback_index > 0) {
+					fallback_index--;
+				}
+			}
+
+			for (values = e_vcard_attribute_get_param (attr, X_EWS_CERT_KIND); values; values = g_list_next (values)) {
+				if (values->data && g_ascii_strcasecmp ((gchar *) values->data, kind) == 0)
+					return attr;
+			}
+		}
+	}
+
+	return fallback_attr;
+}
+
+static const gchar *
+ebews_find_cert_base64_data (EContact *contact,
+			     const gchar *kind,
+			     gint fallback_index)
+{
+	EVCardAttribute *attr;
+	GList *values;
+	const gchar *base64_data;
+
+	attr = ebews_find_cert_attribute (contact, kind, fallback_index);
+	if (!attr)
+		return NULL;
+
+	values = e_vcard_attribute_get_values (attr);
+	base64_data = values ? values->data : NULL;
+
+	if (base64_data && *base64_data)
+		return base64_data;
+
+	return NULL;
+}
+
+static void
+ebews_set_cert (EBookBackendEws *bbews,
+		ESoapMessage *message,
+		EContact *contact,
+		const gchar *kind,
+		gint fallback_index)
+{
+	const gchar *base64_data;
+
+	/* Support for certificates was added in Exchange 2010 SP2. */
+	if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+		return;
+
+	base64_data = ebews_find_cert_base64_data (contact, kind, fallback_index);
+	if (!base64_data)
+		return;
+
+	e_soap_message_start_element (message, kind, NULL, NULL);
+	e_ews_message_write_string_parameter (message, "Base64Binary", NULL, base64_data);
+	e_soap_message_end_element (message);
+}
+
+static void
+ebews_set_user_cert (EBookBackendEws *bbews,
+		     ESoapMessage *message,
+		     EContact *contact)
+{
+	ebews_set_cert (bbews, message, contact, E_EWS_CERT_KIND_USER, 0);
+}
+
+
+static void
+ebews_set_msex_cert (EBookBackendEws *bbews,
+		     ESoapMessage *message,
+		     EContact *contact)
+{
+	ebews_set_cert (bbews, message, contact, E_EWS_CERT_KIND_MSEX, 1);
+}
+
+static void
+ebews_set_cert_changes (EBookBackendEws *bbews,
+			ESoapMessage *message,
+			EContact *new,
+			EContact *old,
+			const gchar *kind,
+			gint fallback_index)
+{
+	const gchar *new_base64_data, *old_base64_data;
+
+	/* The first pass */
+	if (!message)
+		return;
+
+	/* Support for certificates was added in Exchange 2010 SP2. */
+	if (!e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+		return;
+
+	/* Intentionally search by kind in the old contact, the new can have added cert, which would not have set the kind yet */
+	new_base64_data = ebews_find_cert_base64_data (new, kind, fallback_index);
+	old_base64_data = ebews_find_cert_base64_data (old, kind, -1);
+
+	if (g_strcmp0 (new_base64_data, old_base64_data) == 0)
+		return;
+
+	if (new_base64_data) {
+		e_ews_message_start_set_item_field (message, kind, "contacts", "Contact");
+		e_soap_message_start_element (message, kind, NULL, NULL);
+		e_ews_message_write_string_parameter (message, "Base64Binary", NULL, new_base64_data);
+		e_soap_message_end_element (message);
+		e_ews_message_end_set_item_field (message);
+	} else {
+		e_ews_message_add_delete_item_field (message, kind, "contacts");
+	}
+}
+
+static void
+ebews_set_user_cert_changes (EBookBackendEws *bbews,
+			     ESoapMessage *message,
+			     EContact *new,
+			     EContact *old,
+			     gchar **out_new_change_key,
+			     GCancellable *cancellable,
+			     GError **error)
+{
+	ebews_set_cert_changes (bbews, message, new, old, E_EWS_CERT_KIND_USER, 0);
+}
+
+static void
+ebews_set_msex_cert_changes (EBookBackendEws *bbews,
+			     ESoapMessage *message,
+			     EContact *new,
+			     EContact *old,
+			     gchar **out_new_change_key,
+			     GCancellable *cancellable,
+			     GError **error)
+{
+	ebews_set_cert_changes (bbews, message, new, old, E_EWS_CERT_KIND_MSEX, 1);
+}
+
 static void
 set_phone_number (EContact *contact,
                   EContactField field,
@@ -716,15 +964,17 @@ ebews_populate_emails (EBookBackendEws *bbews,
 }
 
 static void
-ebews_set_item_id (ESoapMessage *message,
-                   EContact *contact)
+ebews_set_item_id (EBookBackendEws *bbews,
+		   ESoapMessage *message,
+		   EContact *contact)
 {
 
 }
 
 static void
-ebews_set_full_name (ESoapMessage *msg,
-                     EContact *contact)
+ebews_set_full_name (EBookBackendEws *bbews,
+		     ESoapMessage *msg,
+		     EContact *contact)
 {
 	EContactName *name;
 
@@ -765,22 +1015,25 @@ ebews_set_date_value (ESoapMessage *message,
 }
 
 static void
-ebews_set_birth_date (ESoapMessage *message,
-                      EContact *contact)
+ebews_set_birth_date (EBookBackendEws *bbews,
+		      ESoapMessage *message,
+		      EContact *contact)
 {
 	ebews_set_date_value (message, contact, E_CONTACT_BIRTH_DATE, "Birthday");
 }
 
 static void
-ebews_set_anniversary (ESoapMessage *message,
-                       EContact *contact)
+ebews_set_anniversary (EBookBackendEws *bbews,
+		       ESoapMessage *message,
+		       EContact *contact)
 {
 	ebews_set_date_value (message, contact, E_CONTACT_ANNIVERSARY, "WeddingAnniversary");
 }
 
 static void
-ebews_set_photo (ESoapMessage *message,
-                 EContact *contact)
+ebews_set_photo (EBookBackendEws *bbews,
+		 ESoapMessage *message,
+		 EContact *contact)
 {
 
 }
@@ -811,8 +1064,9 @@ add_entry (ESoapMessage *msg,
 }
 
 static void
-ebews_set_phone_numbers (ESoapMessage *msg,
-                         EContact *contact)
+ebews_set_phone_numbers (EBookBackendEws *bbews,
+			 ESoapMessage *msg,
+			 EContact *contact)
 {
 	gint i;
 	const gchar *include_hdr = "PhoneNumbers";
@@ -858,8 +1112,9 @@ add_physical_address (ESoapMessage *msg,
 }
 
 static void
-ebews_set_address (ESoapMessage *msg,
-                   EContact *contact)
+ebews_set_address (EBookBackendEws *bbews,
+		   ESoapMessage *msg,
+		   EContact *contact)
 {
 	gboolean include_hdr = TRUE;
 
@@ -875,15 +1130,17 @@ ebews_set_address (ESoapMessage *msg,
 }
 
 static void
-ebews_set_ims (ESoapMessage *message,
-               EContact *contact)
+ebews_set_ims (EBookBackendEws *bbews,
+	       ESoapMessage *message,
+	       EContact *contact)
 {
 
 }
 
 static void
-ebews_set_notes (ESoapMessage *msg,
-                 EContact *contact)
+ebews_set_notes (EBookBackendEws *bbews,
+		 ESoapMessage *msg,
+		 EContact *contact)
 {
 	gchar *notes = e_contact_get (contact, E_CONTACT_NOTE);
 	if (!notes)
@@ -895,8 +1152,9 @@ ebews_set_notes (ESoapMessage *msg,
 }
 
 static void
-ebews_set_emails (ESoapMessage *msg,
-                  EContact *contact)
+ebews_set_emails (EBookBackendEws *bbews,
+		  ESoapMessage *msg,
+		  EContact *contact)
 {
 	const gchar *include_hdr = "EmailAddresses";
 
@@ -1470,7 +1728,8 @@ ebews_populate_givenname (EBookBackendEws *bbews,
 }
 
 static void
-ebews_set_givenname (ESoapMessage *message,
+ebews_set_givenname (EBookBackendEws *bbews,
+		     ESoapMessage *message,
 		     EContact *contact)
 {
 	/* Does nothing, the "GivenName" is filled by the "FullName" code */
@@ -1507,7 +1766,7 @@ static const struct field_element_mapping {
 	/* set function for simple string type values */
 	const gchar * (*get_simple_prop_func) (EEwsItem *item);
 	void (*populate_contact_func)(EBookBackendEws *bbews, EContact *contact, EEwsItem *item, GCancellable *cancellable, GError **error);
-	void (*set_value_in_soap_message) (ESoapMessage *message, EContact *contact);
+	void (*set_value_in_soap_message) (EBookBackendEws *bbews, ESoapMessage *message, EContact *contact);
 	void (*set_changes) (EBookBackendEws *bbews, ESoapMessage *message, EContact *new, EContact *old, gchar **out_new_change_key, GCancellable *cancellable, GError **error);
 
 } mappings[] = {
@@ -1538,6 +1797,8 @@ static const struct field_element_mapping {
 	{ E_CONTACT_GIVEN_NAME, ELEMENT_TYPE_COMPLEX, "GivenName", NULL, ebews_populate_givenname, ebews_set_givenname, ebews_set_givenname_changes},
 	{ E_CONTACT_ANNIVERSARY, ELEMENT_TYPE_COMPLEX, "WeddingAnniversary", NULL,  ebews_populate_anniversary, ebews_set_anniversary, ebews_set_anniversary_changes },
 	{ E_CONTACT_PHOTO, ELEMENT_TYPE_COMPLEX, "Photo", NULL,  ebews_populate_photo, ebews_set_photo, ebews_set_photo_changes },
+	{ E_CONTACT_X509_CERT, ELEMENT_TYPE_COMPLEX, "UserSMIMECertificate", NULL,  ebews_populate_user_cert, ebews_set_user_cert, ebews_set_user_cert_changes },
+	{ E_CONTACT_X509_CERT, ELEMENT_TYPE_COMPLEX, "MSExchangeCertificate", NULL,  ebews_populate_msex_cert, ebews_set_msex_cert, ebews_set_msex_cert_changes },
 
 	/* Should take of uid and changekey (REV) */
 	{ E_CONTACT_UID, ELEMENT_TYPE_COMPLEX, "ItemId", NULL,  ebews_populate_uid, ebews_set_item_id},
@@ -1578,12 +1839,19 @@ ebb_ews_write_dl_members (ESoapMessage *msg,
 	e_soap_message_end_element (msg); /* Members */
 }
 
+typedef struct _CreateItemsData
+{
+	EBookBackendEws *bbews;
+	EContact *contact;
+} CreateItemsData;
+
 static gboolean
 ebb_ews_convert_dl_to_xml_cb (ESoapMessage *msg,
 			      gpointer user_data,
 			      GError **error)
 {
-	EContact *contact = user_data;
+	CreateItemsData *cid = user_data;
+	EContact *contact = cid->contact;
 	EVCardAttribute *attribute;
 	GList *values;
 
@@ -1606,7 +1874,8 @@ ebb_ews_convert_contact_to_xml_cb (ESoapMessage *msg,
 				   gpointer user_data,
 				   GError **error)
 {
-	EContact *contact = user_data;
+	CreateItemsData *cid = user_data;
+	EContact *contact = cid->contact;
 	gint i, element_type;
 
 	/* Prepare Contact node in the SOAP message */
@@ -1627,7 +1896,7 @@ ebb_ews_convert_contact_to_xml_cb (ESoapMessage *msg,
 				e_ews_message_write_string_parameter (msg, mappings[i].element_name, NULL, val);
 			g_free (val);
 		} else
-			mappings[i].set_value_in_soap_message (msg, contact);
+			mappings[i].set_value_in_soap_message (cid->bbews, msg, contact);
 	}
 
 	/* end of "Contact" */
@@ -2032,7 +2301,11 @@ ebb_ews_fetch_items_sync (EBookBackendEws *bbews,
 	if (contact_item_ids) {
 		EEwsAdditionalProps *add_props;
 		add_props = e_ews_additional_props_new ();
-		add_props->field_uri = g_strdup (CONTACT_ITEM_PROPS);
+
+		if (e_ews_connection_satisfies_server_version (bbews->priv->cnc, E_EWS_EXCHANGE_2010_SP2))
+			add_props->field_uri = g_strdup (CONTACT_ITEM_PROPS_10SP2);
+		else
+			add_props->field_uri = g_strdup (CONTACT_ITEM_PROPS);
 
 		ret = e_ews_connection_get_items_sync (
 			bbews->priv->cnc, EWS_PRIORITY_MEDIUM,
@@ -3730,8 +4003,13 @@ ebb_ews_save_contact_sync (EBookMetaBackend *meta_backend,
 		g_clear_object (&old_contact);
 		g_clear_object (&book_cache);
 	} else {
+		CreateItemsData cid;
+
+		cid.bbews = bbews;
+		cid.contact = contact;
+
 		success = e_ews_connection_create_items_sync (bbews->priv->cnc, EWS_PRIORITY_MEDIUM, NULL, NULL,
-			fid, is_dl ? ebb_ews_convert_dl_to_xml_cb : ebb_ews_convert_contact_to_xml_cb, contact,
+			fid, is_dl ? ebb_ews_convert_dl_to_xml_cb : ebb_ews_convert_contact_to_xml_cb, &cid,
 			&items, cancellable, error);
 	}
 
@@ -3970,6 +4248,7 @@ ebb_ews_get_backend_property (EBookBackend *book_backend,
 			e_contact_field_name (E_CONTACT_BIRTH_DATE),
 			e_contact_field_name (E_CONTACT_NOTE),
 			e_contact_field_name (E_CONTACT_PHOTO),
+			e_contact_field_name (E_CONTACT_X509_CERT),
 			NULL);
 
 		g_string_free (buffer, TRUE);
diff --git a/src/EWS/addressbook/ews-oab-decoder.c b/src/EWS/addressbook/ews-oab-decoder.c
index cc734019..3374440d 100644
--- a/src/EWS/addressbook/ews-oab-decoder.c
+++ b/src/EWS/addressbook/ews-oab-decoder.c
@@ -140,21 +140,61 @@ ews_populate_string_list (EContact *contact,
 }
 
 static void
-ews_populate_cert (EContact *contact,
-                    EContactField field,
-                    gpointer value,
-                    gpointer user_data)
+ews_populate_cert_data (EContact *contact,
+			GBytes *bytes)
 {
-	GSList *list = value;
-	GBytes *bytes = list->data;
 	EContactCert cert;
 
+	if (!bytes || !g_bytes_get_size (bytes))
+		return;
+
 	cert.data = (gpointer) g_bytes_get_data (bytes, &cert.length);
 	cert.length = g_bytes_get_size (bytes);
 
 	e_contact_set (contact, E_CONTACT_X509_CERT, &cert);
 }
 
+static void
+ews_populate_cert (EContact *contact,
+                    EContactField field,
+                    gpointer value,
+                    gpointer user_data)
+{
+	GSList *link;
+
+	for (link = value; link; link = g_slist_next (link)) {
+		GBytes *bytes = link->data;
+
+		ews_populate_cert_data (contact, bytes);
+	}
+}
+
+static void
+ews_populate_user_cert (EContact *contact,
+			EContactField field,
+			gpointer value,
+			gpointer user_data)
+{
+	GBytes *bytes = value;
+
+	ews_populate_cert_data (contact, bytes);
+}
+
+static void
+ews_populate_user_x509_cert (EContact *contact,
+			     EContactField field,
+			     gpointer value,
+			     gpointer user_data)
+{
+	GSList *link;
+
+	for (link = value; link; link = g_slist_next (link)) {
+		GBytes *bytes = link->data;
+
+		ews_populate_cert_data (contact, bytes);
+	}
+}
+
 static void
 ews_populate_photo (EContact *contact,
                     EContactField field,
@@ -243,6 +283,8 @@ static const struct prop_field_mapping {
 	{EWS_PT_THUMBNAIL_PHOTO, E_CONTACT_PHOTO, ews_populate_photo},
 	{EWS_PT_OFFICE_LOCATION, E_CONTACT_OFFICE, ews_populate_simple_string},
 	{EWS_PT_X509_CERT, E_CONTACT_X509_CERT, ews_populate_cert},
+	{EWS_PT_USER_CERTIFICATE, E_CONTACT_X509_CERT, ews_populate_user_cert},
+	{EWS_PT_USER_X509_CERTIFICATE, E_CONTACT_X509_CERT, ews_populate_user_x509_cert},
 	{EWS_PT_SEND_RICH_INFO, E_CONTACT_WANTS_HTML, ews_populate_simple_string},
 };
 
diff --git a/src/EWS/common/e-ews-connection.c b/src/EWS/common/e-ews-connection.c
index 1d318068..933d9237 100644
--- a/src/EWS/common/e-ews-connection.c
+++ b/src/EWS/common/e-ews-connection.c
@@ -6268,10 +6268,14 @@ e_ews_connection_resolve_names (EEwsConnection *cnc,
 
 	e_soap_message_add_attribute (msg, "SearchScope", get_search_scope_str (scope), NULL, NULL);
 
-	if (fetch_contact_data)
+	if (fetch_contact_data) {
 		e_soap_message_add_attribute (msg, "ReturnFullContactData", "true", NULL, NULL);
-	else
+
+		if (e_ews_connection_satisfies_server_version (cnc, E_EWS_EXCHANGE_2010_SP2))
+			e_soap_message_add_attribute (msg, "ContactDataShape", "AllProperties", NULL, NULL);
+	} else {
 		e_soap_message_add_attribute (msg, "ReturnFullContactData", "false", NULL, NULL);
+	}
 
 	if (parent_folder_ids) {
 		e_soap_message_start_element (msg, "ParentFolderIds", "messages", NULL);
diff --git a/src/EWS/common/e-ews-item.c b/src/EWS/common/e-ews-item.c
index 73a82fd4..ce8fa4d3 100644
--- a/src/EWS/common/e-ews-item.c
+++ b/src/EWS/common/e-ews-item.c
@@ -52,6 +52,12 @@ struct _EEwsContactFields {
 	gchar *givenname;
 	gchar *middlename;
 	gchar *notes;
+
+	gsize msexchange_cert_len;
+	guchar *msexchange_cert;
+
+	gsize user_cert_len;
+	guchar *user_cert;
 };
 
 struct _EEwsTaskFields {
@@ -337,6 +343,8 @@ ews_free_contact_fields (struct _EEwsContactFields *con_fields)
 		g_free (con_fields->givenname);
 		g_free (con_fields->middlename);
 		g_free (con_fields->notes);
+		g_free (con_fields->msexchange_cert);
+		g_free (con_fields->user_cert);
 		g_free (con_fields);
 	}
 }
@@ -827,6 +835,37 @@ parse_contact_field (EEwsItem *item,
 		 * with old servers (< 2010_SP2) we prefer use item:Body.
 		 */
 		priv->contact_fields->notes = e_soap_parameter_get_string_value (subparam);
+	} else if (!g_ascii_strcasecmp (name, "UserSMIMECertificate") ||
+		   !g_ascii_strcasecmp (name, "MSExchangeCertificate")) {
+		ESoapParameter *data_param;
+		guchar **out_bytes;
+		gsize *out_len;
+
+		if (!g_ascii_strcasecmp (name, "UserSMIMECertificate")) {
+			out_bytes = &priv->contact_fields->user_cert;
+			out_len = &priv->contact_fields->user_cert_len;
+		} else {
+			out_bytes = &priv->contact_fields->msexchange_cert;
+			out_len = &priv->contact_fields->msexchange_cert_len;
+		}
+
+		data_param = e_soap_parameter_get_first_child_by_name (subparam, "Base64Binary");
+		if (data_param) {
+			gchar *base64_data;
+
+			base64_data = e_soap_parameter_get_string_value (data_param);
+			if (base64_data && *base64_data) {
+				*out_bytes = g_base64_decode_inplace (base64_data, out_len);
+				if (!*out_len) {
+					g_free (*out_bytes);
+
+					*out_len = 0;
+					*out_bytes = NULL;
+				}
+			} else {
+				g_free (base64_data);
+			}
+		}
 	}
 }
 
@@ -2698,6 +2737,32 @@ e_ews_item_get_notes (EEwsItem *item)
 	return item->priv->contact_fields->notes;
 }
 
+const guchar *
+e_ews_item_get_user_certificate (EEwsItem *item,
+				 gsize *out_len)
+{
+	g_return_val_if_fail (E_IS_EWS_ITEM (item), NULL);
+	g_return_val_if_fail (item->priv->contact_fields != NULL, NULL);
+	g_return_val_if_fail (out_len != NULL, NULL);
+
+	*out_len = item->priv->contact_fields->user_cert_len;
+
+	return item->priv->contact_fields->user_cert;
+}
+
+const guchar *
+e_ews_item_get_msexchange_certificate (EEwsItem *item,
+				       gsize *out_len)
+{
+	g_return_val_if_fail (E_IS_EWS_ITEM (item), NULL);
+	g_return_val_if_fail (item->priv->contact_fields != NULL, NULL);
+	g_return_val_if_fail (out_len != NULL, NULL);
+
+	*out_len = item->priv->contact_fields->msexchange_cert_len;
+
+	return item->priv->contact_fields->msexchange_cert;
+}
+
 time_t
 e_ews_item_get_birthday (EEwsItem *item)
 {
diff --git a/src/EWS/common/e-ews-item.h b/src/EWS/common/e-ews-item.h
index fde46528..8a0dbbf5 100644
--- a/src/EWS/common/e-ews-item.h
+++ b/src/EWS/common/e-ews-item.h
@@ -419,6 +419,11 @@ const gchar *	e_ews_item_get_surname		(EEwsItem *item);
 const gchar *	e_ews_item_get_givenname	(EEwsItem *item);
 const gchar *	e_ews_item_get_middlename	(EEwsItem *item);
 const gchar *	e_ews_item_get_notes		(EEwsItem *item);
+const guchar *	e_ews_item_get_user_certificate	(EEwsItem *item,
+						 gsize *out_len);
+const guchar *	e_ews_item_get_msexchange_certificate
+						(EEwsItem *item,
+						 gsize *out_len);
 
 /*Task fields*/
 const gchar *	e_ews_item_get_status		(EEwsItem *item);
-- 
2.25.1



More information about the pkg-gnome-maintainers mailing list