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