1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /*- |
---|
4 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
---|
5 | * All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions |
---|
9 | * are met: |
---|
10 | * 1. Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * |
---|
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
26 | */ |
---|
27 | |
---|
28 | #include <sys/cdefs.h> |
---|
29 | __FBSDID("$FreeBSD$"); |
---|
30 | |
---|
31 | /* |
---|
32 | * IEEE 802.11i AES-CCMP crypto support. |
---|
33 | * |
---|
34 | * Part of this module is derived from similar code in the Host |
---|
35 | * AP driver. The code is used with the consent of the author and |
---|
36 | * it's license is included below. |
---|
37 | */ |
---|
38 | #include <rtems/bsd/local/opt_wlan.h> |
---|
39 | |
---|
40 | #include <rtems/bsd/sys/param.h> |
---|
41 | #include <sys/systm.h> |
---|
42 | #include <sys/mbuf.h> |
---|
43 | #include <sys/malloc.h> |
---|
44 | #include <sys/kernel.h> |
---|
45 | #include <sys/module.h> |
---|
46 | |
---|
47 | #include <sys/socket.h> |
---|
48 | |
---|
49 | #include <net/if.h> |
---|
50 | #include <net/if_media.h> |
---|
51 | #include <net/ethernet.h> |
---|
52 | |
---|
53 | #include <net80211/ieee80211_var.h> |
---|
54 | |
---|
55 | #include <crypto/rijndael/rijndael.h> |
---|
56 | |
---|
57 | #define AES_BLOCK_LEN 16 |
---|
58 | |
---|
59 | struct ccmp_ctx { |
---|
60 | struct ieee80211vap *cc_vap; /* for diagnostics+statistics */ |
---|
61 | struct ieee80211com *cc_ic; |
---|
62 | rijndael_ctx cc_aes; |
---|
63 | }; |
---|
64 | |
---|
65 | static void *ccmp_attach(struct ieee80211vap *, struct ieee80211_key *); |
---|
66 | static void ccmp_detach(struct ieee80211_key *); |
---|
67 | static int ccmp_setkey(struct ieee80211_key *); |
---|
68 | static void ccmp_setiv(struct ieee80211_key *, uint8_t *); |
---|
69 | static int ccmp_encap(struct ieee80211_key *, struct mbuf *); |
---|
70 | static int ccmp_decap(struct ieee80211_key *, struct mbuf *, int); |
---|
71 | static int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int); |
---|
72 | static int ccmp_demic(struct ieee80211_key *, struct mbuf *, int); |
---|
73 | |
---|
74 | static const struct ieee80211_cipher ccmp = { |
---|
75 | .ic_name = "AES-CCM", |
---|
76 | .ic_cipher = IEEE80211_CIPHER_AES_CCM, |
---|
77 | .ic_header = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + |
---|
78 | IEEE80211_WEP_EXTIVLEN, |
---|
79 | .ic_trailer = IEEE80211_WEP_MICLEN, |
---|
80 | .ic_miclen = 0, |
---|
81 | .ic_attach = ccmp_attach, |
---|
82 | .ic_detach = ccmp_detach, |
---|
83 | .ic_setkey = ccmp_setkey, |
---|
84 | .ic_setiv = ccmp_setiv, |
---|
85 | .ic_encap = ccmp_encap, |
---|
86 | .ic_decap = ccmp_decap, |
---|
87 | .ic_enmic = ccmp_enmic, |
---|
88 | .ic_demic = ccmp_demic, |
---|
89 | }; |
---|
90 | |
---|
91 | static int ccmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen); |
---|
92 | static int ccmp_decrypt(struct ieee80211_key *, u_int64_t pn, |
---|
93 | struct mbuf *, int hdrlen); |
---|
94 | |
---|
95 | /* number of references from net80211 layer */ |
---|
96 | static int nrefs = 0; |
---|
97 | |
---|
98 | static void * |
---|
99 | ccmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k) |
---|
100 | { |
---|
101 | struct ccmp_ctx *ctx; |
---|
102 | |
---|
103 | ctx = (struct ccmp_ctx *) IEEE80211_MALLOC(sizeof(struct ccmp_ctx), |
---|
104 | M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); |
---|
105 | if (ctx == NULL) { |
---|
106 | vap->iv_stats.is_crypto_nomem++; |
---|
107 | return NULL; |
---|
108 | } |
---|
109 | ctx->cc_vap = vap; |
---|
110 | ctx->cc_ic = vap->iv_ic; |
---|
111 | nrefs++; /* NB: we assume caller locking */ |
---|
112 | return ctx; |
---|
113 | } |
---|
114 | |
---|
115 | static void |
---|
116 | ccmp_detach(struct ieee80211_key *k) |
---|
117 | { |
---|
118 | struct ccmp_ctx *ctx = k->wk_private; |
---|
119 | |
---|
120 | IEEE80211_FREE(ctx, M_80211_CRYPTO); |
---|
121 | KASSERT(nrefs > 0, ("imbalanced attach/detach")); |
---|
122 | nrefs--; /* NB: we assume caller locking */ |
---|
123 | } |
---|
124 | |
---|
125 | static int |
---|
126 | ccmp_setkey(struct ieee80211_key *k) |
---|
127 | { |
---|
128 | struct ccmp_ctx *ctx = k->wk_private; |
---|
129 | |
---|
130 | if (k->wk_keylen != (128/NBBY)) { |
---|
131 | IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO, |
---|
132 | "%s: Invalid key length %u, expecting %u\n", |
---|
133 | __func__, k->wk_keylen, 128/NBBY); |
---|
134 | return 0; |
---|
135 | } |
---|
136 | if (k->wk_flags & IEEE80211_KEY_SWENCRYPT) |
---|
137 | rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY); |
---|
138 | return 1; |
---|
139 | } |
---|
140 | |
---|
141 | static void |
---|
142 | ccmp_setiv(struct ieee80211_key *k, uint8_t *ivp) |
---|
143 | { |
---|
144 | struct ccmp_ctx *ctx = k->wk_private; |
---|
145 | struct ieee80211vap *vap = ctx->cc_vap; |
---|
146 | uint8_t keyid; |
---|
147 | |
---|
148 | keyid = ieee80211_crypto_get_keyid(vap, k) << 6; |
---|
149 | |
---|
150 | k->wk_keytsc++; |
---|
151 | ivp[0] = k->wk_keytsc >> 0; /* PN0 */ |
---|
152 | ivp[1] = k->wk_keytsc >> 8; /* PN1 */ |
---|
153 | ivp[2] = 0; /* Reserved */ |
---|
154 | ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */ |
---|
155 | ivp[4] = k->wk_keytsc >> 16; /* PN2 */ |
---|
156 | ivp[5] = k->wk_keytsc >> 24; /* PN3 */ |
---|
157 | ivp[6] = k->wk_keytsc >> 32; /* PN4 */ |
---|
158 | ivp[7] = k->wk_keytsc >> 40; /* PN5 */ |
---|
159 | } |
---|
160 | |
---|
161 | /* |
---|
162 | * Add privacy headers appropriate for the specified key. |
---|
163 | */ |
---|
164 | static int |
---|
165 | ccmp_encap(struct ieee80211_key *k, struct mbuf *m) |
---|
166 | { |
---|
167 | const struct ieee80211_frame *wh; |
---|
168 | struct ccmp_ctx *ctx = k->wk_private; |
---|
169 | struct ieee80211com *ic = ctx->cc_ic; |
---|
170 | uint8_t *ivp; |
---|
171 | int hdrlen; |
---|
172 | int is_mgmt; |
---|
173 | |
---|
174 | hdrlen = ieee80211_hdrspace(ic, mtod(m, void *)); |
---|
175 | wh = mtod(m, const struct ieee80211_frame *); |
---|
176 | is_mgmt = IEEE80211_IS_MGMT(wh); |
---|
177 | |
---|
178 | /* |
---|
179 | * Check to see if we need to insert IV/MIC. |
---|
180 | * |
---|
181 | * Some offload devices don't require the IV to be inserted |
---|
182 | * as part of the hardware encryption. |
---|
183 | */ |
---|
184 | if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT)) |
---|
185 | return 1; |
---|
186 | if ((! is_mgmt) && (k->wk_flags & IEEE80211_KEY_NOIV)) |
---|
187 | return 1; |
---|
188 | |
---|
189 | /* |
---|
190 | * Copy down 802.11 header and add the IV, KeyID, and ExtIV. |
---|
191 | */ |
---|
192 | M_PREPEND(m, ccmp.ic_header, M_NOWAIT); |
---|
193 | if (m == NULL) |
---|
194 | return 0; |
---|
195 | ivp = mtod(m, uint8_t *); |
---|
196 | ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen); |
---|
197 | ivp += hdrlen; |
---|
198 | |
---|
199 | ccmp_setiv(k, ivp); |
---|
200 | |
---|
201 | /* |
---|
202 | * Finally, do software encrypt if needed. |
---|
203 | */ |
---|
204 | if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) && |
---|
205 | !ccmp_encrypt(k, m, hdrlen)) |
---|
206 | return 0; |
---|
207 | |
---|
208 | return 1; |
---|
209 | } |
---|
210 | |
---|
211 | /* |
---|
212 | * Add MIC to the frame as needed. |
---|
213 | */ |
---|
214 | static int |
---|
215 | ccmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force) |
---|
216 | { |
---|
217 | |
---|
218 | return 1; |
---|
219 | } |
---|
220 | |
---|
221 | static __inline uint64_t |
---|
222 | READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) |
---|
223 | { |
---|
224 | uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24); |
---|
225 | uint16_t iv16 = (b4 << 0) | (b5 << 8); |
---|
226 | return (((uint64_t)iv16) << 32) | iv32; |
---|
227 | } |
---|
228 | |
---|
229 | /* |
---|
230 | * Validate and strip privacy headers (and trailer) for a |
---|
231 | * received frame. The specified key should be correct but |
---|
232 | * is also verified. |
---|
233 | */ |
---|
234 | static int |
---|
235 | ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen) |
---|
236 | { |
---|
237 | const struct ieee80211_rx_stats *rxs; |
---|
238 | struct ccmp_ctx *ctx = k->wk_private; |
---|
239 | struct ieee80211vap *vap = ctx->cc_vap; |
---|
240 | struct ieee80211_frame *wh; |
---|
241 | uint8_t *ivp, tid; |
---|
242 | uint64_t pn; |
---|
243 | |
---|
244 | rxs = ieee80211_get_rx_params_ptr(m); |
---|
245 | |
---|
246 | if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP)) |
---|
247 | goto finish; |
---|
248 | |
---|
249 | /* |
---|
250 | * Header should have extended IV and sequence number; |
---|
251 | * verify the former and validate the latter. |
---|
252 | */ |
---|
253 | wh = mtod(m, struct ieee80211_frame *); |
---|
254 | ivp = mtod(m, uint8_t *) + hdrlen; |
---|
255 | if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) { |
---|
256 | /* |
---|
257 | * No extended IV; discard frame. |
---|
258 | */ |
---|
259 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, |
---|
260 | "%s", "missing ExtIV for AES-CCM cipher"); |
---|
261 | vap->iv_stats.is_rx_ccmpformat++; |
---|
262 | return 0; |
---|
263 | } |
---|
264 | tid = ieee80211_gettid(wh); |
---|
265 | pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); |
---|
266 | if (pn <= k->wk_keyrsc[tid] && |
---|
267 | (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) { |
---|
268 | /* |
---|
269 | * Replay violation. |
---|
270 | */ |
---|
271 | ieee80211_notify_replay_failure(vap, wh, k, pn, tid); |
---|
272 | vap->iv_stats.is_rx_ccmpreplay++; |
---|
273 | return 0; |
---|
274 | } |
---|
275 | |
---|
276 | /* |
---|
277 | * Check if the device handled the decrypt in hardware. |
---|
278 | * If so we just strip the header; otherwise we need to |
---|
279 | * handle the decrypt in software. Note that for the |
---|
280 | * latter we leave the header in place for use in the |
---|
281 | * decryption work. |
---|
282 | */ |
---|
283 | if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) && |
---|
284 | !ccmp_decrypt(k, pn, m, hdrlen)) |
---|
285 | return 0; |
---|
286 | |
---|
287 | finish: |
---|
288 | /* |
---|
289 | * Copy up 802.11 header and strip crypto bits. |
---|
290 | */ |
---|
291 | if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { |
---|
292 | ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, |
---|
293 | hdrlen); |
---|
294 | m_adj(m, ccmp.ic_header); |
---|
295 | } |
---|
296 | |
---|
297 | /* |
---|
298 | * XXX TODO: see if MMIC_STRIP also covers CCMP MIC trailer. |
---|
299 | */ |
---|
300 | if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MMIC_STRIP))) |
---|
301 | m_adj(m, -ccmp.ic_trailer); |
---|
302 | |
---|
303 | /* |
---|
304 | * Ok to update rsc now. |
---|
305 | */ |
---|
306 | if (! ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP))) { |
---|
307 | k->wk_keyrsc[tid] = pn; |
---|
308 | } |
---|
309 | |
---|
310 | return 1; |
---|
311 | } |
---|
312 | |
---|
313 | /* |
---|
314 | * Verify and strip MIC from the frame. |
---|
315 | */ |
---|
316 | static int |
---|
317 | ccmp_demic(struct ieee80211_key *k, struct mbuf *m, int force) |
---|
318 | { |
---|
319 | return 1; |
---|
320 | } |
---|
321 | |
---|
322 | static __inline void |
---|
323 | xor_block(uint8_t *b, const uint8_t *a, size_t len) |
---|
324 | { |
---|
325 | int i; |
---|
326 | for (i = 0; i < len; i++) |
---|
327 | b[i] ^= a[i]; |
---|
328 | } |
---|
329 | |
---|
330 | /* |
---|
331 | * Host AP crypt: host-based CCMP encryption implementation for Host AP driver |
---|
332 | * |
---|
333 | * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> |
---|
334 | * |
---|
335 | * This program is free software; you can redistribute it and/or modify |
---|
336 | * it under the terms of the GNU General Public License version 2 as |
---|
337 | * published by the Free Software Foundation. See README and COPYING for |
---|
338 | * more details. |
---|
339 | * |
---|
340 | * Alternatively, this software may be distributed under the terms of BSD |
---|
341 | * license. |
---|
342 | */ |
---|
343 | |
---|
344 | static void |
---|
345 | ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh, |
---|
346 | u_int64_t pn, size_t dlen, |
---|
347 | uint8_t b0[AES_BLOCK_LEN], uint8_t aad[2 * AES_BLOCK_LEN], |
---|
348 | uint8_t auth[AES_BLOCK_LEN], uint8_t s0[AES_BLOCK_LEN]) |
---|
349 | { |
---|
350 | #define IS_QOS_DATA(wh) IEEE80211_QOS_HAS_SEQ(wh) |
---|
351 | |
---|
352 | /* CCM Initial Block: |
---|
353 | * Flag (Include authentication header, M=3 (8-octet MIC), |
---|
354 | * L=1 (2-octet Dlen)) |
---|
355 | * Nonce: 0x00 | A2 | PN |
---|
356 | * Dlen */ |
---|
357 | b0[0] = 0x59; |
---|
358 | /* NB: b0[1] set below */ |
---|
359 | IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2); |
---|
360 | b0[8] = pn >> 40; |
---|
361 | b0[9] = pn >> 32; |
---|
362 | b0[10] = pn >> 24; |
---|
363 | b0[11] = pn >> 16; |
---|
364 | b0[12] = pn >> 8; |
---|
365 | b0[13] = pn >> 0; |
---|
366 | b0[14] = (dlen >> 8) & 0xff; |
---|
367 | b0[15] = dlen & 0xff; |
---|
368 | |
---|
369 | /* AAD: |
---|
370 | * FC with bits 4..6 and 11..13 masked to zero; 14 is always one |
---|
371 | * A1 | A2 | A3 |
---|
372 | * SC with bits 4..15 (seq#) masked to zero |
---|
373 | * A4 (if present) |
---|
374 | * QC (if present) |
---|
375 | */ |
---|
376 | aad[0] = 0; /* AAD length >> 8 */ |
---|
377 | /* NB: aad[1] set below */ |
---|
378 | aad[2] = wh->i_fc[0] & 0x8f; /* XXX magic #s */ |
---|
379 | aad[3] = wh->i_fc[1] & 0xc7; /* XXX magic #s */ |
---|
380 | /* NB: we know 3 addresses are contiguous */ |
---|
381 | memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN); |
---|
382 | aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK; |
---|
383 | aad[23] = 0; /* all bits masked */ |
---|
384 | /* |
---|
385 | * Construct variable-length portion of AAD based |
---|
386 | * on whether this is a 4-address frame/QOS frame. |
---|
387 | * We always zero-pad to 32 bytes before running it |
---|
388 | * through the cipher. |
---|
389 | * |
---|
390 | * We also fill in the priority bits of the CCM |
---|
391 | * initial block as we know whether or not we have |
---|
392 | * a QOS frame. |
---|
393 | */ |
---|
394 | if (IEEE80211_IS_DSTODS(wh)) { |
---|
395 | IEEE80211_ADDR_COPY(aad + 24, |
---|
396 | ((struct ieee80211_frame_addr4 *)wh)->i_addr4); |
---|
397 | if (IS_QOS_DATA(wh)) { |
---|
398 | struct ieee80211_qosframe_addr4 *qwh4 = |
---|
399 | (struct ieee80211_qosframe_addr4 *) wh; |
---|
400 | aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */ |
---|
401 | aad[31] = 0; |
---|
402 | b0[1] = aad[30]; |
---|
403 | aad[1] = 22 + IEEE80211_ADDR_LEN + 2; |
---|
404 | } else { |
---|
405 | *(uint16_t *)&aad[30] = 0; |
---|
406 | b0[1] = 0; |
---|
407 | aad[1] = 22 + IEEE80211_ADDR_LEN; |
---|
408 | } |
---|
409 | } else { |
---|
410 | if (IS_QOS_DATA(wh)) { |
---|
411 | struct ieee80211_qosframe *qwh = |
---|
412 | (struct ieee80211_qosframe*) wh; |
---|
413 | aad[24] = qwh->i_qos[0] & 0x0f; /* just priority bits */ |
---|
414 | aad[25] = 0; |
---|
415 | b0[1] = aad[24]; |
---|
416 | aad[1] = 22 + 2; |
---|
417 | } else { |
---|
418 | *(uint16_t *)&aad[24] = 0; |
---|
419 | b0[1] = 0; |
---|
420 | aad[1] = 22; |
---|
421 | } |
---|
422 | *(uint16_t *)&aad[26] = 0; |
---|
423 | *(uint32_t *)&aad[28] = 0; |
---|
424 | } |
---|
425 | |
---|
426 | /* Start with the first block and AAD */ |
---|
427 | rijndael_encrypt(ctx, b0, auth); |
---|
428 | xor_block(auth, aad, AES_BLOCK_LEN); |
---|
429 | rijndael_encrypt(ctx, auth, auth); |
---|
430 | xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); |
---|
431 | rijndael_encrypt(ctx, auth, auth); |
---|
432 | b0[0] &= 0x07; |
---|
433 | b0[14] = b0[15] = 0; |
---|
434 | rijndael_encrypt(ctx, b0, s0); |
---|
435 | #undef IS_QOS_DATA |
---|
436 | } |
---|
437 | |
---|
438 | #define CCMP_ENCRYPT(_i, _b, _b0, _pos, _e, _len) do { \ |
---|
439 | /* Authentication */ \ |
---|
440 | xor_block(_b, _pos, _len); \ |
---|
441 | rijndael_encrypt(&ctx->cc_aes, _b, _b); \ |
---|
442 | /* Encryption, with counter */ \ |
---|
443 | _b0[14] = (_i >> 8) & 0xff; \ |
---|
444 | _b0[15] = _i & 0xff; \ |
---|
445 | rijndael_encrypt(&ctx->cc_aes, _b0, _e); \ |
---|
446 | xor_block(_pos, _e, _len); \ |
---|
447 | } while (0) |
---|
448 | |
---|
449 | static int |
---|
450 | ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen) |
---|
451 | { |
---|
452 | struct ccmp_ctx *ctx = key->wk_private; |
---|
453 | struct ieee80211_frame *wh; |
---|
454 | struct mbuf *m = m0; |
---|
455 | int data_len, i, space; |
---|
456 | uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], |
---|
457 | e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN]; |
---|
458 | uint8_t *pos; |
---|
459 | |
---|
460 | ctx->cc_vap->iv_stats.is_crypto_ccmp++; |
---|
461 | |
---|
462 | wh = mtod(m, struct ieee80211_frame *); |
---|
463 | data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header); |
---|
464 | ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, |
---|
465 | data_len, b0, aad, b, s0); |
---|
466 | |
---|
467 | i = 1; |
---|
468 | pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header; |
---|
469 | /* NB: assumes header is entirely in first mbuf */ |
---|
470 | space = m->m_len - (hdrlen + ccmp.ic_header); |
---|
471 | for (;;) { |
---|
472 | if (space > data_len) |
---|
473 | space = data_len; |
---|
474 | /* |
---|
475 | * Do full blocks. |
---|
476 | */ |
---|
477 | while (space >= AES_BLOCK_LEN) { |
---|
478 | CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN); |
---|
479 | pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; |
---|
480 | data_len -= AES_BLOCK_LEN; |
---|
481 | i++; |
---|
482 | } |
---|
483 | if (data_len <= 0) /* no more data */ |
---|
484 | break; |
---|
485 | m = m->m_next; |
---|
486 | if (m == NULL) { /* last buffer */ |
---|
487 | if (space != 0) { |
---|
488 | /* |
---|
489 | * Short last block. |
---|
490 | */ |
---|
491 | CCMP_ENCRYPT(i, b, b0, pos, e, space); |
---|
492 | } |
---|
493 | break; |
---|
494 | } |
---|
495 | if (space != 0) { |
---|
496 | uint8_t *pos_next; |
---|
497 | int space_next; |
---|
498 | int len, dl, sp; |
---|
499 | struct mbuf *n; |
---|
500 | |
---|
501 | /* |
---|
502 | * Block straddles one or more mbufs, gather data |
---|
503 | * into the block buffer b, apply the cipher, then |
---|
504 | * scatter the results back into the mbuf chain. |
---|
505 | * The buffer will automatically get space bytes |
---|
506 | * of data at offset 0 copied in+out by the |
---|
507 | * CCMP_ENCRYPT request so we must take care of |
---|
508 | * the remaining data. |
---|
509 | */ |
---|
510 | n = m; |
---|
511 | dl = data_len; |
---|
512 | sp = space; |
---|
513 | for (;;) { |
---|
514 | pos_next = mtod(n, uint8_t *); |
---|
515 | len = min(dl, AES_BLOCK_LEN); |
---|
516 | space_next = len > sp ? len - sp : 0; |
---|
517 | if (n->m_len >= space_next) { |
---|
518 | /* |
---|
519 | * This mbuf has enough data; just grab |
---|
520 | * what we need and stop. |
---|
521 | */ |
---|
522 | xor_block(b+sp, pos_next, space_next); |
---|
523 | break; |
---|
524 | } |
---|
525 | /* |
---|
526 | * This mbuf's contents are insufficient, |
---|
527 | * take 'em all and prepare to advance to |
---|
528 | * the next mbuf. |
---|
529 | */ |
---|
530 | xor_block(b+sp, pos_next, n->m_len); |
---|
531 | sp += n->m_len, dl -= n->m_len; |
---|
532 | n = n->m_next; |
---|
533 | if (n == NULL) |
---|
534 | break; |
---|
535 | } |
---|
536 | |
---|
537 | CCMP_ENCRYPT(i, b, b0, pos, e, space); |
---|
538 | |
---|
539 | /* NB: just like above, but scatter data to mbufs */ |
---|
540 | dl = data_len; |
---|
541 | sp = space; |
---|
542 | for (;;) { |
---|
543 | pos_next = mtod(m, uint8_t *); |
---|
544 | len = min(dl, AES_BLOCK_LEN); |
---|
545 | space_next = len > sp ? len - sp : 0; |
---|
546 | if (m->m_len >= space_next) { |
---|
547 | xor_block(pos_next, e+sp, space_next); |
---|
548 | break; |
---|
549 | } |
---|
550 | xor_block(pos_next, e+sp, m->m_len); |
---|
551 | sp += m->m_len, dl -= m->m_len; |
---|
552 | m = m->m_next; |
---|
553 | if (m == NULL) |
---|
554 | goto done; |
---|
555 | } |
---|
556 | /* |
---|
557 | * Do bookkeeping. m now points to the last mbuf |
---|
558 | * we grabbed data from. We know we consumed a |
---|
559 | * full block of data as otherwise we'd have hit |
---|
560 | * the end of the mbuf chain, so deduct from data_len. |
---|
561 | * Otherwise advance the block number (i) and setup |
---|
562 | * pos+space to reflect contents of the new mbuf. |
---|
563 | */ |
---|
564 | data_len -= AES_BLOCK_LEN; |
---|
565 | i++; |
---|
566 | pos = pos_next + space_next; |
---|
567 | space = m->m_len - space_next; |
---|
568 | } else { |
---|
569 | /* |
---|
570 | * Setup for next buffer. |
---|
571 | */ |
---|
572 | pos = mtod(m, uint8_t *); |
---|
573 | space = m->m_len; |
---|
574 | } |
---|
575 | } |
---|
576 | done: |
---|
577 | /* tack on MIC */ |
---|
578 | xor_block(b, s0, ccmp.ic_trailer); |
---|
579 | return m_append(m0, ccmp.ic_trailer, b); |
---|
580 | } |
---|
581 | #undef CCMP_ENCRYPT |
---|
582 | |
---|
583 | #define CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) do { \ |
---|
584 | /* Decrypt, with counter */ \ |
---|
585 | _b0[14] = (_i >> 8) & 0xff; \ |
---|
586 | _b0[15] = _i & 0xff; \ |
---|
587 | rijndael_encrypt(&ctx->cc_aes, _b0, _b); \ |
---|
588 | xor_block(_pos, _b, _len); \ |
---|
589 | /* Authentication */ \ |
---|
590 | xor_block(_a, _pos, _len); \ |
---|
591 | rijndael_encrypt(&ctx->cc_aes, _a, _a); \ |
---|
592 | } while (0) |
---|
593 | |
---|
594 | static int |
---|
595 | ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen) |
---|
596 | { |
---|
597 | struct ccmp_ctx *ctx = key->wk_private; |
---|
598 | struct ieee80211vap *vap = ctx->cc_vap; |
---|
599 | struct ieee80211_frame *wh; |
---|
600 | uint8_t aad[2 * AES_BLOCK_LEN]; |
---|
601 | uint8_t b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN]; |
---|
602 | uint8_t mic[AES_BLOCK_LEN]; |
---|
603 | size_t data_len; |
---|
604 | int i; |
---|
605 | uint8_t *pos; |
---|
606 | u_int space; |
---|
607 | |
---|
608 | ctx->cc_vap->iv_stats.is_crypto_ccmp++; |
---|
609 | |
---|
610 | wh = mtod(m, struct ieee80211_frame *); |
---|
611 | data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header + ccmp.ic_trailer); |
---|
612 | ccmp_init_blocks(&ctx->cc_aes, wh, pn, data_len, b0, aad, a, b); |
---|
613 | m_copydata(m, m->m_pkthdr.len - ccmp.ic_trailer, ccmp.ic_trailer, mic); |
---|
614 | xor_block(mic, b, ccmp.ic_trailer); |
---|
615 | |
---|
616 | i = 1; |
---|
617 | pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header; |
---|
618 | space = m->m_len - (hdrlen + ccmp.ic_header); |
---|
619 | for (;;) { |
---|
620 | if (space > data_len) |
---|
621 | space = data_len; |
---|
622 | while (space >= AES_BLOCK_LEN) { |
---|
623 | CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN); |
---|
624 | pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; |
---|
625 | data_len -= AES_BLOCK_LEN; |
---|
626 | i++; |
---|
627 | } |
---|
628 | if (data_len <= 0) /* no more data */ |
---|
629 | break; |
---|
630 | m = m->m_next; |
---|
631 | if (m == NULL) { /* last buffer */ |
---|
632 | if (space != 0) /* short last block */ |
---|
633 | CCMP_DECRYPT(i, b, b0, pos, a, space); |
---|
634 | break; |
---|
635 | } |
---|
636 | if (space != 0) { |
---|
637 | uint8_t *pos_next; |
---|
638 | u_int space_next; |
---|
639 | u_int len; |
---|
640 | |
---|
641 | /* |
---|
642 | * Block straddles buffers, split references. We |
---|
643 | * do not handle splits that require >2 buffers |
---|
644 | * since rx'd frames are never badly fragmented |
---|
645 | * because drivers typically recv in clusters. |
---|
646 | */ |
---|
647 | pos_next = mtod(m, uint8_t *); |
---|
648 | len = min(data_len, AES_BLOCK_LEN); |
---|
649 | space_next = len > space ? len - space : 0; |
---|
650 | KASSERT(m->m_len >= space_next, |
---|
651 | ("not enough data in following buffer, " |
---|
652 | "m_len %u need %u\n", m->m_len, space_next)); |
---|
653 | |
---|
654 | xor_block(b+space, pos_next, space_next); |
---|
655 | CCMP_DECRYPT(i, b, b0, pos, a, space); |
---|
656 | xor_block(pos_next, b+space, space_next); |
---|
657 | data_len -= len; |
---|
658 | i++; |
---|
659 | |
---|
660 | pos = pos_next + space_next; |
---|
661 | space = m->m_len - space_next; |
---|
662 | } else { |
---|
663 | /* |
---|
664 | * Setup for next buffer. |
---|
665 | */ |
---|
666 | pos = mtod(m, uint8_t *); |
---|
667 | space = m->m_len; |
---|
668 | } |
---|
669 | } |
---|
670 | if (memcmp(mic, a, ccmp.ic_trailer) != 0) { |
---|
671 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, |
---|
672 | "%s", "AES-CCM decrypt failed; MIC mismatch"); |
---|
673 | vap->iv_stats.is_rx_ccmpmic++; |
---|
674 | return 0; |
---|
675 | } |
---|
676 | return 1; |
---|
677 | } |
---|
678 | #undef CCMP_DECRYPT |
---|
679 | |
---|
680 | /* |
---|
681 | * Module glue. |
---|
682 | */ |
---|
683 | IEEE80211_CRYPTO_MODULE(ccmp, 1); |
---|