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