Browse Source

[wpa] Add CCMP backend (new AES-based cryptosystem)

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 14 years ago
parent
commit
5240fee38f
4 changed files with 535 additions and 0 deletions
  1. 5
    0
      src/config/config_net80211.c
  2. 1
    0
      src/config/general.h
  3. 1
    0
      src/include/gpxe/errfile.h
  4. 528
    0
      src/net/80211/wpa_ccmp.c

+ 5
- 0
src/config/config_net80211.c View File

@@ -39,6 +39,11 @@ REQUIRE_OBJECT ( wireless_errors );
39 39
 REQUIRE_OBJECT ( wep );
40 40
 #endif
41 41
 
42
+#ifdef CRYPTO_80211_WPA2
43
+#define CRYPTO_80211_WPA
44
+REQUIRE_OBJECT ( wpa_ccmp );
45
+#endif
46
+
42 47
 #ifdef CRYPTO_80211_WPA
43 48
 REQUIRE_OBJECT ( wpa_psk );
44 49
 REQUIRE_OBJECT ( wpa_tkip );

+ 1
- 0
src/config/general.h View File

@@ -70,6 +70,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
70 70
  */
71 71
 #define	CRYPTO_80211_WEP	/* WEP encryption (deprecated and insecure!) */
72 72
 #define	CRYPTO_80211_WPA	/* WPA Personal, authenticating with passphrase */
73
+#undef	CRYPTO_80211_WPA2	/* Add support for stronger WPA cryptography */
73 74
 
