xref: /aosp_15_r20/hardware/interfaces/macsec/aidl/default/MacsecPskPlugin.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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