PageRenderTime 26ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/sys/net80211/ieee80211_crypto_ccmp.c

https://bitbucket.org/kmv/aeriebsd-src
C | 465 lines | 358 code | 43 blank | 64 comment | 65 complexity | 7a9dbcafc4b84c7bc6177604f606a0a1 MD5 | raw file
  1. /*-
  2. * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <sys/param.h>
  17. #include <sys/systm.h>
  18. #include <sys/mbuf.h>
  19. #include <sys/malloc.h>
  20. #include <sys/kernel.h>
  21. #include <sys/socket.h>
  22. #include <sys/sockio.h>
  23. #include <sys/endian.h>
  24. #include <net/if.h>
  25. #include <net/if_dl.h>
  26. #include <net/if_media.h>
  27. #include <net/if_arp.h>
  28. #include <net/if_llc.h>
  29. #ifdef INET
  30. #include <netinet/in.h>
  31. #include <netinet/if_ether.h>
  32. #endif
  33. #include <net80211/ieee80211_var.h>
  34. #include <net80211/ieee80211_crypto.h>
  35. #include <crypto/rijndael.h>
  36. /* CCMP software crypto context */
  37. struct ieee80211_ccmp_ctx {
  38. rijndael_ctx rijndael;
  39. };
  40. /*
  41. * Initialize software crypto context. This function can be overridden
  42. * by drivers doing hardware crypto.
  43. */
  44. int
  45. ieee80211_ccmp_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
  46. {
  47. struct ieee80211_ccmp_ctx *ctx;
  48. ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
  49. if (ctx == NULL)
  50. return ENOMEM;
  51. rijndael_set_key_enc_only(&ctx->rijndael, k->k_key, 128);
  52. k->k_priv = ctx;
  53. return 0;
  54. }
  55. void
  56. ieee80211_ccmp_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
  57. {
  58. if (k->k_priv != NULL)
  59. free(k->k_priv, M_DEVBUF);
  60. k->k_priv = NULL;
  61. }
  62. /*-
  63. * Counter with CBC-MAC (CCM) - see RFC3610.
  64. * CCMP uses the following CCM parameters: M = 8, L = 2
  65. */
  66. static void
  67. ieee80211_ccmp_phase1(rijndael_ctx *ctx, const struct ieee80211_frame *wh,
  68. u_int64_t pn, int lm, u_int8_t b[16], u_int8_t a[16], u_int8_t s0[16])
  69. {
  70. u_int8_t auth[32], nonce[13];
  71. u_int8_t *aad;
  72. u_int8_t tid = 0;
  73. int la, i;
  74. /* construct AAD (additional authentication data) */
  75. aad = &auth[2]; /* skip l(a), will be filled later */
  76. *aad = wh->i_fc[0];
  77. /* 11w: conditionnally mask subtype field */
  78. if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
  79. IEEE80211_FC0_TYPE_DATA)
  80. *aad &= ~IEEE80211_FC0_SUBTYPE_MASK;
  81. aad++;
  82. /* protected bit is already set in wh */
  83. *aad = wh->i_fc[1];
  84. *aad &= ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT |
  85. IEEE80211_FC1_MORE_DATA);
  86. /* 11n: conditionnally mask order bit */
  87. if ((wh->i_fc[0] &
  88. (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
  89. (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS))
  90. *aad &= ~IEEE80211_FC1_ORDER;
  91. aad++;
  92. IEEE80211_ADDR_COPY(aad, wh->i_addr1); aad += IEEE80211_ADDR_LEN;
  93. IEEE80211_ADDR_COPY(aad, wh->i_addr2); aad += IEEE80211_ADDR_LEN;
  94. IEEE80211_ADDR_COPY(aad, wh->i_addr3); aad += IEEE80211_ADDR_LEN;
  95. *aad++ = wh->i_seq[0] & ~0xf0;
  96. *aad++ = 0;
  97. if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
  98. IEEE80211_FC1_DIR_DSTODS) {
  99. const struct ieee80211_frame_addr4 *wh4 =
  100. (const struct ieee80211_frame_addr4 *)wh;
  101. IEEE80211_ADDR_COPY(aad, wh4->i_addr4);
  102. aad += IEEE80211_ADDR_LEN;
  103. if ((wh->i_fc[0] &
  104. (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
  105. (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) {
  106. const struct ieee80211_qosframe_addr4 *qwh4 =
  107. (const struct ieee80211_qosframe_addr4 *)wh;
  108. *aad++ = tid = qwh4->i_qos[0] & 0x0f;
  109. *aad++ = 0;
  110. }
  111. } else if ((wh->i_fc[0] &
  112. (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
  113. (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) {
  114. const struct ieee80211_qosframe *qwh =
  115. (const struct ieee80211_qosframe *)wh;
  116. *aad++ = tid = qwh->i_qos[0] & 0x0f;
  117. *aad++ = 0;
  118. }
  119. /* construct CCM nonce */
  120. nonce[ 0] = tid;
  121. if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
  122. IEEE80211_FC0_TYPE_MGT)
  123. nonce[0] |= 1 << 4; /* 11w: set management bit */
  124. IEEE80211_ADDR_COPY(&nonce[1], wh->i_addr2);
  125. nonce[ 7] = pn >> 40; /* PN5 */
  126. nonce[ 8] = pn >> 32; /* PN4 */
  127. nonce[ 9] = pn >> 24; /* PN3 */
  128. nonce[10] = pn >> 16; /* PN2 */
  129. nonce[11] = pn >> 8; /* PN1 */
  130. nonce[12] = pn; /* PN0 */
  131. /* add 2 authentication blocks (including l(a) and padded AAD) */
  132. la = aad - &auth[2]; /* fill l(a) */
  133. auth[0] = la >> 8;
  134. auth[1] = la & 0xff;
  135. memset(aad, 0, 30 - la); /* pad AAD with zeros */
  136. /* construct first block B_0 */
  137. b[ 0] = 89; /* Flags = 64*Adata + 8*((M-2)/2) + (L-1) */
  138. memcpy(&b[1], nonce, 13);
  139. b[14] = lm >> 8;
  140. b[15] = lm & 0xff;
  141. rijndael_encrypt(ctx, b, b);
  142. for (i = 0; i < 16; i++)
  143. b[i] ^= auth[i];
  144. rijndael_encrypt(ctx, b, b);
  145. for (i = 0; i < 16; i++)
  146. b[i] ^= auth[16 + i];
  147. rijndael_encrypt(ctx, b, b);
  148. /* construct S_0 */
  149. a[ 0] = 1; /* Flags = L' = (L-1) */
  150. memcpy(&a[1], nonce, 13);
  151. a[14] = a[15] = 0;
  152. rijndael_encrypt(ctx, a, s0);
  153. }
  154. struct mbuf *
  155. ieee80211_ccmp_encrypt(struct ieee80211com *ic, struct mbuf *m0,
  156. struct ieee80211_key *k)
  157. {
  158. struct ieee80211_ccmp_ctx *ctx = k->k_priv;
  159. const struct ieee80211_frame *wh;
  160. const u_int8_t *src;
  161. u_int8_t *ivp, *mic, *dst;
  162. u_int8_t a[16], b[16], s0[16], s[16];
  163. struct mbuf *n0, *m, *n;
  164. int hdrlen, left, moff, noff, len;
  165. u_int16_t ctr;
  166. int i, j;
  167. MGET(n0, M_DONTWAIT, m0->m_type);
  168. if (n0 == NULL)
  169. goto nospace;
  170. M_DUP_PKTHDR(n0, m0);
  171. n0->m_pkthdr.len += IEEE80211_CCMP_HDRLEN;
  172. n0->m_len = MHLEN;
  173. if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_CCMP_MICLEN) {
  174. MCLGET(n0, M_DONTWAIT);
  175. if (n0->m_flags & M_EXT)
  176. n0->m_len = n0->m_ext.ext_size;
  177. }
  178. if (n0->m_len > n0->m_pkthdr.len)
  179. n0->m_len = n0->m_pkthdr.len;
  180. /* copy 802.11 header */
  181. wh = mtod(m0, struct ieee80211_frame *);
  182. hdrlen = ieee80211_get_hdrlen(wh);
  183. memcpy(mtod(n0, caddr_t), wh, hdrlen);
  184. k->k_tsc++; /* increment the 48-bit PN */
  185. /* construct CCMP header */
  186. ivp = mtod(n0, u_int8_t *) + hdrlen;
  187. ivp[0] = k->k_tsc; /* PN0 */
  188. ivp[1] = k->k_tsc >> 8; /* PN1 */
  189. ivp[2] = 0; /* Rsvd */
  190. ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV; /* KeyID | ExtIV */
  191. ivp[4] = k->k_tsc >> 16; /* PN2 */
  192. ivp[5] = k->k_tsc >> 24; /* PN3 */
  193. ivp[6] = k->k_tsc >> 32; /* PN4 */
  194. ivp[7] = k->k_tsc >> 40; /* PN5 */
  195. /* construct initial B, A and S_0 blocks */
  196. ieee80211_ccmp_phase1(&ctx->rijndael, wh, k->k_tsc,
  197. m0->m_pkthdr.len - hdrlen, b, a, s0);
  198. /* construct S_1 */
  199. ctr = 1;
  200. a[14] = ctr >> 8;
  201. a[15] = ctr & 0xff;
  202. rijndael_encrypt(&ctx->rijndael, a, s);
  203. /* encrypt frame body and compute MIC */
  204. j = 0;
  205. m = m0;
  206. n = n0;
  207. moff = hdrlen;
  208. noff = hdrlen + IEEE80211_CCMP_HDRLEN;
  209. left = m0->m_pkthdr.len - moff;
  210. while (left > 0) {
  211. if (moff == m->m_len) {
  212. /* nothing left to copy from m */
  213. m = m->m_next;
  214. moff = 0;
  215. }
  216. if (noff == n->m_len) {
  217. /* n is full and there's more data to copy */
  218. MGET(n->m_next, M_DONTWAIT, n->m_type);
  219. if (n->m_next == NULL)
  220. goto nospace;
  221. n = n->m_next;
  222. n->m_len = MLEN;
  223. if (left > MLEN - IEEE80211_CCMP_MICLEN) {
  224. MCLGET(n, M_DONTWAIT);
  225. if (n->m_flags & M_EXT)
  226. n->m_len = n->m_ext.ext_size;
  227. }
  228. if (n->m_len > left)
  229. n->m_len = left;
  230. noff = 0;
  231. }
  232. len = min(m->m_len - moff, n->m_len - noff);
  233. src = mtod(m, u_int8_t *) + moff;
  234. dst = mtod(n, u_int8_t *) + noff;
  235. for (i = 0; i < len; i++) {
  236. /* update MIC with clear text */
  237. b[j] ^= src[i];
  238. /* encrypt message */
  239. dst[i] = src[i] ^ s[j];
  240. if (++j < 16)
  241. continue;
  242. /* we have a full block, encrypt MIC */
  243. rijndael_encrypt(&ctx->rijndael, b, b);
  244. /* construct a new S_ctr block */
  245. ctr++;
  246. a[14] = ctr >> 8;
  247. a[15] = ctr & 0xff;
  248. rijndael_encrypt(&ctx->rijndael, a, s);
  249. j = 0;
  250. }
  251. moff += len;
  252. noff += len;
  253. left -= len;
  254. }
  255. if (j != 0) /* partial block, encrypt MIC */
  256. rijndael_encrypt(&ctx->rijndael, b, b);
  257. /* reserve trailing space for MIC */
  258. if (M_TRAILINGSPACE(n) < IEEE80211_CCMP_MICLEN) {
  259. MGET(n->m_next, M_DONTWAIT, n->m_type);
  260. if (n->m_next == NULL)
  261. goto nospace;
  262. n = n->m_next;
  263. n->m_len = 0;
  264. }
  265. /* finalize MIC, U := T XOR first-M-bytes( S_O ) */
  266. mic = mtod(n, u_int8_t *) + n->m_len;
  267. for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
  268. mic[i] = b[i] ^ s0[i];
  269. n->m_len += IEEE80211_CCMP_MICLEN;
  270. n0->m_pkthdr.len += IEEE80211_CCMP_MICLEN;
  271. m_freem(m0);
  272. return n0;
  273. nospace:
  274. ic->ic_stats.is_tx_nombuf++;
  275. m_freem(m0);
  276. if (n0 != NULL)
  277. m_freem(n0);
  278. return NULL;
  279. }
  280. struct mbuf *
  281. ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0,
  282. struct ieee80211_key *k)
  283. {
  284. struct ieee80211_ccmp_ctx *ctx = k->k_priv;
  285. struct ieee80211_frame *wh;
  286. u_int64_t pn;
  287. const u_int8_t *ivp, *src;
  288. u_int8_t *dst;
  289. u_int8_t mic0[IEEE80211_CCMP_MICLEN];
  290. u_int8_t a[16], b[16], s0[16], s[16];
  291. struct mbuf *n0, *m, *n;
  292. int hdrlen, left, moff, noff, len;
  293. u_int16_t ctr;
  294. int i, j;
  295. wh = mtod(m0, struct ieee80211_frame *);
  296. hdrlen = ieee80211_get_hdrlen(wh);
  297. ivp = (u_int8_t *)wh + hdrlen;
  298. if (m0->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN +
  299. IEEE80211_CCMP_MICLEN) {
  300. m_freem(m0);
  301. return NULL;
  302. }
  303. /* check that ExtIV bit is be set */
  304. if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
  305. m_freem(m0);
  306. return NULL;
  307. }
  308. /* extract the 48-bit PN from the CCMP header */
  309. pn = (u_int64_t)ivp[0] |
  310. (u_int64_t)ivp[1] << 8 |
  311. (u_int64_t)ivp[4] << 16 |
  312. (u_int64_t)ivp[5] << 24 |
  313. (u_int64_t)ivp[6] << 32 |
  314. (u_int64_t)ivp[7] << 40;
  315. if (pn <= k->k_rsc[0]) {
  316. /* replayed frame, discard */
  317. m_freem(m0);
  318. return NULL;
  319. }
  320. MGET(n0, M_DONTWAIT, m0->m_type);
  321. if (n0 == NULL)
  322. goto nospace;
  323. M_DUP_PKTHDR(n0, m0);
  324. n0->m_pkthdr.len -= IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN;
  325. n0->m_len = MHLEN;
  326. if (n0->m_pkthdr.len >= MINCLSIZE) {
  327. MCLGET(n0, M_DONTWAIT);
  328. if (n0->m_flags & M_EXT)
  329. n0->m_len = n0->m_ext.ext_size;
  330. }
  331. if (n0->m_len > n0->m_pkthdr.len)
  332. n0->m_len = n0->m_pkthdr.len;
  333. /* construct initial B, A and S_0 blocks */
  334. ieee80211_ccmp_phase1(&ctx->rijndael, wh, pn,
  335. n0->m_pkthdr.len - hdrlen, b, a, s0);
  336. /* copy 802.11 header and clear protected bit */
  337. memcpy(mtod(n0, caddr_t), wh, hdrlen);
  338. wh = mtod(n0, struct ieee80211_frame *);
  339. wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
  340. /* construct S_1 */
  341. ctr = 1;
  342. a[14] = ctr >> 8;
  343. a[15] = ctr & 0xff;
  344. rijndael_encrypt(&ctx->rijndael, a, s);
  345. /* decrypt frame body and compute MIC */
  346. j = 0;
  347. m = m0;
  348. n = n0;
  349. moff = hdrlen + IEEE80211_CCMP_HDRLEN;
  350. noff = hdrlen;
  351. left = n0->m_pkthdr.len - noff;
  352. while (left > 0) {
  353. if (moff == m->m_len) {
  354. /* nothing left to copy from m */
  355. m = m->m_next;
  356. moff = 0;
  357. }
  358. if (noff == n->m_len) {
  359. /* n is full and there's more data to copy */
  360. MGET(n->m_next, M_DONTWAIT, n->m_type);
  361. if (n->m_next == NULL)
  362. goto nospace;
  363. n = n->m_next;
  364. n->m_len = MLEN;
  365. if (left > MLEN) {
  366. MCLGET(n, M_DONTWAIT);
  367. if (n->m_flags & M_EXT)
  368. n->m_len = n->m_ext.ext_size;
  369. }
  370. if (n->m_len > left)
  371. n->m_len = left;
  372. noff = 0;
  373. }
  374. len = min(m->m_len - moff, n->m_len - noff);
  375. src = mtod(m, u_int8_t *) + moff;
  376. dst = mtod(n, u_int8_t *) + noff;
  377. for (i = 0; i < len; i++) {
  378. /* decrypt message */
  379. dst[i] = src[i] ^ s[j];
  380. /* update MIC with clear text */
  381. b[j] ^= dst[i];
  382. if (++j < 16)
  383. continue;
  384. /* we have a full block, encrypt MIC */
  385. rijndael_encrypt(&ctx->rijndael, b, b);
  386. /* construct a new S_ctr block */
  387. ctr++;
  388. a[14] = ctr >> 8;
  389. a[15] = ctr & 0xff;
  390. rijndael_encrypt(&ctx->rijndael, a, s);
  391. j = 0;
  392. }
  393. moff += len;
  394. noff += len;
  395. left -= len;
  396. }
  397. if (j != 0) /* partial block, encrypt MIC */
  398. rijndael_encrypt(&ctx->rijndael, b, b);
  399. /* finalize MIC, U := T XOR first-M-bytes( S_O ) */
  400. for (i = 0; i < IEEE80211_CCMP_MICLEN; i++)
  401. b[i] ^= s0[i];
  402. /* check that it matches the MIC in received frame */
  403. m_copydata(m, moff, IEEE80211_CCMP_MICLEN, mic0);
  404. if (memcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0) {
  405. m_freem(m0);
  406. m_freem(n0);
  407. return NULL;
  408. }
  409. /*
  410. * Update last seen packet number (note that it must be done
  411. * after MIC is validated.)
  412. */
  413. k->k_rsc[0] = pn;
  414. m_freem(m0);
  415. return n0;
  416. nospace:
  417. ic->ic_stats.is_rx_nombuf++;
  418. m_freem(m0);
  419. if (n0 != NULL)
  420. m_freem(n0);
  421. return NULL;
  422. }