From 86179725ccff702a161361c7e0a4e6702fcda5ed Mon Sep 17 00:00:00 2001 From: Keith Mok Date: Thu, 8 Jun 2023 20:19:25 +0000 Subject: Add a variant of wpa_supplicant to support macsec Add macsec key agreement (MKA) support for AAOS, modify Android.mk to support building a variant of wpa_supplicant (wpa_suppicant_macsec) to support macsec MKA. Add an aidl interface to use macsec PSK protected by vendor HAL process. Bug: 254108688 Bug: 283869440 Test: manual Change-Id: I96d9f1f1b5dad9b4d0000cc065f18f4e2dc9f7a5 --- src/pae/aidl/aidl_psk.cpp | 149 ++++++++++++++++++++++++++++++++++++++++++++++ src/pae/aidl/aidl_psk.h | 33 ++++++++++ src/pae/ieee802_1x_kay.c | 51 ++++++++++++++++ wpa_supplicant/Android.mk | 44 +++++++++++++- 4 files changed, 275 insertions(+), 2 deletions(-) create mode 100644 src/pae/aidl/aidl_psk.cpp create mode 100644 src/pae/aidl/aidl_psk.h diff --git a/src/pae/aidl/aidl_psk.cpp b/src/pae/aidl/aidl_psk.cpp new file mode 100644 index 00000000..67afef0e --- /dev/null +++ b/src/pae/aidl/aidl_psk.cpp @@ -0,0 +1,149 @@ +/* + * WPA Supplicant - Aidl interface to access macsec PSK + * Copyright (c) 2023, Google Inc. All rights reserved. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +extern "C" +{ +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/includes.h" + +#include "aidl_psk.h" +} + +using aidl::android::hardware::macsec::IMacsecPskPlugin; + +static std::shared_ptr pskPlugin; + +int aidl_psk_init() +{ + if (pskPlugin != NULL) { + wpa_printf(MSG_ERROR, "Already connected to Macsec plugin"); + return 0; + } + std::string instanceName = std::string(IMacsecPskPlugin::descriptor) + "/default"; + pskPlugin = IMacsecPskPlugin::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str()))); + + if (pskPlugin == NULL) { + wpa_printf(MSG_ERROR, "Cannot get Macsec PSK plugin service"); + return -ENODEV; + } + + return 0; +} + +int aidl_psk_aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, + u8 *cipher) +{ + if (pskPlugin == NULL) + return -ENODEV; + + n = n * 8; + + const std::vector key_id(kek, kek + kek_len); + const std::vector sak(plain, plain + n); + std::vector out(n + 8); + + auto aidlStatus = pskPlugin->wrapSak(key_id, sak, &out); + if (!aidlStatus.isOk()) { + wpa_printf(MSG_ERROR, "wrapSak return error: %s", aidlStatus.getMessage()); + return -ENODEV; + } + + if (out.size() != (n + 8)) { + wpa_printf(MSG_ERROR, "wrapSak return size not n + 8"); + return -ENODEV; + } + + memcpy(cipher, out.data(), n + 8); + + return 0; +} + +int aidl_psk_aes_unwrap(const u8 *kek, size_t kek_len, int n, + const u8 *cipher, u8 *plain) +{ + if (pskPlugin == NULL) + return -ENODEV; + + n = n * 8; + if (n < 8) + return -ENODEV; + + const std::vector key_id(kek, kek + kek_len); + const std::vector sak(cipher, cipher + n); + std::vector out(n - 8); + + auto aidlStatus = pskPlugin->unwrapSak(key_id, sak, &out); + if (!aidlStatus.isOk()) { + return -ENODEV; + } + + if (out.size() != (n - 8)) { + return -ENODEV; + } + + memcpy(plain, out.data(), n - 8); + + return 0; +} + +int aidl_psk_icv_hash(const u8 *ick, size_t ick_bytes, const u8 *msg, + size_t msg_bytes, u8 *icv) +{ + if (pskPlugin == NULL) { + wpa_printf(MSG_ERROR, "pskPlugin not init"); + return -ENODEV; + } + + const std::vector key_id(ick, ick + ick_bytes); + const std::vector data(msg, msg + msg_bytes); + std::vector out(16); + + auto aidlStatus = pskPlugin->calcIcv(key_id, data, &out); + if (!aidlStatus.isOk()) { + wpa_printf(MSG_ERROR, "calcIcv return error: %s", aidlStatus.getMessage()); + return -ENODEV; + } + + if (out.size() != 16) { + wpa_printf(MSG_ERROR, "calcIcv out size not 16 bytes"); + return -ENODEV; + } + + memcpy(icv, out.data(), 16); + + return 0; +} + +int aidl_psk_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx, + size_t ctx_bytes, u8 *sak, size_t sak_bytes) +{ + if (pskPlugin == NULL) + return -ENODEV; + + const std::vector key_id(cak, cak + cak_bytes); + const std::vector data(ctx, ctx + ctx_bytes); + std::vector out(sak_bytes); + + auto aidlStatus = pskPlugin->generateSak(key_id, data, sak_bytes, &out); + if (!aidlStatus.isOk()) { + return -ENODEV; + } + + if (out.size() != sak_bytes) { + return -ENODEV; + } + + memcpy(sak, out.data(), sak_bytes); + + return 0; +} diff --git a/src/pae/aidl/aidl_psk.h b/src/pae/aidl/aidl_psk.h new file mode 100644 index 00000000..ad131bab --- /dev/null +++ b/src/pae/aidl/aidl_psk.h @@ -0,0 +1,33 @@ +/* + * WPA Supplicant - Aidl interface to access macsec PSK + * Copyright (c) 2023, Google Inc. All rights reserved. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_PAE_AIDL_PSK_H +#define WPA_SUPPLICANT_PAE_AIDL_PSK_H + +#ifdef _cplusplus +extern "C" +{ +#endif // _cplusplus + + /* cak, kek, ick are all reference index only for HAL, not real key, the + * HAL will use the actual key */ + int aidl_psk_init(); + int __must_check aidl_psk_aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, + u8 *cipher); + int __must_check aidl_psk_aes_unwrap(const u8 *kek, size_t kek_len, int n, + const u8 *cipher, u8 *plain); + int aidl_psk_icv_hash(const u8 *ick, size_t ick_bytes, const u8 *msg, + size_t msg_bytes, u8 *icv); + int aidl_psk_sak_aes_cmac(const u8 *cak, size_t cak_bytes, const u8 *ctx, + size_t ctx_bytes, u8 *sak, size_t sak_bytes); + +#ifdef _cplusplus +} +#endif // _cplusplus + +#endif // WPA_SUPPLICANT_PAE_AIDL_PSK_H diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c index 66c65aaf..741b0939 100644 --- a/src/pae/ieee802_1x_kay.c +++ b/src/pae/ieee802_1x_kay.c @@ -22,6 +22,10 @@ #include "ieee802_1x_kay_i.h" #include "ieee802_1x_secy_ops.h" +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS +#include "aidl/aidl_psk.h" +#endif + #define DEFAULT_SA_KEY_LEN 16 #define DEFAULT_ICV_LEN 16 @@ -1659,9 +1663,15 @@ ieee802_1x_mka_encode_dist_sak_body( os_memcpy(body->sak, &cs, CS_ID_LEN); sak_pos = CS_ID_LEN; } +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + if (aidl_psk_aes_wrap(participant->kek.key, participant->kek.len, + cipher_suite_tbl[cs_index].sak_len / 8, + sak->key, body->sak + sak_pos)) { +#else if (aes_wrap(participant->kek.key, participant->kek.len, cipher_suite_tbl[cs_index].sak_len / 8, sak->key, body->sak + sak_pos)) { +#endif wpa_printf(MSG_ERROR, "KaY: AES wrap failed"); return -1; } @@ -1800,8 +1810,13 @@ ieee802_1x_mka_decode_dist_sak_body( wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__); return -1; } +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + if (aidl_psk_aes_unwrap(participant->kek.key, participant->kek.len, + sak_len >> 3, wrap_sak, unwrap_sak)) { +#else if (aes_unwrap(participant->kek.key, participant->kek.len, sak_len >> 3, wrap_sak, unwrap_sak)) { +#endif wpa_printf(MSG_ERROR, "KaY: AES unwrap failed"); os_free(unwrap_sak); return -1; @@ -1896,7 +1911,11 @@ ieee802_1x_mka_encode_icv_body(struct ieee802_1x_mka_participant *participant, set_mka_param_body_len(body, length); } +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + if (aidl_psk_icv_hash( +#else if (mka_alg_tbl[participant->kay->mka_algindex].icv_hash( +#endif participant->ick.key, participant->ick.len, wpabuf_head(buf), wpabuf_len(buf), cmac)) { wpa_printf(MSG_ERROR, "KaY: failed to calculate ICV"); @@ -2198,10 +2217,17 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant) os_memcpy(context + ctx_offset, &kay->dist_kn, sizeof(kay->dist_kn)); if (key_len == 16 || key_len == 32) { +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + if (aidl_psk_sak_aes_cmac(participant->cak.key, + participant->cak.len, + context, ctx_len, + key, key_len)) { +#else if (ieee802_1x_sak_aes_cmac(participant->cak.key, participant->cak.len, context, ctx_len, key, key_len)) { +#endif wpa_printf(MSG_ERROR, "KaY: Failed to generate SAK"); goto fail; } @@ -3183,7 +3209,11 @@ static int ieee802_1x_kay_mkpdu_validity_check(struct ieee802_1x_kay *kay, * packet body length. */ if (len < mka_alg_tbl[kay->mka_algindex].icv_len || +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + aidl_psk_icv_hash( +#else mka_alg_tbl[kay->mka_algindex].icv_hash( +#endif participant->ick.key, participant->ick.len, buf, len - mka_alg_tbl[kay->mka_algindex].icv_len, icv)) { wpa_printf(MSG_ERROR, "KaY: Failed to calculate ICV"); @@ -3745,6 +3775,18 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, wpa_printf(MSG_DEBUG, "KaY: Selected random MI: %s", mi_txt(participant->mi)); +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + if (mode != PSK) { + wpa_printf(MSG_ERROR, "CONFIG_AIDL_MACSEC_PSK_METHODS only support PSK"); + goto fail; + } + wpa_printf(MSG_INFO, "Init macsec PSK HAL"); + if (aidl_psk_init()) { + wpa_printf(MSG_ERROR, "Cannot init aidl macsec psk HAL"); + goto fail; + } +#endif + participant->lrx = false; participant->ltx = false; participant->orx = false; @@ -3763,6 +3805,14 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, if (secy_create_transmit_sc(kay, participant->txsc)) goto fail; +#ifdef CONFIG_AIDL_MACSEC_PSK_METHODS + /* If using external PSK methods, we don't need to generate kek and ick + * key here and cak.key is actually a reference index */ + participant->kek.len = participant->cak.len; + participant->ick.len = participant->cak.len; + memcpy(participant->kek.key, participant->cak.key, participant->cak.len); + memcpy(participant->ick.key, participant->cak.key, participant->cak.len); +#else /* to derive KEK from CAK and CKN */ participant->kek.len = participant->cak.len; if (mka_alg_tbl[kay->mka_algindex].kek_trfm(participant->cak.key, @@ -3790,6 +3840,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, } wpa_hexdump_key(MSG_DEBUG, "KaY: Derived ICK", participant->ick.key, participant->ick.len); +#endif dl_list_add(&kay->participant_list, &participant->list); diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index c3a7bc64..01836114 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -1912,8 +1912,13 @@ LOCAL_C_INCLUDES := $(INCLUDES) include $(BUILD_EXECUTABLE) ######################## +# Build wpa_supplicant +# +# $(1): if defined build wpa_supplicant with macsec support (with different executable name wpa_supplicant_macsec +# +define wpa_supplicant_gen + include $(CLEAR_VARS) -LOCAL_MODULE := wpa_supplicant LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-BSD-3-Clause SPDX-license-identifier-ISC legacy_unencumbered LOCAL_LICENSE_CONDITIONS := notice unencumbered LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../LICENSE @@ -1945,12 +1950,17 @@ else LOCAL_STATIC_LIBRARIES += libnl_2 endif endif -LOCAL_CFLAGS := $(L_CFLAGS) LOCAL_SRC_FILES := $(OBJS) LOCAL_C_INCLUDES := $(INCLUDES) ifeq ($(DBUS), y) LOCAL_SHARED_LIBRARIES += libdbus endif + +ifneq ($(1),) +# wpa_supplicant for wifi +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_MODULE := wpa_supplicant + ifeq ($(WPA_SUPPLICANT_USE_AIDL), y) LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant-V2-ndk LOCAL_SHARED_LIBRARIES += android.system.keystore2-V1-ndk @@ -1962,7 +1972,37 @@ ifeq ($(WIFI_HIDL_UNIFIED_SUPPLICANT_SERVICE_RC_ENTRY), true) LOCAL_INIT_RC=aidl/android.hardware.wifi.supplicant-service.rc endif endif + +else +# wpa_supplicant for macsec +# remove aidl control interface, standalone +LOCAL_CFLAGS := $(patsubst -DCONFIG_CTRL_IFACE_AIDL,,$(patsubst -DCONFIG_AIDL,,$(L_CFLAGS))) +LOCAL_CFLAGS += -DCONFIG_MACSEC -DCONFIG_DRIVER_MACSEC_LINUX +# config macsec to use AIDL interface for CAK key. +LOCAL_CFLAGS += -DCONFIG_AIDL_MACSEC_PSK_METHODS +LOCAL_SRC_FILES += ../src/drivers/driver_macsec_linux.c \ + ../src/drivers/driver_wired_common.c +LOCAL_SRC_FILES += wpas_kay.c \ + src/pae/ieee802_1x_cp.c \ + src/pae/ieee802_1x_kay.c \ + src/pae/ieee802_1x_key.c \ + src/pae/ieee802_1x_secy_ops.c +LOCAL_SRC_FILES += src/pae/aidl/aidl_psk.cpp +LOCAL_SHARED_LIBRARIES += android.hardware.macsec-V1-ndk \ + libbinder_ndk +LOCAL_C_INCLUDES += $(LOCAL_PATH)/aidl + +ifdef CONFIG_AP +LOCAL_SRC_FILES += src/ap/wpa_auth_kay.c +endif +LOCAL_MODULE := wpa_supplicant_macsec +endif + include $(BUILD_EXECUTABLE) +endef + +$(eval $(call wpa_supplicant_gen,)) +$(eval $(call wpa_supplicant_gen, macsec)) ######################## # -- cgit v1.2.3