Define MACsec HAL and ref impl

Add MACsec HAL interface and reference implementation.
This allow OEM to store MACsec PSK key in secure storage and provide
functions to use that key,

Bug: 254108688
Test: atest VtsHalMacsecPSKPluginV1_0Test
Change-Id: Iecfe4828839a1dab81989bf9b178ae41c6f46b82
This commit is contained in:
Keith Mok 2023-04-12 15:44:32 +00:00
parent 59414af068
commit 690919a58b
15 changed files with 940 additions and 0 deletions

View file

@ -84,6 +84,14 @@
<regex-instance>[a-z]+/[0-9]+</regex-instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.macsec</name>
<version>1</version>
<interface>
<name>IMacsecPskPlugin</name>
<instance>default</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.occupant_awareness</name>
<version>1</version>

1
macsec/OWNERS Normal file
View file

@ -0,0 +1 @@
keithmok@google.com

40
macsec/aidl/Android.bp Normal file
View file

@ -0,0 +1,40 @@
//
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
aidl_interface {
name: "android.hardware.macsec",
vendor_available: true,
srcs: ["android/hardware/macsec/*.aidl"],
stability: "vintf",
host_supported: true,
backend: {
java: {
enabled: false,
},
rust: {
enabled: false,
},
},
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.macsec;
/**
* MACSEC (IEEE 802.1AE) pre-shared key plugin for wpa_supplicant
*
* The goal of this service is to provide function for using the MACSEC CAK
*
*/
@VintfStability
interface IMacsecPskPlugin {
/**
* For xTS test only inject a key to verify implementation correctness, not called in production
*
* @param keyId is key id to add
* @param Connectivity Association Keys (CAK) to set
* @param Connectivity Association Key Name (CKN) to set
*
*/
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, a data pointer to the buffer for calculate the ICV
*
* @return Integrity check value (ICV).
*/
byte[] calcIcv(in byte[] keyId, in byte[] data);
/**
* KDF with CAK key to generate Secure Association Key (SAK)
* same as ieee802_1x_sak_aes_cmac in wpa_supplicant
*
* @param keyId is key id to be used for KDF
* @param data is key seed (random number)
* @param sakLength generated SAK length (16 or 32)
*
* @return Secure Association Key (SAK).
*/
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 the SAK key (16 or 32 bytes) to be wrapped.
*
* @return wrapped data using Key Encrypting Key (KEK).
*/
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);
}

View file

@ -0,0 +1,91 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.macsec;
/**
* MACSEC (IEEE 802.1AE) pre-shared key plugin for wpa_supplicant
*
* The goal of this service is to provide function for using the MACSEC CAK
*
*/
@VintfStability
interface IMacsecPskPlugin {
/**
* For xTS test only inject a key to verify implementation correctness, not called in production
*
* @param keyId is key id to add
* @param Connectivity Association Keys (CAK) to set
* @param Connectivity Association Key Name (CKN) to set
* @throws EX_ILLEGAL_ARGUMENT If CAK size is not 16 or 32 or keyID size not equals to CAK size
*/
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, a data pointer to the buffer for calculate the ICV
*
* @return Integrity check value (ICV).
* @throws EX_ILLEGAL_ARGUMENT If keyId does not exist
*/
byte[] calcIcv(in byte[] keyId, in byte[] data);
/**
* KDF with CAK key to generate Secure Association Key (SAK)
* same as ieee802_1x_sak_aes_cmac in wpa_supplicant
*
* @param keyId is key id to be used for KDF
* @param data is key seed (random number)
* @param sakLength generated SAK length (16 or 32)
*
* @return Secure Association Key (SAK).
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
* - If keyId does not exist
* - sakLength != 16 or 32
* - data length < sakLength
*/
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 the SAK key (16 or 32 bytes) to be wrapped.
*
* @return wrapped data using Key Encrypting Key (KEK).
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
* - If keyId does not exist
* - sak size eqauls to 0 or not multiples of 8
*/
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.
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
* - If keyId does not exist
* - sak size <= 8 or not multiples of 8
*/
byte[] unwrapSak(in byte[] keyId, in byte[] sak);
}

View file

