• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/logging.h>
22 
23 namespace aidl::android::hardware::macsec {
24 
25 constexpr auto ok = &ndk::ScopedAStatus::ok;
26 
27 // vendor should hide the key in TEE/TA
28 // CAK key can be either 16 / 32 bytes
29 const std::vector<uint8_t> CAK_ID_1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30                                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
31 const std::vector<uint8_t> CAK_KEY_1 = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
32                                         0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
33 std::vector<uint8_t> CKN_1 = {0x31, 0x32, 0x33, 0x34};  // maximum 16 bytes
34 
35 const 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};
39 const 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};
43 std::vector<uint8_t> CKN_2 = {0x35, 0x36, 0x37, 0x38};  // maximum 16 bytes
44 
resultToStatus(binder_exception_t res,const std::string & msg="")45 static 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 
omac1_aes(CMAC_CTX * ctx,const uint8_t * data,size_t data_len,uint8_t * mac)52 static 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 
put_be16(uint8_t * addr,uint16_t value)71 static 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 */
aes_kdf(CMAC_CTX * ctx,const char * label,const uint8_t * context,int ctx_bits,int ret_bits,uint8_t * ret)77 static 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 
MacsecPskPlugin()117 MacsecPskPlugin::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 
~MacsecPskPlugin()126 MacsecPskPlugin::~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 
addTestKey(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & CAK,const std::vector<uint8_t> & CKN)135 ndk::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 
calcIcv(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & data,std::vector<uint8_t> * out)189 ndk::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 
generateSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & data,const int sakLength,std::vector<uint8_t> * out)213 ndk::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 
wrapSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & sak,std::vector<uint8_t> * out)247 ndk::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 
unwrapSak(const std::vector<uint8_t> & keyId,const std::vector<uint8_t> & sak,std::vector<uint8_t> * out)277 ndk::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
308