Enable MACsec for ethernet features

This page explains how to enable MACsec for ethernet features.

Use MACsec to authenticate and encrypt the ethernet communication used by in-vehicle infotainment (IVI) for different ECU units, protecting the data from tampering, replay, or information disclosure. Do this buy enabling MACsec IEEE 802.11AE for the ethernet network.


To enable MACsec, wpa_supplicant is used as the daemon for handling the MACsec Key Agreement (MKA) handshake. A MACsec HAL is defined for storing the MACsec pre-shared-key, called the connectivity association key (CAK) securely. The MACsec HAL only supports CAK. This vendor-specific MACsec HAL stores the CAK securely in a tamper resistant storage. Provisioning the key depends on the vendor implementation.

MACsec flow

Figure 1 illustrates the MACsec flow on the head unit.

Figure 1: MACsec flow.

Enable MACsec

To provide support for functionalities with the MACsec CAK key, MACsec for ethernet must be explicitly enabled with a vendor-specific MACsec HAL.

To enable the feature, enable wpa_supplicant_macsec and the vendor-specific macsec-service to PRODUCT_PACKAGES and the configuration file for wpa_supplicant_macsec, init rc script to PRODUCT_COPY_FILES.

For example, this [device-product].mk file:


# This is a mock MACsec HAL implementation with keys embedded in it. Replace with vendor specific HAL
PRODUCT_PACKAGES += android.hardware.automotive.macsec-service

# wpa_supplicant build with MACsec support

PRODUCT_PACKAGES += wpa_supplicant_macsec

# configuration file for wpa_supplicant with MACsec

    $(LOCAL_PATH)/wpa_supplicant_macsec.conf:$(TARGET_COPY_OUT_VENDOR)/etc/wpa_supplicant_macsec.conf \

For example, wpa_supplicant_macsec.conf.

# wpa_supplicant_macsec.conf
# Example configuration for MACsec with preshared key
# mka_cak is not actual key but index for MACsec HAL to specify which key to use
# and make_cak must be either 16 digits or 32 digits depends the actually CAK key length.

Sample wpa_supplicant_macsec.conf on eth0. When multiple network interfaces need to be protected by MACsec, you can start multiple services.

# wpa_supplicant_macsec.rc
service wpa_supplicant_macsec /vendor/bin/hw/wpa_supplicant_macsec \
        -dd -i eth0 -Dmacsec_linux -c /vendor/etc/wpa_supplicant_macsec.conf

Start wpa_supplicant_macsec after the ethernet interface is ready. If the system ethernet is not ready, wpa_supplicant immediately returns an error. To avoid race conditions, a wait (default timeout is five (5) seconds) for /sys//class/net/${eth_interface} might be needed.

# init.target.rc
on late-fs
    wait /sys/class/net/eth0
    start wpa_supplicant_macsec

Configure the IP address for the MACsec interface

Configuration of the MACsec interface IP address can be done by the system connectivity manager once zygote starts. Here is an example overlay XML file for connectivity. If the IP address for MACsec interface needs to be ready before zygote starts, a vendor-specific daemon would need to listen for macsec0 interface and configure it instead since the system connectivity manager only starts after zygote starts.

# Example of com.google.android.connectivity.resources overlay config
<?xml version="1.0" encoding="utf-8"?>
<!-- Resources to configure the connectivity module based on each OEM's preference. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <!-- Whether the internal vehicle network should remain active even when no
         apps requested it. -->
    <bool name="config_vehicleInternalNetworkAlwaysRequested">true</bool>
    <string-array translatable="false" name="config_ethernet_interfaces">
        <!-- Not metered, trusted, not vpn, vehicle, not vcn managed, restricted -->
        <item>macsec0;11,14,15,27,28;ip= gateway= dns=,</item>
    <string translatable="false" name="config_ethernet_iface_regex">macsec\\d</string>


The MACsec vendor-specific HAL must implement the following functions to protect the CAK key. All encryption and decryption with the key is done directly without exposing the key to wpa_supplicant.

 * MACSEC pre-shared key plugin for wpa_applicant
 * The goal of this service is to provide function for using the MACSEC CAK
interface IMacsecPSKPlugin {
     * For xTS test only, not called in production
     * @param keyId is key id to add
     * @param CAK, CAK key to set
     * @param CKN, CKN to set
     * @return ICV.
    void addTestKey(in byte[] keyId, in byte[] CAK, in byte[] CKN);

/** * Use ICV key do AES CMAC same as ieee802_1x_icv_aes_cmac in wpa_supplicant * * @param keyId is key id to be used for AES CMAC * @param data * * @return ICV. */ byte[] calcICV(in byte[] keyId, in byte[] data);
/** * KDF with CAK key to generate SAK key same as ieee802_1x_sak_aes_cmac in wpa_supplicant * * @param keyId is key id to be used for KDF * @param seed is key seed (random number) * @param sakLength generated SAK length (16 or 32) * * @return SAK key. */ byte[] generateSAK(in byte[] keyId, in byte[] data, in int sakLength);
/** * Encrypt using KEK key, this is same as aes_wrap with kek.key in wpa_supplicant * which used to wrap a SAK key * * @param keyId is key id to be used for encryption * @param sak is SAK key (16 or 32 bytes) to be wrapped. * * @return wrapped data using KEK key. */ byte[] wrapSAK(in byte[] keyId, in byte[] sak);
/** * Decrypt using KEK key, this is same as aes_unwrap with kek.key in wpa_supplicant * which used to unwrap a SAK key * * @param keyId is key id to be used for decryption * @param sak is wrapped SAK key. * * @return unwrapped data using KEK key. */ byte[] unwrapSAK(in byte[] keyId, in byte[] sak); }

Reference implementation

A reference implementation is provided in hardware/interfaces/macsec/aidl/default, which provides a software implementation of the HAL with keys embedded inside. This implementation provides only a functional reference to the HAL since the keys are not backed by tamper-resistant storage.

Test the MACsec HAL

A MACsec HAL test is provided in hardware/interfaces/automotive/macsec/aidl/vts/functional.

To run the test:

$ atest VtsHalMacsecPskPluginV1Test

This calls addTestKey-- to insert a test key into the HAL and to verify against the expected values for calcIcv, generateSak, wrapSak and unwrapSak.

To confirm MACsec is working, for integration tests, ping between two machines in the MACsec interface:

# ping -I macsec0

To test Cuttlefish with host, echo 8 > /sys/devices/virtual/net/cvd-ebr/bridge/group_fwd_mask in host is needed to allow passthrough the LLDP frames required for MACsec.