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