@ -0,0 +1,64 @@
//
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_binary {
name: "android.hardware.macsec-service",
init_rc: ["android.hardware.macsec.rc"],
vendor: true,
relative_install_path: "hw",
srcs: [
"MacsecPskPlugin.cpp",
"service.cpp",
],
shared_libs: [
"android.hardware.macsec-V1-ndk",
"libcrypto",
"libbase",
"libbinder_ndk",
],
vintf_fragments: ["android.hardware.macsec.xml"],
}
cc_fuzz {
name: "android.hardware.macsec@V1-default-service.aidl_fuzzer",
vendor: true,
srcs: [
"MacsecPskPlugin.cpp",
"fuzzer/fuzzer.cpp",
],
shared_libs: [
"android.hardware.macsec-V1-ndk",
"libcrypto",
"liblog",
],
defaults: [
"service_fuzzer_defaults",
],
fuzz_config: {
cc: [
"keithmok@google.com",
],
},
}

View file

@ -0,0 +1,308 @@
/*
* Copyright 2023, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MacsecPskPlugin.h"
#include <openssl/cipher.h>
#include <openssl/mem.h>
#include <android-base/format.h>
#include <android-base/logging.h>
namespace aidl::android::hardware::macsec {
constexpr auto ok = &ndk::ScopedAStatus::ok;
// vendor should hide the key in TEE/TA
// CAK key can be either 16 / 32 bytes
const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34}; // maximum 16 bytes
const std::vector<uint8_t> CAK_ID_2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02};
const std::vector<uint8_t> CAK_KEY_2 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38}; // maximum 16 bytes
static ndk::ScopedAStatus resultToStatus(binder_exception_t res, const std::string& msg = "") {
if (msg.empty()) {
return ndk::ScopedAStatus::fromExceptionCode(res);
}
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(res, msg.c_str());
}
static int omac1_aes(CMAC_CTX* ctx, const uint8_t* data, size_t data_len,
uint8_t* mac /* 16 bytes */) {
size_t outlen;
// Just reuse same key in ctx
if (!CMAC_Reset(ctx)) {
return -1;
}
if (!CMAC_Update(ctx, data, data_len)) {
return -1;
}
if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16) {
return -1;
}
return 0;
}
static void put_be16(uint8_t* addr, uint16_t value) {
*addr++ = value >> 8;
*addr = value & 0xff;
}
/* IEEE Std 802.1X-2010, 6.2.1 KDF */
static int aes_kdf(CMAC_CTX* ctx, const char* label, const uint8_t* context, int ctx_bits,
int ret_bits, uint8_t* ret) {
const int h = 128;
const int r = 8;
int i, n;
int lab_len, ctx_len, ret_len, buf_len;
uint8_t* buf;
lab_len = strlen(label);
ctx_len = (ctx_bits + 7) / 8;
ret_len = ((ret_bits & 0xffff) + 7) / 8;
buf_len = lab_len + ctx_len + 4;
memset(ret, 0, ret_len);
n = (ret_bits + h - 1) / h;
if (n > ((0x1 << r) - 1)) return -1;
buf = (uint8_t*)calloc(1, buf_len);
if (buf == NULL) return -1;
memcpy(buf + 1, label, lab_len);
memcpy(buf + lab_len + 2, context, ctx_len);
put_be16(&buf[buf_len - 2], ret_bits);
for (i = 0; i < n; i++) {
int res;
buf[0] = (uint8_t)(i + 1);
res = omac1_aes(ctx, buf, buf_len, ret);
if (res) {
free(buf);
return -1;
}
ret = ret + h / 8;
}
free(buf);
return 0;
}
MacsecPskPlugin::MacsecPskPlugin() {
// always make sure ckn is 16 bytes, zero padded
CKN_1.resize(16);
CKN_2.resize(16);
addTestKey(CAK_ID_1, CAK_KEY_1, CKN_1);
addTestKey(CAK_ID_2, CAK_KEY_2, CKN_2);
}
MacsecPskPlugin::~MacsecPskPlugin() {
for (auto s : mKeys) {
OPENSSL_cleanse(&s.kekEncCtx, sizeof(AES_KEY));
OPENSSL_cleanse(&s.kekDecCtx, sizeof(AES_KEY));
CMAC_CTX_free(s.ickCtx);
CMAC_CTX_free(s.cakCtx);
}
}
ndk::ScopedAStatus MacsecPskPlugin::addTestKey(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& CAK,
const std::vector<uint8_t>& CKN) {
if (CAK.size() != 16 && CAK.size() != 32) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "CAK length must be 16 or 32 bytes");
}
if (keyId.size() != CAK.size()) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key ID must be same as CAK length");
}
std::vector<uint8_t> ckn;
ckn = CKN;
ckn.resize(16); // make sure it is always zero padded with maximum length of
// 16 bytes
AES_KEY kekEncCtx;
AES_KEY kekDecCtx;
CMAC_CTX* ickCtx;
CMAC_CTX* cakCtx;
// Create the CAK openssl context
cakCtx = CMAC_CTX_new();
CMAC_Init(cakCtx, CAK.data(), CAK.size(),
CAK.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL);
// derive KEK from CAK (ieee802_1x_kek_aes_cmac)
std::vector<uint8_t> kek;
kek.resize(CAK.size());
aes_kdf(cakCtx, "IEEE8021 KEK", (const uint8_t*)ckn.data(), ckn.size() * 8, 8 * kek.size(),
kek.data());
AES_set_encrypt_key(kek.data(), kek.size() << 3, &kekEncCtx);
AES_set_decrypt_key(kek.data(), kek.size() << 3, &kekDecCtx);
// derive ICK from CAK (ieee802_1x_ick_aes_cmac)
std::vector<uint8_t> ick;
ick.resize(CAK.size());
aes_kdf(cakCtx, "IEEE8021 ICK", (const uint8_t*)CKN.data(), CKN.size() * 8, 8 * ick.size(),
ick.data());
ickCtx = CMAC_CTX_new();
CMAC_Init(ickCtx, ick.data(), ick.size(),
ick.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL);
mKeys.push_back({keyId, kekEncCtx, kekDecCtx, ickCtx, cakCtx});
return ok();
}
ndk::ScopedAStatus MacsecPskPlugin::calcIcv(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& data,
std::vector<uint8_t>* out) {
CMAC_CTX* ctx = NULL;
for (auto s : mKeys) {
if (s.keyId == keyId) {
ctx = s.ickCtx;
break;
}
}
if (ctx == NULL) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
}
out->resize(16);
if (omac1_aes(ctx, data.data(), data.size(), out->data()) != 0) {
return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
}
return ok();
}
ndk::ScopedAStatus MacsecPskPlugin::generateSak(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& data,
const int sakLength, std::vector<uint8_t>* out) {
CMAC_CTX* ctx = NULL;
if ((sakLength != 16) && (sakLength != 32)) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid SAK length");
}
if (data.size() < sakLength) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid data length");
}
for (auto s : mKeys) {
if (s.keyId == keyId) {
ctx = s.cakCtx;
break;
}
}
if (ctx == NULL) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
}
out->resize(sakLength);
if (aes_kdf(ctx, "IEEE8021 SAK", data.data(), data.size() * 8, out->size() * 8, out->data()) !=
0) {
return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
}
return ok();
}
ndk::ScopedAStatus MacsecPskPlugin::wrapSak(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& sak,
std::vector<uint8_t>* out) {
if (sak.size() == 0 || sak.size() % 8 != 0) {
return resultToStatus(EX_ILLEGAL_ARGUMENT,
"SAK length not multiple of 8 or greater than 0");
}
AES_KEY* ctx = NULL;
for (auto s : mKeys) {
if (s.keyId == keyId) {
ctx = &s.kekEncCtx;
break;
}
}
if (ctx == NULL) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
}
out->resize(sak.size() + 8);
if (AES_wrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) {
return ok();
}
return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
}
ndk::ScopedAStatus MacsecPskPlugin::unwrapSak(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& sak,
std::vector<uint8_t>* out) {
if (sak.size() <= 8 || sak.size() % 8 != 0) {
return resultToStatus(EX_ILLEGAL_ARGUMENT,
"SAK length not multiple of 8 or greater than 0");
}
AES_KEY* ctx = NULL;
for (auto s : mKeys) {
if (s.keyId == keyId) {
ctx = &s.kekDecCtx;
break;
}
}
if (ctx == NULL) {
return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist");
}
out->resize(sak.size() - 8);
if (AES_unwrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) {
return ok();
}
return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error");
}
} // namespace aidl::android::hardware::macsec