74 75
 /*
75 76
  * Name resolution modules

+ 1
- 0
src/include/gpxe/errfile.h View File

@@ -164,6 +164,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
164 164
 #define ERRFILE_wpa			( ERRFILE_NET | 0x00260000 )
165 165
 #define ERRFILE_wpa_psk			( ERRFILE_NET | 0x00270000 )
166 166
 #define ERRFILE_wpa_tkip		( ERRFILE_NET | 0x00280000 )
167
+#define ERRFILE_wpa_ccmp		( ERRFILE_NET | 0x00290000 )
167 168
 
168 169
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
169 170
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 528
- 0
src/net/80211/wpa_ccmp.c View File

@@ -0,0 +1,528 @@
1
+/*
2
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <gpxe/net80211.h>
22
+#include <gpxe/crypto.h>
23
+#include <gpxe/hmac.h>
24
+#include <gpxe/sha1.h>
25
+#include <gpxe/aes.h>
26
+#include <gpxe/wpa.h>
27
+#include <byteswap.h>
28
+#include <errno.h>
29
+
30
+/** @file
31
+ *
32
+ * Backend for WPA using the CCMP encryption method
33
+ */
34
+
35
+/** Context for CCMP encryption and decryption */
36
+struct ccmp_ctx
37
+{
38
+	/** AES context - only ever used for encryption */
39
+	u8 aes_ctx[AES_CTX_SIZE];
40
+
41
+	/** Most recently sent packet number */
42
+	u64 tx_seq;
43
+
44
+	/** Most recently received packet number */
45
+	u64 rx_seq;
46
+};
47
+
48
+/** Header structure at the beginning of CCMP frame data */
49
+struct ccmp_head
50
+{
51
+	u8 pn_lo[2];		/**< Bytes 0 and 1 of packet number */
52
+	u8 _rsvd;		/**< Reserved byte */
53
+	u8 kid;			/**< Key ID and ExtIV byte */
54
+	u8 pn_hi[4];		/**< Bytes 2-5 (2 first) of packet number */
55
+} __attribute__ (( packed ));
56
+
57
+
58
+/** CCMP header overhead */
59
+#define CCMP_HEAD_LEN	8
60
+
61
+/** CCMP MIC trailer overhead */
62
+#define CCMP_MIC_LEN	8
63
+
64
+/** CCMP nonce length */
65
+#define CCMP_NONCE_LEN	13
66
+
67
+/** CCMP nonce structure */
68
+struct ccmp_nonce
69
+{
70
+	u8 prio;		/**< Packet priority, 0 for non-QoS */
71
+	u8 a2[ETH_ALEN];	/**< Address 2 from packet header (sender) */
72
+	u8 pn[6];		/**< Packet number */
73
+} __attribute__ (( packed ));
74
+
75
+/** CCMP additional authentication data length (for non-QoS, non-WDS frames) */
76
+#define CCMP_AAD_LEN	22
77
+
78
+/** CCMP additional authentication data structure */
79
+struct ccmp_aad
80
+{
81
+	u16 fc;			/**< Frame Control field */
82
+	u8 a1[6];		/**< Address 1 */
83
+	u8 a2[6];		/**< Address 2 */
84
+	u8 a3[6];		/**< Address 3 */
85
+	u16 seq;		/**< Sequence Control field */
86
+	/* Address 4 and QoS Control are included if present */
87
+} __attribute__ (( packed ));
88
+
89
+/** Mask for Frame Control field in AAD */
90
+#define CCMP_AAD_FC_MASK	0xC38F
91
+
92
+/** Mask for Sequence Control field in AAD */
93
+#define CCMP_AAD_SEQ_MASK	0x000F
94
+
95
+
96
+/**
97
+ * Convert 6-byte LSB packet number to 64-bit integer
98
+ *
99
+ * @v pn	Pointer to 6-byte packet number
100
+ * @ret v	64-bit integer value of @a pn
101
+ */
102
+static u64 pn_to_u64 ( const u8 *pn )
103
+{
104
+	int i;
105
+	u64 ret = 0;
106
+
107
+	for ( i = 5; i >= 0; i-- ) {
108
+		ret <<= 8;
109
+		ret |= pn[i];
110
+	}
111
+
112
+	return ret;
113
+}
114
+
115
+/**
116
+ * Convert 64-bit integer to 6-byte packet number
117
+ *
118
+ * @v v		64-bit integer
119
+ * @v msb	If TRUE, reverse the output PN to be in MSB order
120
+ * @ret pn	6-byte packet number
121
+ *
122
+ * The PN is stored in LSB order in the packet header and in MSB order
123
+ * in the nonce. WHYYYYY?
124
+ */
125
+static void u64_to_pn ( u64 v, u8 *pn, int msb )
126
+{
127
+	int i;
128
+	u8 *pnp = pn + ( msb ? 5 : 0 );
129
+	int delta = ( msb ? -1 : +1 );
130
+
131
+	for ( i = 0; i < 6; i++ ) {
132
+		*pnp = v & 0xFF;
133
+		pnp += delta;
134
+		v >>= 8;
135
+	}
136
+}
137
+
138
+/** Value for @a msb argument of u64_to_pn() for MSB output */
139
+#define PN_MSB	1
140
+
141
+/** Value for @a msb argument of u64_to_pn() for LSB output */
142
+#define PN_LSB	0
143
+
144
+
145
+
146
+/**
147
+ * Initialise CCMP state and install key
148
+ *
149
+ * @v crypto	CCMP cryptosystem structure
150
+ * @v key	Pointer to 16-byte temporal key to install
151
+ * @v keylen	Length of key (16 bytes)
152
+ * @v rsc	Initial receive sequence counter
153
+ */
154
+static int ccmp_init ( struct net80211_crypto *crypto, const void *key,
155
+		       int keylen, const void *rsc )
156
+{
157
+	struct ccmp_ctx *ctx = crypto->priv;
158
+
159
+	if ( keylen != 16 )
160
+		return -EINVAL;
161
+
162
+	if ( rsc )
163
+		ctx->rx_seq = pn_to_u64 ( rsc );
164
+
165
+	cipher_setkey ( &aes_algorithm, ctx->aes_ctx, key, keylen );
166
+
167
+	return 0;
168
+}
169
+
170
+
171
+/**
172
+ * Encrypt or decrypt data stream using AES in Counter mode
173
+ *
174
+ * @v ctx	CCMP cryptosystem context
175
+ * @v nonce	Nonce value, 13 bytes
176
+ * @v srcv	Data to encrypt or decrypt
177
+ * @v len	Number of bytes pointed to by @a src
178
+ * @v msrcv	MIC value to encrypt or decrypt (may be NULL)
179
+ * @ret destv	Encrypted or decrypted data
180
+ * @ret mdestv	Encrypted or decrypted MIC value
181
+ *
182
+ * This assumes CCMP parameters of L=2 and M=8. The algorithm is
183
+ * defined in RFC 3610.
184
+ */
185
+static void ccmp_ctr_xor ( struct ccmp_ctx *ctx, const void *nonce,
186
+			   const void *srcv, void *destv, int len,
187
+			   const void *msrcv, void *mdestv )
188
+{
189
+	u8 A[16], S[16];
190
+	u16 ctr;
191
+	int i;
192
+	const u8 *src = srcv, *msrc = msrcv;
193
+	u8 *dest = destv, *mdest = mdestv;
194
+
195
+	A[0] = 0x01;		/* flags, L' = L - 1 = 1, other bits rsvd */
196
+	memcpy ( A + 1, nonce, CCMP_NONCE_LEN );
197
+
198
+	if ( msrcv ) {
199
+		A[14] = A[15] = 0;
200
+
201
+		cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 );
202
+
203
+		for ( i = 0; i < 8; i++ ) {
204
+			*mdest++ = *msrc++ ^ S[i];
205
+		}
206
+	}
207
+
208
+	for ( ctr = 1 ;; ctr++ ) {
209
+		A[14] = ctr >> 8;
210
+		A[15] = ctr & 0xFF;
211
+
212
+		cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 );
213
+
214
+		for ( i = 0; i < len && i < 16; i++ )
215
+			*dest++ = *src++ ^ S[i];
216
+
217
+		if ( len <= 16 )
218
+			break;	/* we're done */
219
+
220
+		len -= 16;
221
+	}
222
+}
223
+
224
+
225
+/**
226
+ * Advance one block in CBC-MAC calculation
227
+ *
228
+ * @v aes_ctx	AES encryption context with key set
229
+ * @v B		Cleartext block to incorporate (16 bytes)
230
+ * @v X		Previous ciphertext block (16 bytes)
231
+ * @ret B	Clobbered
232
+ * @ret X	New ciphertext block (16 bytes)
233
+ *
234
+ * This function does X := E[key] ( X ^ B ).
235
+ */
236
+static void ccmp_feed_cbc_mac ( void *aes_ctx, u8 *B, u8 *X )
237
+{
238
+	int i;
239
+	for ( i = 0; i < 16; i++ )
240
+		B[i] ^= X[i];
241
+	cipher_encrypt ( &aes_algorithm, aes_ctx, B, X, 16 );
242
+}
243
+
244
+
245
+/**
246
+ * Calculate MIC on plaintext data using CBC-MAC
247
+ *
248
+ * @v ctx	CCMP cryptosystem context
249
+ * @v nonce	Nonce value, 13 bytes
250
+ * @v data	Data to calculate MIC over
251
+ * @v datalen	Length of @a data
252
+ * @v aad	Additional authentication data, for MIC but not encryption
253
+ * @ret mic	MIC value (unencrypted), 8 bytes
254
+ *
255
+ * @a aadlen is assumed to be 22 bytes long, as it always is for
256
+ * 802.11 use when transmitting non-QoS, not-between-APs frames (the
257
+ * only type we deal with).
258
+ */
259
+static void ccmp_cbc_mac ( struct ccmp_ctx *ctx, const void *nonce,
260
+			   const void *data, u16 datalen,
261
+			   const void *aad, void *mic )
262
+{
263
+	u8 X[16], B[16];
264
+
265
+	/* Zeroth block: flags, nonce, length */
266
+
267
+	/* Rsv AAD - M'-  - L'-
268
+	 *  0   1  0 1 1  0 0 1   for an 8-byte MAC and 2-byte message length
269
+	 */
270
+	B[0] = 0x59;
271
+	memcpy ( B + 1, nonce, CCMP_NONCE_LEN );
272
+	B[14] = datalen >> 8;
273
+	B[15] = datalen & 0xFF;
274
+
275
+	cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, B, X, 16 );
276
+
277
+	/* First block: AAD length field and 14 bytes of AAD */
278
+	B[0] = 0;
279
+	B[1] = CCMP_AAD_LEN;
280
+	memcpy ( B + 2, aad, 14 );
281
+
282
+	ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
283
+
284
+	/* Second block: Remaining 8 bytes of AAD, 8 bytes zero pad */
285
+	memcpy ( B, aad + 14, 8 );
286
+	memset ( B + 8, 0, 8 );
287
+
288
+	ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
289
+
290
+	/* Message blocks */
291
+	while ( datalen ) {
292
+		if ( datalen >= 16 ) {
293
+			memcpy ( B, data, 16 );
294
+			datalen -= 16;
295
+		} else {
296
+			memcpy ( B, data, datalen );
297
+			memset ( B + datalen, 0, 16 - datalen );
298
+			datalen = 0;
299
+		}
300
+
301
+		ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X );
302
+
303
+		data += 16;
304
+	}
305
+
306
+	/* Get MIC from final value of X */
307
+	memcpy ( mic, X, 8 );
308
+}
309
+
310
+
311
+/**
312
+ * Encapsulate and encrypt a packet using CCMP
313
+ *
314
+ * @v crypto	CCMP cryptosystem
315
+ * @v iob	I/O buffer containing cleartext packet
316
+ * @ret eiob	I/O buffer containing encrypted packet
317
+ */
318
+struct io_buffer * ccmp_encrypt ( struct net80211_crypto *crypto,
319
+				  struct io_buffer *iob )
320
+{
321
+	struct ccmp_ctx *ctx = crypto->priv;
322
+	struct ieee80211_frame *hdr = iob->data;
323
+	struct io_buffer *eiob;
324
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
325
+	int datalen = iob_len ( iob ) - hdrlen;
326
+	struct ccmp_head head;
327
+	struct ccmp_nonce nonce;
328
+	struct ccmp_aad aad;
329
+	u8 mic[8], tx_pn[6];
330
+	void *edata, *emic;
331
+
332
+	ctx->tx_seq++;
333
+	u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB );
334
+
335
+	/* Allocate memory */
336
+	eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN );
337
+	if ( ! eiob )
338
+		return NULL;
339
+
340
+	/* Copy frame header */
341
+	memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen );
342
+	hdr = eiob->data;
343
+	hdr->fc |= IEEE80211_FC_PROTECTED;
344
+
345
+	/* Fill in packet number and extended IV */
346
+	memcpy ( head.pn_lo, tx_pn, 2 );
347
+	memcpy ( head.pn_hi, tx_pn + 2, 4 );
348
+	head.kid = 0x20;	/* have Extended IV, key ID 0 */
349
+	head._rsvd = 0;
350
+	memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) );
351
+
352
+	/* Form nonce */
353
+	nonce.prio = 0;
354
+	memcpy ( nonce.a2, hdr->addr2, ETH_ALEN );
355
+	u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB );
356
+
357
+	/* Form additional authentication data */
358
+	aad.fc = hdr->fc & CCMP_AAD_FC_MASK;
359
+	memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */
360
+	aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK;
361
+
362
+	/* Calculate MIC over the data */
363
+	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic );
364
+
365
+	/* Copy and encrypt data and MIC */
366
+	edata = iob_put ( eiob, datalen );
367
+	emic = iob_put ( eiob, CCMP_MIC_LEN );
368
+	ccmp_ctr_xor ( ctx, &nonce,
369
+		       iob->data + hdrlen, edata, datalen,
370
+		       mic, emic );
371
+
372
+	/* Done! */
373
+	DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx,
374
+		iob, eiob );
375
+
376
+	return eiob;
377
+}
378
+
379
+/**
380
+ * Decrypt a packet using CCMP
381
+ *
382
+ * @v crypto	CCMP cryptosystem
383
+ * @v eiob	I/O buffer containing encrypted packet
384
+ * @ret iob	I/O buffer containing cleartext packet
385
+ */
386
+static struct io_buffer * ccmp_decrypt ( struct net80211_crypto *crypto,
387
+					 struct io_buffer *eiob )
388
+{
389
+	struct ccmp_ctx *ctx = crypto->priv;
390
+	struct ieee80211_frame *hdr;
391
+	struct io_buffer *iob;
392
+	const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN;
393
+	int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN;
394
+	struct ccmp_head *head;
395
+	struct ccmp_nonce nonce;
396
+	struct ccmp_aad aad;
397
+	u8 rx_pn[6], their_mic[8], our_mic[8];
398
+
399
+	iob = alloc_iob ( hdrlen + datalen );
400
+	if ( ! iob )
401
+		return NULL;
402
+
403
+	/* Copy frame header */
404
+	memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen );
405
+	hdr = iob->data;
406
+	hdr->fc &= ~IEEE80211_FC_PROTECTED;
407
+
408
+	/* Check and update RX packet number */
409
+	head = eiob->data + hdrlen;
410
+	memcpy ( rx_pn, head->pn_lo, 2 );
411
+	memcpy ( rx_pn + 2, head->pn_hi, 4 );
412
+
413
+	if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) {
414
+		DBGC ( ctx, "WPA-CCMP %p: packet received out of order "
415
+		       "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ),
416
+		       ctx->rx_seq );
417
+		free_iob ( iob );
418
+		return NULL;
419
+	}
420
+
421
+	ctx->rx_seq = pn_to_u64 ( rx_pn );
422
+	DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq );
423
+
424
+	/* Form nonce */
425
+	nonce.prio = 0;
426
+	memcpy ( nonce.a2, hdr->addr2, ETH_ALEN );
427
+	u64_to_pn ( ctx->rx_seq, nonce.pn, PN_MSB );
428
+
429
+	/* Form additional authentication data */
430
+	aad.fc = ( hdr->fc & CCMP_AAD_FC_MASK ) | IEEE80211_FC_PROTECTED;
431
+	memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */
432
+	aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK;
433
+
434
+	/* Copy-decrypt data and MIC */
435
+	ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ),
436
+		       iob_put ( iob, datalen ), datalen,
437
+		       eiob->tail - CCMP_MIC_LEN, their_mic );
438
+
439
+	/* Check MIC */
440
+	ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad,
441
+		       our_mic );
442
+
443
+	if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) {
444
+		DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx );
445
+		free_iob ( iob );
446
+		return NULL;
447
+	}
448
+
449
+	DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx,
450
+		eiob, iob );
451
+
452
+	return iob;
453
+}
454
+
455
+
456
+/** CCMP cryptosystem */
457
+struct net80211_crypto ccmp_crypto __net80211_crypto = {
458
+	.algorithm = NET80211_CRYPT_CCMP,
459
+	.init = ccmp_init,
460
+	.encrypt = ccmp_encrypt,
461
+	.decrypt = ccmp_decrypt,
462
+	.priv_len = sizeof ( struct ccmp_ctx ),
463
+};
464
+
465
+
466
+
467
+
468
+/**
469
+ * Calculate HMAC-SHA1 MIC for EAPOL-Key frame
470
+ *
471
+ * @v kck	Key Confirmation Key, 16 bytes
472
+ * @v msg	Message to calculate MIC over
473
+ * @v len	Number of bytes to calculate MIC over
474
+ * @ret mic	Calculated MIC, 16 bytes long
475
+ */
476
+static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len,
477
+			   void *mic )
478
+{
479
+	u8 sha1_ctx[SHA1_CTX_SIZE];
480
+	u8 kckb[16];
481
+	u8 hash[SHA1_SIZE];
482
+	size_t kck_len = 16;
483
+
484
+	memcpy ( kckb, kck, kck_len );
485
+
486
+	hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len );
487
+	hmac_update ( &sha1_algorithm, sha1_ctx, msg, len );
488
+	hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash );
489
+
490
+	memcpy ( mic, hash, 16 );
491
+}
492
+
493
+/**
494
+ * Decrypt key data in EAPOL-Key frame
495
+ *
496
+ * @v kek	Key Encryption Key, 16 bytes
497
+ * @v iv	Initialisation vector, 16 bytes (unused)
498
+ * @v msg	Message to decrypt
499
+ * @v len	Length of message
500
+ * @ret msg	Decrypted message in place of original
501
+ * @ret len	Adjusted downward for 8 bytes of overhead
502
+ * @ret rc	Return status code
503
+ *
504
+ * The returned message may still contain padding of 0xDD followed by
505
+ * zero or more 0x00 octets. It is impossible to remove the padding
506
+ * without parsing the IEs in the packet (another design decision that
507
+ * tends to make one question the 802.11i committee's intelligence...)
508
+ */
509
+static int ccmp_kie_decrypt ( const void *kek, const void *iv __unused,
510
+			      void *msg, u16 *len )
511
+{
512
+	if ( *len % 8 != 0 )
513
+		return -EINVAL;
514
+
515
+	if ( aes_unwrap ( kek, msg, msg, *len / 8 - 1 ) != 0 )
516
+		return -EINVAL;
517
+
518
+	*len -= 8;
519
+
520
+	return 0;
521
+}
522
+
523
+/** CCMP-style key integrity and encryption handler */
524
+struct wpa_kie ccmp_kie __wpa_kie = {
525
+	.version = EAPOL_KEY_VERSION_WPA2,
526
+	.mic = ccmp_kie_mic,
527
+	.decrypt = ccmp_kie_decrypt,
528
+};

Loading…
Cancel
Save