2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 2001 Atsushi Onoe
8 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * Alternatively, this software may be distributed under the terms of the
23 * GNU General Public License ("GPL") version 2 as published by the Free
24 * Software Foundation.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * IEEE 802.11i CCMP crypto support.
41 #include <sys/byteorder.h>
42 #include <sys/crypto/common.h>
43 #include <sys/crypto/api.h>
44 #include <sys/crc32.h>
45 #include <sys/random.h>
46 #include <sys/strsun.h>
47 #include "net80211_impl.h"
50 struct ieee80211com
*cc_ic
; /* for diagnostics */
53 #define AES_BLOCK_LEN 16
54 #define AES_NONCE_LEN 13
56 static void *ccmp_attach(struct ieee80211com
*, struct ieee80211_key
*);
57 static void ccmp_detach(struct ieee80211_key
*);
58 static int ccmp_setkey(struct ieee80211_key
*);
59 static int ccmp_encap(struct ieee80211_key
*k
, mblk_t
*, uint8_t);
60 static int ccmp_decap(struct ieee80211_key
*, mblk_t
*, int);
61 static int ccmp_enmic(struct ieee80211_key
*, mblk_t
*, int);
62 static int ccmp_demic(struct ieee80211_key
*, mblk_t
*, int);
64 static int ccmp_encrypt(struct ieee80211_key
*, mblk_t
*, int);
65 static int ccmp_decrypt(struct ieee80211_key
*, uint64_t pn
, mblk_t
*, int);
67 const struct ieee80211_cipher ccmp
= {
69 IEEE80211_CIPHER_AES_CCM
,
70 IEEE80211_WEP_IVLEN
+ IEEE80211_WEP_KIDLEN
+
71 IEEE80211_WEP_EXTIVLEN
,
85 ccmp_attach(struct ieee80211com
*ic
, struct ieee80211_key
*k
)
89 ctx
= kmem_zalloc(sizeof (struct ccmp_ctx
), KM_SLEEP
);
98 ccmp_detach(struct ieee80211_key
*k
)
100 struct ccmp_ctx
*ctx
= k
->wk_private
;
103 kmem_free(ctx
, sizeof (struct ccmp_ctx
));
107 ccmp_setkey(struct ieee80211_key
*k
)
109 if (k
->wk_keylen
!= (128/NBBY
))
116 * Add privacy headers appropriate for the specified key.
119 ccmp_encap(struct ieee80211_key
*k
, mblk_t
*mp
, uint8_t keyid
)
121 struct ccmp_ctx
*ctx
= k
->wk_private
;
125 hdrlen
= ieee80211_hdrspace(ctx
->cc_ic
, mp
->b_rptr
);
127 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
132 k
->wk_keytsc
++; /* wrap at 48 bits */
133 ivp
[0] = k
->wk_keytsc
>> 0; /* PN0 */
134 ivp
[1] = k
->wk_keytsc
>> 8; /* PN1 */
135 ivp
[2] = 0; /* Reserved */
136 ivp
[3] = keyid
| IEEE80211_WEP_EXTIV
; /* KeyID | ExtID */
137 ivp
[4] = k
->wk_keytsc
>> 16; /* PN2 */
138 ivp
[5] = k
->wk_keytsc
>> 24; /* PN3 */
139 ivp
[6] = k
->wk_keytsc
>> 32; /* PN4 */
140 ivp
[7] = k
->wk_keytsc
>> 40; /* PN5 */
143 * Finally, do software encrypt if neeed.
145 if ((k
->wk_flags
& IEEE80211_KEY_SWCRYPT
) &&
146 !ccmp_encrypt(k
, mp
, hdrlen
))
153 * Validate and strip privacy headers (and trailer) for a
154 * received frame. The specified key should be correct but
158 ccmp_decap(struct ieee80211_key
*k
, mblk_t
*mp
, int hdrlen
)
164 * Header should have extended IV and sequence number;
165 * verify the former and validate the latter.
167 ivp
= mp
->b_rptr
+ hdrlen
;
168 if ((ivp
[IEEE80211_WEP_IVLEN
] & IEEE80211_WEP_EXTIV
) == 0) {
170 * No extended IV; discard frame.
175 pn
= ieee80211_read_6(ivp
[0], ivp
[1], ivp
[4], ivp
[5], ivp
[6], ivp
[7]);
176 if (pn
<= k
->wk_keyrsc
) {
184 * Check if the device handled the decrypt in hardware.
185 * If so we just strip the header; otherwise we need to
186 * handle the decrypt in software. Note that for the
187 * latter we leave the header in place for use in the
190 if ((k
->wk_flags
& IEEE80211_KEY_SWCRYPT
) &&
191 !ccmp_decrypt(k
, pn
, mp
, hdrlen
))
195 * Copy up 802.11 header and strip crypto bits.
197 (void) memmove(mp
->b_rptr
+ ccmp
.ic_header
, mp
->b_rptr
, hdrlen
);
198 mp
->b_rptr
+= ccmp
.ic_header
;
199 mp
->b_wptr
-= ccmp
.ic_trailer
;
202 * Ok to update rsc now.
210 * Add MIC to the frame as needed.
214 ccmp_enmic(struct ieee80211_key
*k
, mblk_t
*mp
, int force
)
220 * Verify and strip MIC from the frame.
224 ccmp_demic(struct ieee80211_key
*k
, mblk_t
*mp
, int force
)
230 aes_ccm_encrypt(CK_AES_CCM_PARAMS
*cmparam
, const uint8_t *key
, int keylen
,
231 const uint8_t *plaintext
, int plain_len
,
232 uint8_t *ciphertext
, int cipher_len
)
234 crypto_mechanism_t mech
;
236 crypto_data_t d1
, d2
;
240 ieee80211_dbg(IEEE80211_MSG_CRYPTO
,
241 "aes_ccm_encrypt(len=%d, keylen=%d)", plain_len
, keylen
);
243 bzero(&crkey
, sizeof (crkey
));
245 crkey
.ck_format
= CRYPTO_KEY_RAW
;
246 crkey
.ck_data
= (char *)key
;
247 /* keys are measured in bits, not bytes, so multiply by 8 */
248 crkey
.ck_length
= keylen
* 8;
250 mech
.cm_type
= crypto_mech2id(SUN_CKM_AES_CCM
);
251 mech
.cm_param
= (caddr_t
)cmparam
;
252 mech
.cm_param_len
= sizeof (CK_AES_CCM_PARAMS
);
254 #if defined(__amd64) || defined(__sparc)
255 ieee80211_dbg(IEEE80211_MSG_CRYPTO
, "cm_type=%lx", mech
.cm_type
);
257 ieee80211_dbg(IEEE80211_MSG_CRYPTO
, "cm_type=%llx", mech
.cm_type
);
260 bzero(&d1
, sizeof (d1
));
261 bzero(&d2
, sizeof (d2
));
263 d1
.cd_format
= CRYPTO_DATA_RAW
;
265 d1
.cd_length
= plain_len
;
266 d1
.cd_raw
.iov_base
= (char *)plaintext
;
267 d1
.cd_raw
.iov_len
= plain_len
;
269 d2
.cd_format
= CRYPTO_DATA_RAW
;
271 d2
.cd_length
= cipher_len
;
272 d2
.cd_raw
.iov_base
= (char *)ciphertext
;
273 d2
.cd_raw
.iov_len
= cipher_len
;
276 rv
= crypto_encrypt(&mech
, &d1
, &crkey
, NULL
, &d2
, NULL
);
277 if (rv
!= CRYPTO_SUCCESS
)
278 ieee80211_err("aes_ccm_encrypt failed (%x)", rv
);
283 aes_ccm_decrypt(CK_AES_CCM_PARAMS
*cmparam
, const uint8_t *key
, int keylen
,
284 const uint8_t *ciphertext
, int cipher_len
,
285 uint8_t *plaintext
, int plain_len
)
287 crypto_mechanism_t mech
;
289 crypto_data_t d1
, d2
;
293 ieee80211_dbg(IEEE80211_MSG_CRYPTO
,
294 "aes_ccm_decrypt(len=%d, keylen=%d)", cipher_len
, keylen
);
296 bzero(&crkey
, sizeof (crkey
));
298 crkey
.ck_format
= CRYPTO_KEY_RAW
;
299 crkey
.ck_data
= (char *)key
;
300 /* keys are measured in bits, not bytes, so multiply by 8 */
301 crkey
.ck_length
= keylen
* 8;
303 mech
.cm_type
= crypto_mech2id(SUN_CKM_AES_CCM
);
304 mech
.cm_param
= (caddr_t
)cmparam
;
305 mech
.cm_param_len
= sizeof (CK_AES_CCM_PARAMS
);
307 #if defined(__amd64) || defined(__sparc)
308 ieee80211_dbg(IEEE80211_MSG_CRYPTO
, "cm_type=%lx", mech
.cm_type
);
310 ieee80211_dbg(IEEE80211_MSG_CRYPTO
, "cm_type=%llx", mech
.cm_type
);
313 bzero(&d1
, sizeof (d1
));
314 bzero(&d2
, sizeof (d2
));
316 d1
.cd_format
= CRYPTO_DATA_RAW
;
318 d1
.cd_length
= cipher_len
;
319 d1
.cd_raw
.iov_base
= (char *)ciphertext
;
320 d1
.cd_raw
.iov_len
= cipher_len
;
322 d2
.cd_format
= CRYPTO_DATA_RAW
;
324 d2
.cd_length
= plain_len
;
325 d2
.cd_raw
.iov_base
= (char *)plaintext
;
326 d2
.cd_raw
.iov_len
= plain_len
;
329 rv
= crypto_decrypt(&mech
, &d1
, &crkey
, NULL
, &d2
, NULL
);
330 if (rv
!= CRYPTO_SUCCESS
)
331 ieee80211_err("aes_ccm_decrypt failed (%x)", rv
);
336 * For the avoidance of doubt, except that if any license choice other
337 * than GPL or LGPL is available it will apply instead, Sun elects to
338 * use only the General Public License version 2 (GPLv2) at this time
339 * for any software where a choice of GPL license versions is made
340 * available with the language indicating that GPLv2 or any later
341 * version may be used, or where a choice of which version of the GPL
342 * is applied is otherwise unspecified.
346 * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
348 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
350 * This program is free software; you can redistribute it and/or modify
351 * it under the terms of the GNU General Public License version 2 as
352 * published by the Free Software Foundation. See README and COPYING for
355 * Alternatively, this software may be distributed under the terms of BSD
360 ccmp_init(struct ieee80211_frame
*wh
, uint64_t pn
, size_t dlen
,
361 uint8_t b0
[AES_BLOCK_LEN
], uint8_t aad
[2 * AES_BLOCK_LEN
])
365 * Flag (Include authentication header, M=3 (8-octet MIC),
366 * L=1 (2-octet Dlen))
367 * Nonce: 0x00 | A2 | PN
371 /* b0[1] set below */
372 IEEE80211_ADDR_COPY(b0
+ 2, wh
->i_addr2
);
378 b0
[13] = (uint8_t)(pn
>> 0);
379 b0
[14] = (dlen
>> 8) & 0xff;
380 b0
[15] = dlen
& 0xff;
384 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
386 * SC with bits 4..15 (seq#) masked to zero
390 aad
[0] = 0; /* AAD length >> 8 */
391 /* aad[1] set below */
392 aad
[2] = wh
->i_fc
[0] & 0x8f; /* magic #s */
393 aad
[3] = wh
->i_fc
[1] & 0xc7; /* magic #s */
394 /* we know 3 addresses are contiguous */
395 (void) memcpy(aad
+ 4, wh
->i_addr1
, 3 * IEEE80211_ADDR_LEN
);
396 aad
[22] = wh
->i_seq
[0] & IEEE80211_SEQ_FRAG_MASK
;
397 aad
[23] = 0; /* all bits masked */
399 * Construct variable-length portion of AAD based
400 * on whether this is a 4-address frame/QOS frame.
401 * We always zero-pad to 32 bytes before running it
402 * through the cipher.
404 * We also fill in the priority bits of the CCM
405 * initial block as we know whether or not we have
408 if (IEEE80211_QOS_HAS_SEQ(wh
)) {
409 struct ieee80211_qosframe
*qwh
=
410 (struct ieee80211_qosframe
*)wh
;
411 aad
[24] = qwh
->i_qos
[0] & 0x0f; /* just priority bits */
416 *(uint16_t *)&aad
[24] = 0;
420 *(uint16_t *)&aad
[26] = 0;
421 *(uint32_t *)&aad
[28] = 0;
425 ccmp_encrypt(struct ieee80211_key
*key
, mblk_t
*mp
, int hdrlen
)
427 struct ieee80211_frame
*wh
;
429 uint8_t aad
[2 * AES_BLOCK_LEN
], b0
[AES_BLOCK_LEN
];
431 CK_AES_CCM_PARAMS cmparam
;
433 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
434 data_len
= MBLKL(mp
) - (hdrlen
+ ccmp
.ic_header
);
435 pos
= mp
->b_rptr
+ hdrlen
+ ccmp
.ic_header
;
437 ccmp_init(wh
, key
->wk_keytsc
, data_len
, b0
, aad
);
439 cmparam
.ulMACSize
= IEEE80211_WEP_MICLEN
;
440 cmparam
.ulNonceSize
= AES_NONCE_LEN
; /* N size */
441 cmparam
.ulAuthDataSize
= aad
[1]; /* A size */
442 cmparam
.ulDataSize
= data_len
; /* data length; */
443 cmparam
.nonce
= &b0
[1]; /* N */
444 cmparam
.authData
= &aad
[2]; /* A */
446 rv
= aes_ccm_encrypt(&cmparam
,
447 key
->wk_key
, key
->wk_keylen
,
448 pos
, data_len
, pos
, data_len
+ IEEE80211_WEP_MICLEN
);
450 mp
->b_wptr
+= ccmp
.ic_trailer
;
452 return ((rv
== CRYPTO_SUCCESS
)? 1 : 0);
456 ccmp_decrypt(struct ieee80211_key
*key
, uint64_t pn
, mblk_t
*mp
, int hdrlen
)
458 struct ieee80211_frame
*wh
;
460 uint8_t aad
[2 * AES_BLOCK_LEN
], b0
[AES_BLOCK_LEN
];
462 CK_AES_CCM_PARAMS cmparam
;
464 wh
= (struct ieee80211_frame
*)mp
->b_rptr
;
465 data_len
= MBLKL(mp
) - (hdrlen
+ ccmp
.ic_header
);
466 pos
= mp
->b_rptr
+ hdrlen
+ ccmp
.ic_header
;
468 ccmp_init(wh
, pn
, data_len
, b0
, aad
);
470 cmparam
.ulMACSize
= IEEE80211_WEP_MICLEN
; /* MIC = 8 */
471 cmparam
.ulNonceSize
= AES_NONCE_LEN
; /* N size */
472 cmparam
.ulAuthDataSize
= aad
[1]; /* A size */
473 cmparam
.ulDataSize
= data_len
;
474 cmparam
.nonce
= &b0
[1]; /* N */
475 cmparam
.authData
= &aad
[2]; /* A */
477 rv
= aes_ccm_decrypt(&cmparam
,
478 key
->wk_key
, key
->wk_keylen
, pos
, data_len
, pos
, data_len
);
480 return ((rv
== CRYPTO_SUCCESS
)? 1 : 0);