wifi: implement certificate HAL callback for Trust On First Use support

Bug: 196180536
Test: atest VtsHalWifiSupplicantStaIfaceTargetTest \
            VtsHalWifiSupplicantStaNetworkTargetTest \
            VtsHalWifiSupplicantP2pIfaceTargetTest

Change-Id: Ifdba307dee9003054f897db57a9f207ebc198cb4
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/aidl.cpp
index c3ee8b6..f078e71 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/aidl.cpp
@@ -936,3 +936,28 @@
 
 	aidl_manager->notifyBssFreqChanged(wpa_s);
 }
+
+void wpas_aidl_notify_ceritification(struct wpa_supplicant *wpa_s,
+		int depth, const char *subject,
+		const char *altsubject[],
+		int num_altsubject,
+		const char *cert_hash,
+		const struct wpabuf *cert)
+{
+	if (!wpa_s)
+		return;
+
+	AidlManager *aidl_manager = AidlManager::getInstance();
+	if (!aidl_manager)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Notify certification");
+
+	aidl_manager->notifyCertification(wpa_s,
+			depth,
+			subject,
+			altsubject,
+			num_altsubject,
+			cert_hash,
+			cert);
+}
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/aidl.h
index 8d2807d..71275e3 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/aidl.h
@@ -127,6 +127,12 @@
 		struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, u8 bitmap);
 	void wpas_aidl_notify_network_not_found(struct wpa_supplicant *wpa_s);
 	void wpas_aidl_notify_bss_freq_changed(struct wpa_supplicant *wpa_s);
+	void wpas_aidl_notify_ceritification(struct wpa_supplicant *wpa_s,
+		int depth, const char *subject,
+		const char *altsubject[],
+		int num_altsubject,
+		const char *cert_hash,
+		const struct wpabuf *cert);
 #else   // CONFIG_CTRL_IFACE_AIDL
 static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
 {
@@ -280,6 +286,13 @@
 {}
 void wpas_aidl_notify_bss_freq_changed(struct wpa_supplicant *wpa_s)
 {}
+void wpas_aidl_notify_ceritification(struct wpa_supplicant *wpa_s,
+	int depth, const char *subject,
+	const char *altsubject[],
+	int num_altsubject,
+	const char *cert_hash,
+	const struct wpabuf *cert)
+{}
 #endif  // CONFIG_CTRL_IFACE_AIDL
 
 #ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index b1457b8..780ee92 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -1915,6 +1915,52 @@
 	callWithEachP2pIfaceCallback(misc_utils::charBufToString(wpa_s->ifname), func);
 }
 
+void AidlManager::notifyCertification(struct wpa_supplicant *wpa_s,
+		int depth, const char *subject,
+		const char *altsubject[],
+		int num_altsubject,
+		const char *cert_hash,
+		const struct wpabuf *cert)
+{
+	if (!wpa_s->current_ssid) {
+		wpa_printf(MSG_ERROR, "Current network NULL. Drop Certification event!");
+		return;
+	}
+	struct wpa_ssid *current_ssid = wpa_s->current_ssid;
+	if (NULL == subject || NULL == cert_hash || NULL == cert) {
+		wpa_printf(MSG_ERROR,
+				"Incomplete certificate information. Drop Certification event!");
+		return;
+	}
+	if (!wpa_key_mgmt_wpa_ieee8021x(current_ssid->key_mgmt)) {
+		wpa_printf(MSG_ERROR, "Not 802.1x configuration, Drop Certification event!");
+		return;
+	}
+	if (current_ssid->eap.cert.ca_path || current_ssid->eap.cert.ca_cert) {
+		wpa_printf(MSG_DEBUG, "Already has CA certificate. Drop Certification event!");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "notifyCertification: depth=%d subject=%s hash=%s cert-size=%zu",
+			depth, subject, cert_hash, cert->used);
+	std::vector<uint8_t> subjectBlob(subject, subject + strlen(subject));
+	std::vector<uint8_t> certHashBlob(cert_hash, cert_hash + strlen(cert_hash));
+	std::vector<uint8_t> certBlob(cert->buf, cert->buf + cert->used);
+
+	const std::function<
+		ndk::ScopedAStatus(std::shared_ptr<ISupplicantStaNetworkCallback>)>
+		func = std::bind(
+		&ISupplicantStaNetworkCallback::onServerCertificateAvailable,
+		std::placeholders::_1,
+		depth,
+		subjectBlob,
+		certHashBlob,
+		certBlob);
+
+	callWithEachStaNetworkCallback(
+		misc_utils::charBufToString(wpa_s->ifname), current_ssid->id, func);
+}
+
 /**
  * Retrieve the |ISupplicantP2pIface| aidl object reference using the provided
  * ifname.
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/aidl_manager.h
index 912c817..babb2cc 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/aidl_manager.h
@@ -144,6 +144,12 @@
 			u8 bitmap);
 	void notifyNetworkNotFound(struct wpa_supplicant *wpa_s);
 	void notifyBssFreqChanged(struct wpa_supplicant *wpa_s);
+	void notifyCertification(struct wpa_supplicant *wpa_s,
+			int depth, const char *subject,
+			const char *altsubject[],
+			int num_altsubject,
+			const char *cert_hash,
+			const struct wpabuf *cert);
 
 	// Methods called from aidl objects.
 	void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index 7238267..abde780 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -1688,6 +1688,8 @@
 #endif
 	mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::WFD_R2);
 
+	mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::TRUST_ON_FIRST_USE);
+
 	wpa_printf(MSG_DEBUG, "Driver capability mask: 0x%x", mask);
 
 	return {static_cast<WpaDriverCapabilitiesMask>(mask),
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index a2bd488..aaa2269 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -906,6 +906,10 @@
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_ALT
 			"depth=%d %s", cert->depth, cert->altsubject[i]);
 
+	wpas_aidl_notify_ceritification(wpa_s, cert->depth, cert->subject,
+				       cert->altsubject, cert->num_altsubject,
+				       cert_hash, cert->cert);
+
 	/* notify the new DBus API */
 	wpas_dbus_signal_certification(wpa_s, cert->depth, cert->subject,
 				       cert->altsubject, cert->num_altsubject,