1 /* 2 * Copyright 2023, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "MacsecPskPlugin.h" 18 #include <openssl/cipher.h> 19 #include <openssl/mem.h> 20 21 #include <android-base/format.h> 22 #include <android-base/logging.h> 23 24 namespace aidl::android::hardware::macsec { 25 26 constexpr auto ok = &ndk::ScopedAStatus::ok; 27 28 // vendor should hide the key in TEE/TA 29 // CAK key can be either 16 / 32 bytes 30 const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; 32 const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 33 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; 34 std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34}; // maximum 16 bytes 35 36 const std::vector<uint8_t> CAK_ID_2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}; 40 const std::vector<uint8_t> CAK_KEY_2 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 41 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 42 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 43 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; 44 std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38}; // maximum 16 bytes 45 resultToStatus(binder_exception_t res,const std::string & msg="")46 static ndk::ScopedAStatus resultToStatus(binder_exception_t res, const std::string& msg = "") { 47 if (msg.empty()) { 48 return ndk::ScopedAStatus::fromExceptionCode(res); 49 } 50 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(res, msg.c_str()); 51 } 52 omac1_aes(CMAC_CTX * ctx,const uint8_t * data,size_t data_len,uint8_t * mac)53 static int omac1_aes(CMAC_CTX* ctx, const uint8_t* data, size_t data_len, 54 uint8_t* mac /* 16 bytes */) { 55 size_t outlen; 56 57 // Just reuse same key in ctx 58 if (!CMAC_Reset(ctx)) { 59 return -1; 60 } 61 62 if (!CMAC_Update(ctx, data, data_len)) { 63 return -1; 64 } 65 66 if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16) { 67 return -1; 68 } 69 return 0; 70 } 71 put_be16(uint8_t * addr,uint16_t value)72 static void put_be16(uint8_t* addr, uint16_t value) { 73 *addr++ = value >> 8; 74 *addr = value & 0xff; 75 } 76 77 /* IEEE Std 802.1X-2010, 6.2.1 KDF */ aes_kdf(CMAC_CTX * ctx,const char * label,const uint8_t * context,int ctx_bits,int ret_bits,uint8_t * ret)78 static int aes_kdf(CMAC_CTX* ctx, const char* label, const uint8_t* context, int ctx_bits, 79 int ret_bits, uint8_t* ret) { 80 const int h = 128; 81 const int r = 8; 82 int i, n; 83 int lab_len, ctx_len, ret_len, buf_len; 84 uint8_t* buf; 85 86 lab_len = strlen(label); 87 ctx_len = (ctx_bits + 7) / 8; 88 ret_len = ((ret_bits & 0xffff) + 7) / 8; 89 buf_len = lab_len + ctx_len + 4; 90 91 memset(ret, 0, ret_len); 92 93 n = (ret_bits + h - 1) / h; 94 if (n > ((0x1 << r) - 1)) return -1; 95 96 buf = (uint8_t*)calloc(1, buf_len); 97 if (buf == NULL) return -1; 98 99 memcpy(buf + 1, label, lab_len); 100 memcpy(buf + lab_len + 2, context, ctx_len); 101 put_be16(&buf[buf_len - 2], ret_bits); 102 103 for (i = 0; i < n; i++) { 104 int res; 105 106 buf[0] = (uint8_t)(i + 1); 107 res = omac1_aes(ctx, buf, buf_len, ret); 108 if (res) { 109 free(buf); 110 return -1; 111 } 112 ret = ret + h / 8; 113 } 114 free(buf); 115 return 0; 116 } 117 MacsecPskPlugin()118 MacsecPskPlugin::MacsecPskPlugin() { 119 // always make sure ckn is 16 bytes, zero padded 120 CKN_1.resize(16); 121 CKN_2.resize(16); 122 123 addTestKey(CAK_ID_1, CAK_KEY_1, CKN_1); 124 addTestKey(CAK_ID_2, CAK_KEY_2, CKN_2); 125 } 126 ~MacsecPskPlugin()127 MacsecPskPlugin::~MacsecPskPlugin() { 128 for (auto s : mKeys) { 129 OPENSSL_cleanse(&s.kekEncCtx, sizeof(AES_KEY)); 130 OPENSSL_cleanse(&s.kekDecCtx, sizeof(AES_KEY)); 131 CMAC_CTX_free(s.ickCtx); 132 CMAC_CTX_free(s.cakCtx); 133 } 134 } 135 addTestKey(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & CAK,const std::vector<uint8_t> & CKN)136 ndk::ScopedAStatus MacsecPskPlugin::addTestKey(const std::vector<uint8_t>& keyId, 137 const std::vector<uint8_t>& CAK, 138 const std::vector<uint8_t>& CKN) { 139 if (CAK.size() != 16 && CAK.size() != 32) { 140 return resultToStatus(EX_ILLEGAL_ARGUMENT, "CAK length must be 16 or 32 bytes"); 141 } 142 143 if (keyId.size() != CAK.size()) { 144 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key ID must be same as CAK length"); 145 } 146 147 std::vector<uint8_t> ckn; 148 ckn = CKN; 149 ckn.resize(16); // make sure it is always zero padded with maximum length of 150 // 16 bytes 151 152 AES_KEY kekEncCtx; 153 AES_KEY kekDecCtx; 154 CMAC_CTX* ickCtx; 155 CMAC_CTX* cakCtx; 156 157 // Create the CAK openssl context 158 cakCtx = CMAC_CTX_new(); 159 160 CMAC_Init(cakCtx, CAK.data(), CAK.size(), 161 CAK.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL); 162 163 // derive KEK from CAK (ieee802_1x_kek_aes_cmac) 164 std::vector<uint8_t> kek; 165 kek.resize(CAK.size()); 166 167 aes_kdf(cakCtx, "IEEE8021 KEK", (const uint8_t*)ckn.data(), ckn.size() * 8, 8 * kek.size(), 168 kek.data()); 169 170 AES_set_encrypt_key(kek.data(), kek.size() << 3, &kekEncCtx); 171 AES_set_decrypt_key(kek.data(), kek.size() << 3, &kekDecCtx); 172 173 // derive ICK from CAK (ieee802_1x_ick_aes_cmac) 174 std::vector<uint8_t> ick; 175 ick.resize(CAK.size()); 176 177 aes_kdf(cakCtx, "IEEE8021 ICK", (const uint8_t*)CKN.data(), CKN.size() * 8, 8 * ick.size(), 178 ick.data()); 179 180 ickCtx = CMAC_CTX_new(); 181 182 CMAC_Init(ickCtx, ick.data(), ick.size(), 183 ick.size() == 16 ? EVP_aes_128_cbc() : EVP_aes_256_cbc(), NULL); 184 185 mKeys.push_back({keyId, kekEncCtx, kekDecCtx, ickCtx, cakCtx}); 186 187 return ok(); 188 } 189 calcIcv(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & data,std::vector<uint8_t> * out)190 ndk::ScopedAStatus MacsecPskPlugin::calcIcv(const std::vector<uint8_t>& keyId, 191 const std::vector<uint8_t>& data, 192 std::vector<uint8_t>* out) { 193 CMAC_CTX* ctx = NULL; 194 195 for (auto s : mKeys) { 196 if (s.keyId == keyId) { 197 ctx = s.ickCtx; 198 break; 199 } 200 } 201 202 if (ctx == NULL) { 203 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist"); 204 } 205 206 out->resize(16); 207 if (omac1_aes(ctx, data.data(), data.size(), out->data()) != 0) { 208 return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error"); 209 } 210 211 return ok(); 212 } 213 generateSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & data,const int sakLength,std::vector<uint8_t> * out)214 ndk::ScopedAStatus MacsecPskPlugin::generateSak(const std::vector<uint8_t>& keyId, 215 const std::vector<uint8_t>& data, 216 const int sakLength, std::vector<uint8_t>* out) { 217 CMAC_CTX* ctx = NULL; 218 219 if ((sakLength != 16) && (sakLength != 32)) { 220 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid SAK length"); 221 } 222 223 if (data.size() < sakLength) { 224 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Invalid data length"); 225 } 226 227 for (auto s : mKeys) { 228 if (s.keyId == keyId) { 229 ctx = s.cakCtx; 230 break; 231 } 232 } 233 234 if (ctx == NULL) { 235 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist"); 236 } 237 238 out->resize(sakLength); 239 240 if (aes_kdf(ctx, "IEEE8021 SAK", data.data(), data.size() * 8, out->size() * 8, out->data()) != 241 0) { 242 return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error"); 243 } 244 245 return ok(); 246 } 247 wrapSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & sak,std::vector<uint8_t> * out)248 ndk::ScopedAStatus MacsecPskPlugin::wrapSak(const std::vector<uint8_t>& keyId, 249 const std::vector<uint8_t>& sak, 250 std::vector<uint8_t>* out) { 251 if (sak.size() == 0 || sak.size() % 8 != 0) { 252 return resultToStatus(EX_ILLEGAL_ARGUMENT, 253 "SAK length not multiple of 8 or greater than 0"); 254 } 255 256 AES_KEY* ctx = NULL; 257 258 for (auto s : mKeys) { 259 if (s.keyId == keyId) { 260 ctx = &s.kekEncCtx; 261 break; 262 } 263 } 264 265 if (ctx == NULL) { 266 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist"); 267 } 268 269 out->resize(sak.size() + 8); 270 271 if (AES_wrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) { 272 return ok(); 273 } 274 275 return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error"); 276 } 277 unwrapSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & sak,std::vector<uint8_t> * out)278 ndk::ScopedAStatus MacsecPskPlugin::unwrapSak(const std::vector<uint8_t>& keyId, 279 const std::vector<uint8_t>& sak, 280 std::vector<uint8_t>* out) { 281 if (sak.size() <= 8 || sak.size() % 8 != 0) { 282 return resultToStatus(EX_ILLEGAL_ARGUMENT, 283 "SAK length not multiple of 8 or greater than 0"); 284 } 285 286 AES_KEY* ctx = NULL; 287 288 for (auto s : mKeys) { 289 if (s.keyId == keyId) { 290 ctx = &s.kekDecCtx; 291 break; 292 } 293 } 294 295 if (ctx == NULL) { 296 return resultToStatus(EX_ILLEGAL_ARGUMENT, "Key not exist"); 297 } 298 299 out->resize(sak.size() - 8); 300 301 if (AES_unwrap_key(ctx, NULL, out->data(), sak.data(), sak.size()) > 0) { 302 return ok(); 303 } 304 305 return resultToStatus(EX_SERVICE_SPECIFIC, "Internal error"); 306 } 307 308 } // namespace aidl::android::hardware::macsec 309