View file

@ -0,0 +1,57 @@
/*
* Copyright 2023, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/macsec/BnMacsecPskPlugin.h>
#include <openssl/aes.h>
#include <openssl/cmac.h>
namespace aidl::android::hardware::macsec {
struct keys {
std::vector<uint8_t> keyId;
AES_KEY kekEncCtx;
AES_KEY kekDecCtx;
CMAC_CTX* ickCtx;
CMAC_CTX* cakCtx;
};
class MacsecPskPlugin : public BnMacsecPskPlugin {
public:
MacsecPskPlugin();
~MacsecPskPlugin();
ndk::ScopedAStatus addTestKey(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& CAK,
const std::vector<uint8_t>& CKN) override;
ndk::ScopedAStatus calcIcv(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& data,
std::vector<uint8_t>* out) override;
ndk::ScopedAStatus generateSak(const std::vector<uint8_t>& keyId,
const std::vector<uint8_t>& data, const int sakLength,
std::vector<uint8_t>* out);
ndk::ScopedAStatus wrapSak(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& sak,
std::vector<uint8_t>* out) override;
ndk::ScopedAStatus unwrapSak(const std::vector<uint8_t>& keyId, const std::vector<uint8_t>& sak,
std::vector<uint8_t>* out) override;
private:
std::vector<struct keys> mKeys;
};
} // namespace aidl::android::hardware::macsec

View file

@ -0,0 +1,3 @@
service android.hardware.macsec /vendor/bin/hw/android.hardware.macsec-service
class early_hal
user nobody

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.macsec</name>
<version>1</version>
<interface>
<name>IMacsecPskPlugin</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fuzzbinder/libbinder_ndk_driver.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "MacsecPskPlugin.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::shared_ptr<aidl::android::hardware::macsec::MacsecPskPlugin> service =
ndk::SharedRefBase::make<aidl::android::hardware::macsec::MacsecPskPlugin>();
android::fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2023, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MacsecPskPlugin.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
namespace android::hardware::macsec {
using namespace std::string_literals;
using ::aidl::android::hardware::macsec::MacsecPskPlugin;
extern "C" int main() {
base::SetDefaultTag("MacsecPskPlugin");
base::SetMinimumLogSeverity(base::VERBOSE);
LOG(VERBOSE) << "Starting up...";
auto service = ndk::SharedRefBase::make<MacsecPskPlugin>();
const auto instance = MacsecPskPlugin::descriptor + "/default"s;
const auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance;
LOG(VERBOSE) << "Started successfully!";
ABinderProcess_joinThreadPool();
LOG(FATAL) << "MacsecPskPlugin exited unexpectedly!";
return EXIT_FAILURE;
}
} // namespace android::hardware::macsec

View file

@ -0,0 +1,48 @@
//
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsHalMacsecPskPluginV1Test",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
cpp_std: "experimental",
srcs: [
"MacsecAidlTest.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
],
static_libs: [
"android.hardware.macsec-V1-ndk",
"libgmock",
],
test_suites: [
"general-tests",
"vts",
],
}

View file

@ -0,0 +1,142 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/macsec/IMacsecPskPlugin.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
using aidl::android::hardware::macsec::IMacsecPskPlugin;
using namespace std::chrono_literals;
using namespace std::string_literals;
const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01};
const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
const std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34}; // maximum 16 bytes
const std::vector<uint8_t> SAK_DATA_1 = {0x31, 0x32, 0x33, 0x34, 0x11, 0x12, 0x12, 0x14,
0x31, 0x32, 0x33, 0x34, 0x11, 0x12, 0x12, 0x14};
const std::vector<uint8_t> SAK_1 = {0x13, 0xD9, 0xEE, 0x5B, 0x26, 0x8B, 0x44, 0xFB,
0x37, 0x63, 0x3D, 0x41, 0xC8, 0xE7, 0x0D, 0x93};
const std::vector<uint8_t> WRAPPED_SAK_1 = {0x3B, 0x39, 0xAB, 0x4C, 0xD8, 0xDA, 0x2E, 0xC5,
0xD1, 0x38, 0x6A, 0x13, 0x9D, 0xE3, 0x78, 0xD9,
0x93, 0xD2, 0xA0, 0x70, 0x88, 0xCB, 0xF5, 0xEC};
const std::vector<uint8_t> DATA_1 = {0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x34, 0x29,
0x51, 0x52, 0x53, 0x54, 0x51, 0x35, 0x54, 0x59};
const std::vector<uint8_t> ICV_1 = {0xDF, 0x54, 0xFF, 0xCD, 0xE0, 0xA9, 0x78, 0x10,
0x6B, 0x7B, 0xD2, 0xBF, 0xEF, 0xD9, 0x0C, 0x81};
const std::vector<uint8_t> CAK_ID_2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02};
const std::vector<uint8_t> CAK_KEY_2 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
const std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38}; // maximum 16 bytes
const std::vector<uint8_t> SAK_DATA_2 = {0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34,
0x31, 0x32, 0x33, 0x34, 0x31, 0x32, 0x33, 0x34};
const std::vector<uint8_t> SAK_2 = {0x39, 0x09, 0x36, 0x60, 0x18, 0x07, 0x2B, 0x5D,
0xF0, 0x81, 0x81, 0x45, 0xCD, 0x71, 0xC6, 0xBA,
0x1D, 0x2B, 0x87, 0xC4, 0xEF, 0x79, 0x68, 0x82,
0x28, 0xD0, 0x25, 0x86, 0xD3, 0x63, 0xFF, 0x89};
const std::vector<uint8_t> WRAPPED_SAK_2 = {
0x2f, 0x6a, 0x22, 0x29, 0x68, 0x0e, 0x6e, 0x35, 0x91, 0x64, 0x05, 0x4a, 0x31, 0x8d,
0x35, 0xea, 0x95, 0x85, 0x40, 0xc6, 0xea, 0x55, 0xe5, 0xc5, 0x68, 0x40, 0xae, 0x4d,
0x6f, 0xeb, 0x73, 0xcd, 0x4e, 0x2a, 0x43, 0xb1, 0xda, 0x49, 0x4f, 0x0a};
const std::vector<uint8_t> DATA_2 = {0x71, 0x82, 0x13, 0x24, 0x31, 0x82, 0xA4, 0x2F,
0x51, 0x52, 0x53, 0x44, 0x21, 0x35, 0x54, 0x59};
const std::vector<uint8_t> ICV_2 = {0x8D, 0xF1, 0x1D, 0x6E, 0xAC, 0x62, 0xC1, 0x2A,
0xE8, 0xF8, 0x4E, 0xB1, 0x00, 0x45, 0x9A, 0xAD};
class MacsecAidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
android::base::SetDefaultTag("MACSEC_HAL_VTS");
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
const auto instance = IMacsecPskPlugin::descriptor + "/default"s;
mMacsecPskPluginService = IMacsecPskPlugin::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
ASSERT_NE(mMacsecPskPluginService, nullptr);
auto aidlStatus = mMacsecPskPluginService->addTestKey(CAK_ID_1, CAK_KEY_1, CKN_1);
ASSERT_TRUE(aidlStatus.isOk());
aidlStatus = mMacsecPskPluginService->addTestKey(CAK_ID_2, CAK_KEY_2, CKN_2);
ASSERT_TRUE(aidlStatus.isOk());
}
virtual void TearDown() override {}
std::shared_ptr<IMacsecPskPlugin> mMacsecPskPluginService;
};
TEST_P(MacsecAidlTest, calcIcv) {
std::vector<uint8_t> out;
auto aidlStatus = mMacsecPskPluginService->calcIcv(CAK_ID_1, DATA_1, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "calcIcv KEY 1 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, ICV_1);
aidlStatus = mMacsecPskPluginService->calcIcv(CAK_ID_2, DATA_2, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "calcIcv KEY 2 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, ICV_2);
}
TEST_P(MacsecAidlTest, generateSak) {
std::vector<uint8_t> out;
auto aidlStatus = mMacsecPskPluginService->generateSak(CAK_ID_1, SAK_DATA_1, 16, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "generateSak KEY 1 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, SAK_1);
aidlStatus = mMacsecPskPluginService->generateSak(CAK_ID_2, SAK_DATA_2, 32, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "generateSak KEY 2 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, SAK_2);
}
TEST_P(MacsecAidlTest, wrapSak) {
std::vector<uint8_t> out;
auto aidlStatus = mMacsecPskPluginService->wrapSak(CAK_ID_1, SAK_1, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "wrapSak KEY 1 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, WRAPPED_SAK_1);
aidlStatus = mMacsecPskPluginService->wrapSak(CAK_ID_2, SAK_2, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "wrapSak KEY 2 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, WRAPPED_SAK_2);
}
TEST_P(MacsecAidlTest, unwrapSak) {
std::vector<uint8_t> out;
auto aidlStatus = mMacsecPskPluginService->unwrapSak(CAK_ID_1, WRAPPED_SAK_1, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "unwrapSak KEY 1 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, SAK_1);
aidlStatus = mMacsecPskPluginService->unwrapSak(CAK_ID_2, WRAPPED_SAK_2, &out);
ASSERT_TRUE(aidlStatus.isOk()) << "unwrapSak KEY 2 failed: " << aidlStatus.getMessage();
EXPECT_EQ(out, SAK_2);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MacsecAidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, MacsecAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IMacsecPskPlugin::descriptor)),
android::PrintInstanceNameToString);

View file

@ -0,0 +1,2 @@
# Bug component: 533426
keithmok@google.com