ieee80211_crypto_ccmp.c 12 KB

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