Home | History | Annotate | Download | only in net80211
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * Copyright (c) 2001 Atsushi Onoe
      8  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     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.
     21  *
     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.
     25  *
     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.
     36  */
     37 
     38 /*
     39  * IEEE 802.11i CCMP crypto support.
     40  */
     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"
     48 
     49 struct ccmp_ctx {
     50 	struct ieee80211com *cc_ic;	/* for diagnostics */
     51 };
     52 
     53 #define	AES_BLOCK_LEN	16
     54 #define	AES_NONCE_LEN	13
     55 
     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);
     63 
     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);
     66 
     67 const struct ieee80211_cipher ccmp = {
     68 	"AES-CCM",
     69 	IEEE80211_CIPHER_AES_CCM,
     70 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
     71 	    IEEE80211_WEP_EXTIVLEN,
     72 	IEEE80211_WEP_MICLEN,
     73 	0,
     74 	ccmp_attach,
     75 	ccmp_detach,
     76 	ccmp_setkey,
     77 	ccmp_encap,
     78 	ccmp_decap,
     79 	ccmp_enmic,
     80 	ccmp_demic,
     81 };
     82 
     83 /* ARGSUSED */
     84 static void *
     85 ccmp_attach(struct ieee80211com *ic, struct ieee80211_key *k)
     86 {
     87 	struct ccmp_ctx *ctx;
     88 
     89 	ctx = kmem_zalloc(sizeof (struct ccmp_ctx), KM_SLEEP);
     90 	if (ctx == NULL)
     91 		return (NULL);
     92 
     93 	ctx->cc_ic = ic;
     94 	return (ctx);
     95 }
     96 
     97 static void
     98 ccmp_detach(struct ieee80211_key *k)
     99 {
    100 	struct ccmp_ctx *ctx = k->wk_private;
    101 
    102 	if (ctx != NULL)
    103 		kmem_free(ctx, sizeof (struct ccmp_ctx));
    104 }
    105 
    106 static int
    107 ccmp_setkey(struct ieee80211_key *k)
    108 {
    109 	if (k->wk_keylen != (128/NBBY))
    110 		return (0);
    111 
    112 	return (1);
    113 }
    114 
    115 /*
    116  * Add privacy headers appropriate for the specified key.
    117  */
    118 static int
    119 ccmp_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
    120 {
    121 	struct ccmp_ctx *ctx = k->wk_private;
    122 	uint8_t *ivp;
    123 	int hdrlen;
    124 
    125 	hdrlen = ieee80211_hdrspace(ctx->cc_ic, mp->b_rptr);
    126 	/*
    127 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
    128 	 */
    129 	ivp = mp->b_rptr;
    130 	ivp += hdrlen;
    131 
    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 */
    141 
    142 	/*
    143 	 * Finally, do software encrypt if neeed.
    144 	 */
    145 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
    146 	    !ccmp_encrypt(k, mp, hdrlen))
    147 		return (0);
    148 
    149 	return (1);
    150 }
    151 
    152 /*
    153  * Validate and strip privacy headers (and trailer) for a
    154  * received frame. The specified key should be correct but
    155  * is also verified.
    156  */
    157 static int
    158 ccmp_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
    159 {
    160 	uint8_t *ivp;
    161 	uint64_t pn;
    162 
    163 	/*
    164 	 * Header should have extended IV and sequence number;
    165 	 * verify the former and validate the latter.
    166 	 */
    167 	ivp = mp->b_rptr + hdrlen;
    168 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
    169 		/*
    170 		 * No extended IV; discard frame.
    171 		 */
    172 		return (0);
    173 	}
    174 
    175 	pn = ieee80211_read_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
    176 	if (pn <= k->wk_keyrsc) {
    177 		/*
    178 		 * Replay violation.
    179 		 */
    180 		return (0);
    181 	}
    182 
    183 	/*
    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
    188 	 * decryption work.
    189 	 */
    190 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
    191 	    !ccmp_decrypt(k, pn, mp, hdrlen))
    192 		return (0);
    193 
    194 	/*
    195 	 * Copy up 802.11 header and strip crypto bits.
    196 	 */
    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;
    200 
    201 	/*
    202 	 * Ok to update rsc now.
    203 	 */
    204 	k->wk_keyrsc = pn;
    205 
    206 	return (1);
    207 }
    208 
    209 /*
    210  * Add MIC to the frame as needed.
    211  */
    212 /* ARGSUSED */
    213 static int
    214 ccmp_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
    215 {
    216 	return (1);
    217 }
    218 
    219 /*
    220  * Verify and strip MIC from the frame.
    221  */
    222 /* ARGSUSED */
    223 static int
    224 ccmp_demic(struct ieee80211_key *k, mblk_t *mp, int force)
    225 {
    226 	return (1);
    227 }
    228 
    229 static int
    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)
    233 {
    234 	crypto_mechanism_t mech;
    235 	crypto_key_t crkey;
    236 	crypto_data_t d1, d2;
    237 
    238 	int rv;
    239 
    240 	ieee80211_dbg(IEEE80211_MSG_CRYPTO,
    241 	    "aes_ccm_encrypt(len=%d, keylen=%d)", plain_len, keylen);
    242 
    243 	bzero(&crkey, sizeof (crkey));
    244 
    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;
    249 
    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);
    253 
    254 #if defined(__amd64) || defined(__sparc)
    255 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%lx", mech.cm_type);
    256 #else
    257 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%llx", mech.cm_type);
    258 #endif
    259 
    260 	bzero(&d1, sizeof (d1));
    261 	bzero(&d2, sizeof (d2));
    262 
    263 	d1.cd_format = CRYPTO_DATA_RAW;
    264 	d1.cd_offset = 0;
    265 	d1.cd_length = plain_len;
    266 	d1.cd_raw.iov_base = (char *)plaintext;
    267 	d1.cd_raw.iov_len  = plain_len;
    268 
    269 	d2.cd_format = CRYPTO_DATA_RAW;
    270 	d2.cd_offset = 0;
    271 	d2.cd_length = cipher_len;
    272 	d2.cd_raw.iov_base = (char *)ciphertext;
    273 	d2.cd_raw.iov_len  = cipher_len;
    274 
    275 
    276 	rv = crypto_encrypt(&mech, &d1, &crkey, NULL, &d2, NULL);
    277 	if (rv != CRYPTO_SUCCESS)
    278 		ieee80211_err("aes_ccm_encrypt failed (%x)", rv);
    279 	return (rv);
    280 }
    281 
    282 static int
    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)
    286 {
    287 	crypto_mechanism_t mech;
    288 	crypto_key_t crkey;
    289 	crypto_data_t d1, d2;
    290 
    291 	int rv;
    292 
    293 	ieee80211_dbg(IEEE80211_MSG_CRYPTO,
    294 	    "aes_ccm_decrypt(len=%d, keylen=%d)", cipher_len, keylen);
    295 
    296 	bzero(&crkey, sizeof (crkey));
    297 
    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;
    302 
    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);
    306 
    307 #if defined(__amd64) || defined(__sparc)
    308 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%lx", mech.cm_type);
    309 #else
    310 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%llx", mech.cm_type);
    311 #endif
    312 
    313 	bzero(&d1, sizeof (d1));
    314 	bzero(&d2, sizeof (d2));
    315 
    316 	d1.cd_format = CRYPTO_DATA_RAW;
    317 	d1.cd_offset = 0;
    318 	d1.cd_length = cipher_len;
    319 	d1.cd_raw.iov_base = (char *)ciphertext;
    320 	d1.cd_raw.iov_len  = cipher_len;
    321 
    322 	d2.cd_format = CRYPTO_DATA_RAW;
    323 	d2.cd_offset = 0;
    324 	d2.cd_length = plain_len;
    325 	d2.cd_raw.iov_base = (char *)plaintext;
    326 	d2.cd_raw.iov_len  = plain_len;
    327 
    328 
    329 	rv = crypto_decrypt(&mech, &d1, &crkey, NULL, &d2, NULL);
    330 	if (rv != CRYPTO_SUCCESS)
    331 		ieee80211_err("aes_ccm_decrypt failed (%x)", rv);
    332 	return (rv);
    333 }
    334 
    335 /*
    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.
    343  */
    344 
    345 /*
    346  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
    347  *
    348  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline (at) cc.hut.fi>
    349  *
    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
    353  * more details.
    354  *
    355  * Alternatively, this software may be distributed under the terms of BSD
    356  * license.
    357  */
    358 
    359 static void
    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])
    362 {
    363 	/*
    364 	 * CCM Initial Block:
    365 	 * Flag (Include authentication header, M=3 (8-octet MIC),
    366 	 * L=1 (2-octet Dlen))
    367 	 * Nonce: 0x00 | A2 | PN
    368 	 * Dlen
    369 	 */
    370 	b0[0] = 0x59;
    371 	/* b0[1] set below */
    372 	IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2);
    373 	b0[8] = pn >> 40;
    374 	b0[9] = pn >> 32;
    375 	b0[10] = pn >> 24;
    376 	b0[11] = pn >> 16;
    377 	b0[12] = pn >> 8;
    378 	b0[13] = (uint8_t)(pn >> 0);
    379 	b0[14] = (dlen >> 8) & 0xff;
    380 	b0[15] = dlen & 0xff;
    381 
    382 	/*
    383 	 * AAD:
    384 	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
    385 	 * A1 | A2 | A3
    386 	 * SC with bits 4..15 (seq#) masked to zero
    387 	 * A4 (if present)
    388 	 * QC (if present)
    389 	 */
    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 */
    398 	/*
    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.
    403 	 *
    404 	 * We also fill in the priority bits of the CCM
    405 	 * initial block as we know whether or not we have
    406 	 * a QOS frame.
    407 	 */
    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 */
    412 		aad[25] = 0;
    413 		b0[1] = aad[24];
    414 		aad[1] = 22 + 2;
    415 	} else {
    416 		*(uint16_t *)&aad[24] = 0;
    417 		b0[1] = 0;
    418 		aad[1] = 22;
    419 	}
    420 	*(uint16_t *)&aad[26] = 0;
    421 	*(uint32_t *)&aad[28] = 0;
    422 }
    423 
    424 static int
    425 ccmp_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
    426 {
    427 	struct ieee80211_frame *wh;
    428 	int rv, data_len;
    429 	uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN];
    430 	uint8_t *pos;
    431 	CK_AES_CCM_PARAMS cmparam;
    432 
    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;
    436 
    437 	ccmp_init(wh, key->wk_keytsc, data_len, b0, aad);
    438 
    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 */
    445 
    446 	rv = aes_ccm_encrypt(&cmparam,
    447 	    key->wk_key, key->wk_keylen,
    448 	    pos, data_len, pos, data_len + IEEE80211_WEP_MICLEN);
    449 
    450 	mp->b_wptr += ccmp.ic_trailer;
    451 
    452 	return ((rv == CRYPTO_SUCCESS)? 1 : 0);
    453 }
    454 
    455 static int
    456 ccmp_decrypt(struct ieee80211_key *key, uint64_t pn, mblk_t *mp, int hdrlen)
    457 {
    458 	struct ieee80211_frame *wh;
    459 	int rv, data_len;
    460 	uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN];
    461 	uint8_t *pos;
    462 	CK_AES_CCM_PARAMS cmparam;
    463 
    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;
    467 
    468 	ccmp_init(wh, pn, data_len, b0, aad);
    469 
    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 */
    476 
    477 	rv = aes_ccm_decrypt(&cmparam,
    478 	    key->wk_key, key->wk_keylen, pos, data_len, pos, data_len);
    479 
    480 	return ((rv == CRYPTO_SUCCESS)? 1 : 0);
    481 }
    482