1/* 2 * Host AP crypt: host-based CCMP encryption implementation for Host AP driver 3 * 4 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. See README and COPYING for 9 * more details. 10 */ 11 12//#include <linux/config.h> 13#include <linux/version.h> 14#include <linux/module.h> 15#include <linux/init.h> 16#include <linux/slab.h> 17#include <linux/random.h> 18#include <linux/skbuff.h> 19#include <linux/netdevice.h> 20#include <linux/if_ether.h> 21#include <linux/if_arp.h> 22#include <asm/string.h> 23#include <linux/wireless.h> 24 25#include "ieee80211.h" 26 27#include <linux/crypto.h> 28 29 #include <linux/scatterlist.h> 30 31MODULE_AUTHOR("Jouni Malinen"); 32MODULE_DESCRIPTION("Host AP crypt: CCMP"); 33MODULE_LICENSE("GPL"); 34 35#ifndef OPENSUSE_SLED 36#define OPENSUSE_SLED 0 37#endif 38 39#define AES_BLOCK_LEN 16 40#define CCMP_HDR_LEN 8 41#define CCMP_MIC_LEN 8 42#define CCMP_TK_LEN 16 43#define CCMP_PN_LEN 6 44 45struct ieee80211_ccmp_data { 46 u8 key[CCMP_TK_LEN]; 47 int key_set; 48 49 u8 tx_pn[CCMP_PN_LEN]; 50 u8 rx_pn[CCMP_PN_LEN]; 51 52 u32 dot11RSNAStatsCCMPFormatErrors; 53 u32 dot11RSNAStatsCCMPReplays; 54 u32 dot11RSNAStatsCCMPDecryptErrors; 55 56 int key_idx; 57 58 struct crypto_tfm *tfm; 59 60 /* scratch buffers for virt_to_page() (crypto API) */ 61 u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], 62 tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; 63 u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; 64}; 65 66void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, 67 const u8 pt[16], u8 ct[16]) 68{ 69 crypto_cipher_encrypt_one((void*)tfm, ct, pt); 70} 71 72static void * ieee80211_ccmp_init(int key_idx) 73{ 74 struct ieee80211_ccmp_data *priv; 75 76 priv = kzalloc(sizeof(*priv), GFP_ATOMIC); 77 if (priv == NULL) 78 goto fail; 79 priv->key_idx = key_idx; 80 81 priv->tfm = (void*)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); 82 if (IS_ERR(priv->tfm)) { 83 printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " 84 "crypto API aes\n"); 85 priv->tfm = NULL; 86 goto fail; 87 } 88 return priv; 89 90fail: 91 if (priv) { 92 if (priv->tfm) 93 crypto_free_cipher((void*)priv->tfm); 94 kfree(priv); 95 } 96 97 return NULL; 98} 99 100 101static void ieee80211_ccmp_deinit(void *priv) 102{ 103 struct ieee80211_ccmp_data *_priv = priv; 104 if (_priv && _priv->tfm) 105 crypto_free_cipher((void*)_priv->tfm); 106 kfree(priv); 107} 108 109 110static inline void xor_block(u8 *b, u8 *a, size_t len) 111{ 112 int i; 113 for (i = 0; i < len; i++) 114 b[i] ^= a[i]; 115} 116 117 118 119static void ccmp_init_blocks(struct crypto_tfm *tfm, 120 struct ieee80211_hdr_4addr *hdr, 121 u8 *pn, size_t dlen, u8 *b0, u8 *auth, 122 u8 *s0) 123{ 124 u8 *pos, qc = 0; 125 size_t aad_len; 126 u16 fc; 127 int a4_included, qc_included; 128 u8 aad[2 * AES_BLOCK_LEN]; 129 130 fc = le16_to_cpu(hdr->frame_ctl); 131 a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == 132 (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); 133 /* 134 qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && 135 (WLAN_FC_GET_STYPE(fc) & 0x08)); 136 */ 137 // fixed by David :2006.9.6 138 qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && 139 (WLAN_FC_GET_STYPE(fc) & 0x80)); 140 aad_len = 22; 141 if (a4_included) 142 aad_len += 6; 143 if (qc_included) { 144 pos = (u8 *) &hdr->addr4; 145 if (a4_included) 146 pos += 6; 147 qc = *pos & 0x0f; 148 aad_len += 2; 149 } 150 /* CCM Initial Block: 151 * Flag (Include authentication header, M=3 (8-octet MIC), 152 * L=1 (2-octet Dlen)) 153 * Nonce: 0x00 | A2 | PN 154 * Dlen */ 155 b0[0] = 0x59; 156 b0[1] = qc; 157 memcpy(b0 + 2, hdr->addr2, ETH_ALEN); 158 memcpy(b0 + 8, pn, CCMP_PN_LEN); 159 b0[14] = (dlen >> 8) & 0xff; 160 b0[15] = dlen & 0xff; 161 162 /* AAD: 163 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one 164 * A1 | A2 | A3 165 * SC with bits 4..15 (seq#) masked to zero 166 * A4 (if present) 167 * QC (if present) 168 */ 169 pos = (u8 *) hdr; 170 aad[0] = 0; /* aad_len >> 8 */ 171 aad[1] = aad_len & 0xff; 172 aad[2] = pos[0] & 0x8f; 173 aad[3] = pos[1] & 0xc7; 174 memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); 175 pos = (u8 *) &hdr->seq_ctl; 176 aad[22] = pos[0] & 0x0f; 177 aad[23] = 0; /* all bits masked */ 178 memset(aad + 24, 0, 8); 179 if (a4_included) 180 memcpy(aad + 24, hdr->addr4, ETH_ALEN); 181 if (qc_included) { 182 aad[a4_included ? 30 : 24] = qc; 183 /* rest of QC masked */ 184 } 185 186 /* Start with the first block and AAD */ 187 ieee80211_ccmp_aes_encrypt(tfm, b0, auth); 188 xor_block(auth, aad, AES_BLOCK_LEN); 189 ieee80211_ccmp_aes_encrypt(tfm, auth, auth); 190 xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); 191 ieee80211_ccmp_aes_encrypt(tfm, auth, auth); 192 b0[0] &= 0x07; 193 b0[14] = b0[15] = 0; 194 ieee80211_ccmp_aes_encrypt(tfm, b0, s0); 195} 196 197 198 199static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) 200{ 201 struct ieee80211_ccmp_data *key = priv; 202 int data_len, i; 203 u8 *pos; 204 struct ieee80211_hdr_4addr *hdr; 205 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); 206 207 if (skb_headroom(skb) < CCMP_HDR_LEN || 208 skb_tailroom(skb) < CCMP_MIC_LEN || 209 skb->len < hdr_len) 210 return -1; 211 212 data_len = skb->len - hdr_len; 213 pos = skb_push(skb, CCMP_HDR_LEN); 214 memmove(pos, pos + CCMP_HDR_LEN, hdr_len); 215 pos += hdr_len; 216// mic = skb_put(skb, CCMP_MIC_LEN); 217 218 i = CCMP_PN_LEN - 1; 219 while (i >= 0) { 220 key->tx_pn[i]++; 221 if (key->tx_pn[i] != 0) 222 break; 223 i--; 224 } 225 226 *pos++ = key->tx_pn[5]; 227 *pos++ = key->tx_pn[4]; 228 *pos++ = 0; 229 *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; 230 *pos++ = key->tx_pn[3]; 231 *pos++ = key->tx_pn[2]; 232 *pos++ = key->tx_pn[1]; 233 *pos++ = key->tx_pn[0]; 234 235 236 hdr = (struct ieee80211_hdr_4addr *) skb->data; 237 if (!tcb_desc->bHwSec) 238 { 239 int blocks, last, len; 240 u8 *mic; 241 u8 *b0 = key->tx_b0; 242 u8 *b = key->tx_b; 243 u8 *e = key->tx_e; 244 u8 *s0 = key->tx_s0; 245 246 //mic is moved to here by john 247 mic = skb_put(skb, CCMP_MIC_LEN); 248 249 ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); 250 251 blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; 252 last = data_len % AES_BLOCK_LEN; 253 254 for (i = 1; i <= blocks; i++) { 255 len = (i == blocks && last) ? last : AES_BLOCK_LEN; 256 /* Authentication */ 257 xor_block(b, pos, len); 258 ieee80211_ccmp_aes_encrypt(key->tfm, b, b); 259 /* Encryption, with counter */ 260 b0[14] = (i >> 8) & 0xff; 261 b0[15] = i & 0xff; 262 ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); 263 xor_block(pos, e, len); 264 pos += len; 265 } 266 267 for (i = 0; i < CCMP_MIC_LEN; i++) 268 mic[i] = b[i] ^ s0[i]; 269 } 270 return 0; 271} 272 273 274static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) 275{ 276 struct ieee80211_ccmp_data *key = priv; 277 u8 keyidx, *pos; 278 struct ieee80211_hdr_4addr *hdr; 279 cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); 280 u8 pn[6]; 281 282 if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { 283 key->dot11RSNAStatsCCMPFormatErrors++; 284 return -1; 285 } 286 287 hdr = (struct ieee80211_hdr_4addr *) skb->data; 288 pos = skb->data + hdr_len; 289 keyidx = pos[3]; 290 if (!(keyidx & (1 << 5))) { 291 if (net_ratelimit()) { 292 printk(KERN_DEBUG "CCMP: received packet without ExtIV" 293 " flag from %pM\n", hdr->addr2); 294 } 295 key->dot11RSNAStatsCCMPFormatErrors++; 296 return -2; 297 } 298 keyidx >>= 6; 299 if (key->key_idx != keyidx) { 300 printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " 301 "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); 302 return -6; 303 } 304 if (!key->key_set) { 305 if (net_ratelimit()) { 306 printk(KERN_DEBUG "CCMP: received packet from %pM" 307 " with keyid=%d that does not have a configured" 308 " key\n", hdr->addr2, keyidx); 309 } 310 return -3; 311 } 312 313 pn[0] = pos[7]; 314 pn[1] = pos[6]; 315 pn[2] = pos[5]; 316 pn[3] = pos[4]; 317 pn[4] = pos[1]; 318 pn[5] = pos[0]; 319 pos += 8; 320 321 if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { 322 if (net_ratelimit()) { 323 //printk(KERN_DEBUG "CCMP: replay detected: STA=%pM" 324 // " previous PN %pm received PN %pm\n", 325 // hdr->addr2, key->rx_pn, pn); 326 } 327 key->dot11RSNAStatsCCMPReplays++; 328 return -4; 329 } 330 if (!tcb_desc->bHwSec) 331 { 332 size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; 333 u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; 334 u8 *b0 = key->rx_b0; 335 u8 *b = key->rx_b; 336 u8 *a = key->rx_a; 337 int i, blocks, last, len; 338 339 340 ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); 341 xor_block(mic, b, CCMP_MIC_LEN); 342 343 blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; 344 last = data_len % AES_BLOCK_LEN; 345 346 for (i = 1; i <= blocks; i++) { 347 len = (i == blocks && last) ? last : AES_BLOCK_LEN; 348 /* Decrypt, with counter */ 349 b0[14] = (i >> 8) & 0xff; 350 b0[15] = i & 0xff; 351 ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); 352 xor_block(pos, b, len); 353 /* Authentication */ 354 xor_block(a, pos, len); 355 ieee80211_ccmp_aes_encrypt(key->tfm, a, a); 356 pos += len; 357 } 358 359 if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { 360 if (net_ratelimit()) { 361 printk(KERN_DEBUG "CCMP: decrypt failed: STA=" 362 "%pM\n", hdr->addr2); 363 } 364 key->dot11RSNAStatsCCMPDecryptErrors++; 365 return -5; 366 } 367 368 memcpy(key->rx_pn, pn, CCMP_PN_LEN); 369 } 370 /* Remove hdr and MIC */ 371 memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); 372 skb_pull(skb, CCMP_HDR_LEN); 373 skb_trim(skb, skb->len - CCMP_MIC_LEN); 374 375 return keyidx; 376} 377 378 379static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) 380{ 381 struct ieee80211_ccmp_data *data = priv; 382 int keyidx; 383 struct crypto_tfm *tfm = data->tfm; 384 385 keyidx = data->key_idx; 386 memset(data, 0, sizeof(*data)); 387 data->key_idx = keyidx; 388 data->tfm = tfm; 389 if (len == CCMP_TK_LEN) { 390 memcpy(data->key, key, CCMP_TK_LEN); 391 data->key_set = 1; 392 if (seq) { 393 data->rx_pn[0] = seq[5]; 394 data->rx_pn[1] = seq[4]; 395 data->rx_pn[2] = seq[3]; 396 data->rx_pn[3] = seq[2]; 397 data->rx_pn[4] = seq[1]; 398 data->rx_pn[5] = seq[0]; 399 } 400 crypto_cipher_setkey((void*)data->tfm, data->key, CCMP_TK_LEN); 401 } else if (len == 0) 402 data->key_set = 0; 403 else 404 return -1; 405 406 return 0; 407} 408 409 410static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) 411{ 412 struct ieee80211_ccmp_data *data = priv; 413 414 if (len < CCMP_TK_LEN) 415 return -1; 416 417 if (!data->key_set) 418 return 0; 419 memcpy(key, data->key, CCMP_TK_LEN); 420 421 if (seq) { 422 seq[0] = data->tx_pn[5]; 423 seq[1] = data->tx_pn[4]; 424 seq[2] = data->tx_pn[3]; 425 seq[3] = data->tx_pn[2]; 426 seq[4] = data->tx_pn[1]; 427 seq[5] = data->tx_pn[0]; 428 } 429 430 return CCMP_TK_LEN; 431} 432 433 434static char * ieee80211_ccmp_print_stats(char *p, void *priv) 435{ 436 struct ieee80211_ccmp_data *ccmp = priv; 437 int i; 438 439 p += sprintf(p, "key[%d] alg=CCMP key_set=%d tx_pn=", 440 ccmp->key_idx, ccmp->key_set); 441 442 for (i = 0; i < ARRAY_SIZE(ccmp->tx_pn); i++) 443 p += sprintf(p, "%02x", ccmp->tx_pn[i]); 444 445 sprintf(p, " rx_pn="); 446 for (i = 0; i < ARRAY_SIZE(ccmp->rx_pn); i++) 447 p += sprintf(p, "%02x", ccmp->tx_pn[i]); 448 449 p += sprintf(p, " format_errors=%d replays=%d decrypt_errors=%d\n", 450 ccmp->dot11RSNAStatsCCMPFormatErrors, 451 ccmp->dot11RSNAStatsCCMPReplays, 452 ccmp->dot11RSNAStatsCCMPDecryptErrors); 453 454 return p; 455} 456 457void ieee80211_ccmp_null(void) 458{ 459// printk("============>%s()\n", __FUNCTION__); 460 return; 461} 462 463static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { 464 .name = "CCMP", 465 .init = ieee80211_ccmp_init, 466 .deinit = ieee80211_ccmp_deinit, 467 .encrypt_mpdu = ieee80211_ccmp_encrypt, 468 .decrypt_mpdu = ieee80211_ccmp_decrypt, 469 .encrypt_msdu = NULL, 470 .decrypt_msdu = NULL, 471 .set_key = ieee80211_ccmp_set_key, 472 .get_key = ieee80211_ccmp_get_key, 473 .print_stats = ieee80211_ccmp_print_stats, 474 .extra_prefix_len = CCMP_HDR_LEN, 475 .extra_postfix_len = CCMP_MIC_LEN, 476 .owner = THIS_MODULE, 477}; 478 479 480int __init ieee80211_crypto_ccmp_init(void) 481{ 482 return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); 483} 484 485 486void ieee80211_crypto_ccmp_exit(void) 487{ 488 ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); 489} 490