xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211_crypto_ccmp.c (revision 15e6edf145a9c2bb0e0272cf8debe823bb97529b)
1 /*
2  * Copyright 2008 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-2005 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 /*
41  * IEEE 802.11i CCMP crypto support.
42  */
43 #include <sys/byteorder.h>
44 #include <sys/crypto/common.h>
45 #include <sys/crypto/api.h>
46 #include <sys/crc32.h>
47 #include <sys/random.h>
48 #include "net80211_impl.h"
49 
50 struct ccmp_ctx {
51 	struct ieee80211com *cc_ic;	/* for diagnostics */
52 };
53 
54 #define	AES_BLOCK_LEN	16
55 #define	AES_NONCE_LEN	13
56 
57 static void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
58 static void ccmp_detach(struct ieee80211_key *);
59 static int ccmp_setkey(struct ieee80211_key *);
60 static int ccmp_encap(struct ieee80211_key *k, mblk_t *, uint8_t);
61 static int ccmp_decap(struct ieee80211_key *, mblk_t *, int);
62 static int ccmp_enmic(struct ieee80211_key *, mblk_t *, int);
63 static int ccmp_demic(struct ieee80211_key *, mblk_t *, int);
64 
65 static int ccmp_encrypt(struct ieee80211_key *, mblk_t *, int);
66 static int ccmp_decrypt(struct ieee80211_key *, uint64_t pn, mblk_t *, int);
67 
68 const struct ieee80211_cipher ccmp = {
69 	"AES-CCM",
70 	IEEE80211_CIPHER_AES_CCM,
71 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
72 	    IEEE80211_WEP_EXTIVLEN,
73 	IEEE80211_WEP_MICLEN,
74 	0,
75 	ccmp_attach,
76 	ccmp_detach,
77 	ccmp_setkey,
78 	ccmp_encap,
79 	ccmp_decap,
80 	ccmp_enmic,
81 	ccmp_demic,
82 };
83 
84 /* ARGSUSED */
85 static void *
86 ccmp_attach(struct ieee80211com *ic, struct ieee80211_key *k)
87 {
88 	struct ccmp_ctx *ctx;
89 
90 	ctx = kmem_zalloc(sizeof (struct ccmp_ctx), KM_SLEEP);
91 	if (ctx == NULL)
92 		return (NULL);
93 
94 	ctx->cc_ic = ic;
95 	return (ctx);
96 }
97 
98 static void
99 ccmp_detach(struct ieee80211_key *k)
100 {
101 	struct ccmp_ctx *ctx = k->wk_private;
102 
103 	if (ctx != NULL)
104 		kmem_free(ctx, sizeof (struct ccmp_ctx));
105 }
106 
107 static int
108 ccmp_setkey(struct ieee80211_key *k)
109 {
110 	if (k->wk_keylen != (128/NBBY))
111 		return (0);
112 
113 	return (1);
114 }
115 
116 /*
117  * Add privacy headers appropriate for the specified key.
118  */
119 static int
120 ccmp_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
121 {
122 	uint8_t *ivp;
123 	int hdrlen;
124 
125 	hdrlen = ieee80211_hdrspace(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 	struct ieee80211_frame tmp;
161 	uint8_t *ivp;
162 	uint64_t pn;
163 
164 	/*
165 	 * Header should have extended IV and sequence number;
166 	 * verify the former and validate the latter.
167 	 */
168 	ivp = mp->b_rptr + hdrlen;
169 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
170 		/*
171 		 * No extended IV; discard frame.
172 		 */
173 		return (0);
174 	}
175 
176 	pn = ieee80211_read_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
177 	if (pn <= k->wk_keyrsc) {
178 		/*
179 		 * Replay violation.
180 		 */
181 		return (0);
182 	}
183 
184 	/*
185 	 * Check if the device handled the decrypt in hardware.
186 	 * If so we just strip the header; otherwise we need to
187 	 * handle the decrypt in software.  Note that for the
188 	 * latter we leave the header in place for use in the
189 	 * decryption work.
190 	 */
191 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
192 	    !ccmp_decrypt(k, pn, mp, hdrlen))
193 		return (0);
194 
195 	/*
196 	 * Copy up 802.11 header and strip crypto bits.
197 	 */
198 	bcopy(mp->b_rptr, &tmp, hdrlen);
199 	bcopy(&tmp, mp->b_rptr + ccmp.ic_header, hdrlen);
200 	mp->b_rptr += ccmp.ic_header;
201 	mp->b_wptr -= ccmp.ic_trailer;
202 
203 	/*
204 	 * Ok to update rsc now.
205 	 */
206 	k->wk_keyrsc = pn;
207 
208 	return (1);
209 }
210 
211 /*
212  * Add MIC to the frame as needed.
213  */
214 /* ARGSUSED */
215 static int
216 ccmp_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
217 {
218 	return (1);
219 }
220 
221 /*
222  * Verify and strip MIC from the frame.
223  */
224 /* ARGSUSED */
225 static int
226 ccmp_demic(struct ieee80211_key *k, mblk_t *mp, int force)
227 {
228 	return (1);
229 }
230 
231 static int
232 aes_ccm_encrypt(CK_AES_CCM_PARAMS *cmparam, const uint8_t *key, int keylen,
233     const uint8_t *plaintext, int plain_len,
234     uint8_t *ciphertext, int cipher_len)
235 {
236 	crypto_mechanism_t mech;
237 	crypto_key_t crkey;
238 	crypto_data_t d1, d2;
239 
240 	int rv;
241 
242 	ieee80211_dbg(IEEE80211_MSG_CRYPTO,
243 	    "aes_ccm_encrypt(len=%d, keylen=%d)", plain_len, keylen);
244 
245 	bzero(&crkey, sizeof (crkey));
246 
247 	crkey.ck_format = CRYPTO_KEY_RAW;
248 	crkey.ck_data   = (char *)key;
249 	/* keys are measured in bits, not bytes, so multiply by 8 */
250 	crkey.ck_length = keylen * 8;
251 
252 	mech.cm_type	  = crypto_mech2id(SUN_CKM_AES_CCM);
253 	mech.cm_param	  = (caddr_t)cmparam;
254 	mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
255 
256 #if defined(__amd64) || defined(__sparc)
257 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%lx", mech.cm_type);
258 #else
259 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%llx", mech.cm_type);
260 #endif
261 
262 	bzero(&d1, sizeof (d1));
263 	bzero(&d2, sizeof (d2));
264 
265 	d1.cd_format = CRYPTO_DATA_RAW;
266 	d1.cd_offset = 0;
267 	d1.cd_length = plain_len;
268 	d1.cd_raw.iov_base = (char *)plaintext;
269 	d1.cd_raw.iov_len  = plain_len;
270 
271 	d2.cd_format = CRYPTO_DATA_RAW;
272 	d2.cd_offset = 0;
273 	d2.cd_length = cipher_len;
274 	d2.cd_raw.iov_base = (char *)ciphertext;
275 	d2.cd_raw.iov_len  = cipher_len;
276 
277 
278 	rv = crypto_encrypt(&mech, &d1, &crkey, NULL, &d2, NULL);
279 	if (rv != CRYPTO_SUCCESS)
280 		ieee80211_err("aes_ccm_encrypt failed (%x)", rv);
281 	return (rv);
282 }
283 
284 static int
285 aes_ccm_decrypt(CK_AES_CCM_PARAMS *cmparam, const uint8_t *key, int keylen,
286     const uint8_t *ciphertext, int cipher_len,
287     uint8_t *plaintext, int plain_len)
288 {
289 	crypto_mechanism_t mech;
290 	crypto_key_t crkey;
291 	crypto_data_t d1, d2;
292 
293 	int rv;
294 
295 	ieee80211_dbg(IEEE80211_MSG_CRYPTO,
296 	    "aes_ccm_decrypt(len=%d, keylen=%d)", cipher_len, keylen);
297 
298 	bzero(&crkey, sizeof (crkey));
299 
300 	crkey.ck_format = CRYPTO_KEY_RAW;
301 	crkey.ck_data   = (char *)key;
302 	/* keys are measured in bits, not bytes, so multiply by 8 */
303 	crkey.ck_length = keylen * 8;
304 
305 	mech.cm_type	  = crypto_mech2id(SUN_CKM_AES_CCM);
306 	mech.cm_param	  = (caddr_t)cmparam;
307 	mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
308 
309 #if defined(__amd64) || defined(__sparc)
310 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%lx", mech.cm_type);
311 #else
312 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "cm_type=%llx", mech.cm_type);
313 #endif
314 
315 	bzero(&d1, sizeof (d1));
316 	bzero(&d2, sizeof (d2));
317 
318 	d1.cd_format = CRYPTO_DATA_RAW;
319 	d1.cd_offset = 0;
320 	d1.cd_length = cipher_len;
321 	d1.cd_raw.iov_base = (char *)ciphertext;
322 	d1.cd_raw.iov_len  = cipher_len;
323 
324 	d2.cd_format = CRYPTO_DATA_RAW;
325 	d2.cd_offset = 0;
326 	d2.cd_length = plain_len;
327 	d2.cd_raw.iov_base = (char *)plaintext;
328 	d2.cd_raw.iov_len  = plain_len;
329 
330 
331 	rv = crypto_decrypt(&mech, &d1, &crkey, NULL, &d2, NULL);
332 	if (rv != CRYPTO_SUCCESS)
333 		ieee80211_err("aes_ccm_decrypt failed (%x)", rv);
334 	return (rv);
335 }
336 
337 /*
338  * For the avoidance of doubt, except that if any license choice other
339  * than GPL or LGPL is available it will apply instead, Sun elects to
340  * use only the General Public License version 2 (GPLv2) at this time
341  * for any software where a choice of GPL license versions is made
342  * available with the language indicating that GPLv2 or any later
343  * version may be used, or where a choice of which version of the GPL
344  * is applied is otherwise unspecified.
345  */
346 
347 /*
348  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
349  *
350  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
351  *
352  * This program is free software; you can redistribute it and/or modify
353  * it under the terms of the GNU General Public License version 2 as
354  * published by the Free Software Foundation. See README and COPYING for
355  * more details.
356  *
357  * Alternatively, this software may be distributed under the terms of BSD
358  * license.
359  */
360 
361 static void
362 ccmp_init(struct ieee80211_frame *wh, uint64_t pn, size_t dlen,
363     uint8_t b0[AES_BLOCK_LEN], uint8_t aad[2 * AES_BLOCK_LEN])
364 {
365 	/*
366 	 * CCM Initial Block:
367 	 * Flag (Include authentication header, M=3 (8-octet MIC),
368 	 * L=1 (2-octet Dlen))
369 	 * Nonce: 0x00 | A2 | PN
370 	 * Dlen
371 	 */
372 	b0[0] = 0x59;
373 	/* b0[1] set below */
374 	IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2);
375 	b0[8] = pn >> 40;
376 	b0[9] = pn >> 32;
377 	b0[10] = pn >> 24;
378 	b0[11] = pn >> 16;
379 	b0[12] = pn >> 8;
380 	b0[13] = (uint8_t)(pn >> 0);
381 	b0[14] = (dlen >> 8) & 0xff;
382 	b0[15] = dlen & 0xff;
383 
384 	/*
385 	 * AAD:
386 	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
387 	 * A1 | A2 | A3
388 	 * SC with bits 4..15 (seq#) masked to zero
389 	 * A4 (if present)
390 	 * QC (if present)
391 	 */
392 	aad[0] = 0;	/* AAD length >> 8 */
393 	/* aad[1] set below */
394 	aad[2] = wh->i_fc[0] & 0x8f;	/* magic #s */
395 	aad[3] = wh->i_fc[1] & 0xc7;	/* magic #s */
396 	/* we know 3 addresses are contiguous */
397 	(void) memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
398 	aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
399 	aad[23] = 0; /* all bits masked */
400 	/*
401 	 * Construct variable-length portion of AAD based
402 	 * on whether this is a 4-address frame/QOS frame.
403 	 * We always zero-pad to 32 bytes before running it
404 	 * through the cipher.
405 	 *
406 	 * We also fill in the priority bits of the CCM
407 	 * initial block as we know whether or not we have
408 	 * a QOS frame.
409 	 */
410 	*(uint16_t *)&aad[24] = 0;
411 	b0[1] = 0;
412 	aad[1] = 22;
413 	*(uint16_t *)&aad[26] = 0;
414 	*(uint32_t *)&aad[28] = 0;
415 }
416 
417 static int
418 ccmp_encrypt(struct ieee80211_key *key, mblk_t *mp, int hdrlen)
419 {
420 	struct ieee80211_frame *wh;
421 	int rv, data_len;
422 	uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN];
423 	uint8_t *pos;
424 	CK_AES_CCM_PARAMS cmparam;
425 	uint8_t buf[IEEE80211_MAX_LEN];
426 
427 	wh = (struct ieee80211_frame *)mp->b_rptr;
428 	data_len = (mp->b_wptr - mp->b_rptr) - (hdrlen + ccmp.ic_header);
429 	pos = mp->b_rptr + hdrlen + ccmp.ic_header;
430 
431 	ccmp_init(wh, key->wk_keytsc, data_len, b0, aad);
432 
433 	cmparam.ulMACSize = IEEE80211_WEP_MICLEN;
434 	cmparam.ulNonceSize = AES_NONCE_LEN; /* N size */
435 	cmparam.ulAuthDataSize = aad[1]; /* A size */
436 	cmparam.ulDataSize = data_len;	/* data length; */
437 	cmparam.nonce = &b0[1]; /* N */
438 	cmparam.authData = &aad[2]; /* A */
439 
440 	rv = aes_ccm_encrypt(&cmparam,
441 	    key->wk_key, key->wk_keylen,
442 	    pos, data_len, buf, data_len + IEEE80211_WEP_MICLEN);
443 
444 	bcopy(buf, pos, data_len + IEEE80211_WEP_MICLEN);
445 	mp->b_wptr += ccmp.ic_trailer;
446 
447 	return ((rv == CRYPTO_SUCCESS)? 1 : 0);
448 }
449 
450 static int
451 ccmp_decrypt(struct ieee80211_key *key, uint64_t pn, mblk_t *mp, int hdrlen)
452 {
453 	struct ieee80211_frame *wh;
454 	int rv, data_len;
455 	uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN];
456 	uint8_t *pos;
457 	CK_AES_CCM_PARAMS cmparam;
458 	uint8_t buf[IEEE80211_MAX_LEN];
459 
460 	wh = (struct ieee80211_frame *)mp->b_rptr;
461 	data_len = (mp->b_wptr - mp->b_rptr) - (hdrlen + ccmp.ic_header);
462 	pos = mp->b_rptr + hdrlen + ccmp.ic_header;
463 
464 	ccmp_init(wh, pn, data_len, b0, aad);
465 
466 	cmparam.ulMACSize = IEEE80211_WEP_MICLEN; /* MIC = 8 */
467 	cmparam.ulNonceSize = AES_NONCE_LEN; /* N size */
468 	cmparam.ulAuthDataSize = aad[1]; /* A size */
469 	cmparam.ulDataSize = data_len;
470 	cmparam.nonce = &b0[1]; /* N */
471 	cmparam.authData = &aad[2]; /* A */
472 
473 	rv = aes_ccm_decrypt(&cmparam,
474 	    key->wk_key, key->wk_keylen, pos, data_len, buf, data_len);
475 	bcopy(buf, pos, data_len);
476 
477 	return ((rv == CRYPTO_SUCCESS)? 1 : 0);
478 }
479