LCOV - code coverage report
Current view: top level - net80211 - ieee80211_crypto_wep.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 156 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: ieee80211_crypto_wep.c,v 1.16 2017/06/03 11:58:10 tb Exp $    */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * This code implements Wired Equivalent Privacy (WEP) defined in
      21             :  * IEEE Std 802.11-2007 section 8.2.1.
      22             :  */
      23             : 
      24             : #include <sys/param.h>
      25             : #include <sys/systm.h>
      26             : #include <sys/mbuf.h>
      27             : #include <sys/malloc.h>
      28             : #include <sys/kernel.h>
      29             : #include <sys/socket.h>
      30             : #include <sys/endian.h>
      31             : 
      32             : #include <net/if.h>
      33             : #include <net/if_dl.h>
      34             : #include <net/if_media.h>
      35             : 
      36             : #include <netinet/in.h>
      37             : #include <netinet/if_ether.h>
      38             : 
      39             : #include <net80211/ieee80211_var.h>
      40             : #include <net80211/ieee80211_crypto.h>
      41             : 
      42             : #include <crypto/arc4.h>
      43             : 
      44             : /* WEP software crypto context */
      45             : struct ieee80211_wep_ctx {
      46             :         struct rc4_ctx  rc4;
      47             :         u_int32_t       iv;
      48             : };
      49             : 
      50             : /*
      51             :  * Initialize software crypto context.  This function can be overridden
      52             :  * by drivers doing hardware crypto.
      53             :  */
      54             : int
      55           0 : ieee80211_wep_set_key(struct ieee80211com *ic, struct ieee80211_key *k)
      56             : {
      57             :         struct ieee80211_wep_ctx *ctx;
      58             : 
      59           0 :         ctx = malloc(sizeof(*ctx), M_DEVBUF, M_NOWAIT | M_ZERO);
      60           0 :         if (ctx == NULL)
      61           0 :                 return ENOMEM;
      62           0 :         k->k_priv = ctx;
      63           0 :         return 0;
      64           0 : }
      65             : 
      66             : void
      67           0 : ieee80211_wep_delete_key(struct ieee80211com *ic, struct ieee80211_key *k)
      68             : {
      69           0 :         if (k->k_priv != NULL) {
      70           0 :                 explicit_bzero(k->k_priv, sizeof(struct ieee80211_wep_ctx));
      71           0 :                 free(k->k_priv, M_DEVBUF, sizeof(struct ieee80211_wep_ctx));
      72           0 :         }
      73           0 :         k->k_priv = NULL;
      74           0 : }
      75             : 
      76             : /* shortcut */
      77             : #define IEEE80211_WEP_HDRLEN    \
      78             :         (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
      79             : 
      80             : struct mbuf *
      81           0 : ieee80211_wep_encrypt(struct ieee80211com *ic, struct mbuf *m0,
      82             :     struct ieee80211_key *k)
      83             : {
      84           0 :         struct ieee80211_wep_ctx *ctx = k->k_priv;
      85           0 :         u_int8_t wepseed[16];
      86             :         const struct ieee80211_frame *wh;
      87             :         struct mbuf *n0, *m, *n;
      88             :         u_int8_t *ivp, *icvp;
      89             :         u_int32_t iv, crc;
      90             :         int left, moff, noff, len, hdrlen;
      91             : 
      92           0 :         MGET(n0, M_DONTWAIT, m0->m_type);
      93           0 :         if (n0 == NULL)
      94             :                 goto nospace;
      95           0 :         if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
      96             :                 goto nospace;
      97           0 :         n0->m_pkthdr.len += IEEE80211_WEP_HDRLEN;
      98           0 :         n0->m_len = MHLEN;
      99           0 :         if (n0->m_pkthdr.len >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
     100           0 :                 MCLGET(n0, M_DONTWAIT);
     101           0 :                 if (n0->m_flags & M_EXT)
     102           0 :                         n0->m_len = n0->m_ext.ext_size;
     103             :         }
     104           0 :         if (n0->m_len > n0->m_pkthdr.len)
     105           0 :                 n0->m_len = n0->m_pkthdr.len;
     106             : 
     107             :         /* copy 802.11 header */
     108           0 :         wh = mtod(m0, struct ieee80211_frame *);
     109           0 :         hdrlen = ieee80211_get_hdrlen(wh);
     110           0 :         memcpy(mtod(n0, caddr_t), wh, hdrlen);
     111             : 
     112             :         /* select a new IV for every MPDU */
     113           0 :         iv = (ctx->iv != 0) ? ctx->iv : arc4random();
     114             :         /* skip weak IVs from Fluhrer/Mantin/Shamir */
     115           0 :         if (iv >= 0x03ff00 && (iv & 0xf8ff00) == 0x00ff00)
     116           0 :                 iv += 0x000100;
     117           0 :         ctx->iv = iv + 1;
     118           0 :         ivp = mtod(n0, u_int8_t *) + hdrlen;
     119           0 :         ivp[0] = iv;
     120           0 :         ivp[1] = iv >> 8;
     121           0 :         ivp[2] = iv >> 16;
     122           0 :         ivp[3] = k->k_id << 6;
     123             : 
     124             :         /* compute WEP seed: concatenate IV and WEP Key */
     125           0 :         memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
     126           0 :         memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
     127           0 :         rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
     128           0 :         explicit_bzero(wepseed, sizeof(wepseed));
     129             : 
     130             :         /* encrypt frame body and compute WEP ICV */
     131             :         m = m0;
     132             :         n = n0;
     133             :         moff = hdrlen;
     134           0 :         noff = hdrlen + IEEE80211_WEP_HDRLEN;
     135           0 :         left = m0->m_pkthdr.len - moff;
     136             :         crc = ~0;
     137           0 :         while (left > 0) {
     138           0 :                 if (moff == m->m_len) {
     139             :                         /* nothing left to copy from m */
     140           0 :                         m = m->m_next;
     141             :                         moff = 0;
     142           0 :                 }
     143           0 :                 if (noff == n->m_len) {
     144             :                         /* n is full and there's more data to copy */
     145           0 :                         MGET(n->m_next, M_DONTWAIT, n->m_type);
     146           0 :                         if (n->m_next == NULL)
     147             :                                 goto nospace;
     148             :                         n = n->m_next;
     149           0 :                         n->m_len = MLEN;
     150           0 :                         if (left >= MINCLSIZE - IEEE80211_WEP_CRCLEN) {
     151           0 :                                 MCLGET(n, M_DONTWAIT);
     152           0 :                                 if (n->m_flags & M_EXT)
     153           0 :                                         n->m_len = n->m_ext.ext_size;
     154             :                         }
     155           0 :                         if (n->m_len > left)
     156           0 :                                 n->m_len = left;
     157             :                         noff = 0;
     158           0 :                 }
     159           0 :                 len = min(m->m_len - moff, n->m_len - noff);
     160             : 
     161           0 :                 crc = ether_crc32_le_update(crc, mtod(m, caddr_t) + moff, len);
     162           0 :                 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
     163           0 :                     mtod(n, caddr_t) + noff, len);
     164             : 
     165           0 :                 moff += len;
     166           0 :                 noff += len;
     167           0 :                 left -= len;
     168             :         }
     169             : 
     170             :         /* reserve trailing space for WEP ICV */
     171           0 :         if (M_TRAILINGSPACE(n) < IEEE80211_WEP_CRCLEN) {
     172           0 :                 MGET(n->m_next, M_DONTWAIT, n->m_type);
     173           0 :                 if (n->m_next == NULL)
     174             :                         goto nospace;
     175             :                 n = n->m_next;
     176           0 :                 n->m_len = 0;
     177           0 :         }
     178             : 
     179             :         /* finalize WEP ICV */
     180           0 :         icvp = mtod(n, caddr_t) + n->m_len;
     181           0 :         crc = ~crc;
     182           0 :         icvp[0] = crc;
     183           0 :         icvp[1] = crc >> 8;
     184           0 :         icvp[2] = crc >> 16;
     185           0 :         icvp[3] = crc >> 24;
     186           0 :         rc4_crypt(&ctx->rc4, icvp, icvp, IEEE80211_WEP_CRCLEN);
     187           0 :         n->m_len += IEEE80211_WEP_CRCLEN;
     188           0 :         n0->m_pkthdr.len += IEEE80211_WEP_CRCLEN;
     189             : 
     190           0 :         m_freem(m0);
     191           0 :         return n0;
     192             :  nospace:
     193           0 :         ic->ic_stats.is_tx_nombuf++;
     194           0 :         m_freem(m0);
     195           0 :         m_freem(n0);
     196           0 :         return NULL;
     197           0 : }
     198             : 
     199             : struct mbuf *
     200           0 : ieee80211_wep_decrypt(struct ieee80211com *ic, struct mbuf *m0,
     201             :     struct ieee80211_key *k)
     202             : {
     203           0 :         struct ieee80211_wep_ctx *ctx = k->k_priv;
     204             :         struct ieee80211_frame *wh;
     205           0 :         u_int8_t wepseed[16];
     206           0 :         u_int32_t crc, crc0;
     207             :         u_int8_t *ivp;
     208             :         struct mbuf *n0, *m, *n;
     209             :         int hdrlen, left, moff, noff, len;
     210             : 
     211           0 :         wh = mtod(m0, struct ieee80211_frame *);
     212           0 :         hdrlen = ieee80211_get_hdrlen(wh);
     213             : 
     214           0 :         if (m0->m_pkthdr.len < hdrlen + IEEE80211_WEP_TOTLEN) {
     215           0 :                 m_freem(m0);
     216           0 :                 return NULL;
     217             :         }
     218             : 
     219             :         /* concatenate IV and WEP Key */
     220           0 :         ivp = (u_int8_t *)wh + hdrlen;
     221           0 :         memcpy(wepseed, ivp, IEEE80211_WEP_IVLEN);
     222           0 :         memcpy(wepseed + IEEE80211_WEP_IVLEN, k->k_key, k->k_len);
     223           0 :         rc4_keysetup(&ctx->rc4, wepseed, IEEE80211_WEP_IVLEN + k->k_len);
     224           0 :         explicit_bzero(wepseed, sizeof(wepseed));
     225             : 
     226           0 :         MGET(n0, M_DONTWAIT, m0->m_type);
     227           0 :         if (n0 == NULL)
     228             :                 goto nospace;
     229           0 :         if (m_dup_pkthdr(n0, m0, M_DONTWAIT))
     230             :                 goto nospace;
     231           0 :         n0->m_pkthdr.len -= IEEE80211_WEP_TOTLEN;
     232           0 :         n0->m_len = MHLEN;
     233           0 :         if (n0->m_pkthdr.len >= MINCLSIZE) {
     234           0 :                 MCLGET(n0, M_DONTWAIT);
     235           0 :                 if (n0->m_flags & M_EXT)
     236           0 :                         n0->m_len = n0->m_ext.ext_size;
     237             :         }
     238           0 :         if (n0->m_len > n0->m_pkthdr.len)
     239           0 :                 n0->m_len = n0->m_pkthdr.len;
     240             : 
     241             :         /* copy 802.11 header and clear protected bit */
     242           0 :         memcpy(mtod(n0, caddr_t), wh, hdrlen);
     243           0 :         wh = mtod(n0, struct ieee80211_frame *);
     244           0 :         wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
     245             : 
     246             :         /* decrypt frame body and compute WEP ICV */
     247             :         m = m0;
     248             :         n = n0;
     249           0 :         moff = hdrlen + IEEE80211_WEP_HDRLEN;
     250             :         noff = hdrlen;
     251           0 :         left = n0->m_pkthdr.len - noff;
     252             :         crc = ~0;
     253           0 :         while (left > 0) {
     254           0 :                 if (moff == m->m_len) {
     255             :                         /* nothing left to copy from m */
     256           0 :                         m = m->m_next;
     257             :                         moff = 0;
     258           0 :                 }
     259           0 :                 if (noff == n->m_len) {
     260             :                         /* n is full and there's more data to copy */
     261           0 :                         MGET(n->m_next, M_DONTWAIT, n->m_type);
     262           0 :                         if (n->m_next == NULL)
     263             :                                 goto nospace;
     264             :                         n = n->m_next;
     265           0 :                         n->m_len = MLEN;
     266           0 :                         if (left >= MINCLSIZE) {
     267           0 :                                 MCLGET(n, M_DONTWAIT);
     268           0 :                                 if (n->m_flags & M_EXT)
     269           0 :                                         n->m_len = n->m_ext.ext_size;
     270             :                         }
     271           0 :                         if (n->m_len > left)
     272           0 :                                 n->m_len = left;
     273             :                         noff = 0;
     274           0 :                 }
     275           0 :                 len = min(m->m_len - moff, n->m_len - noff);
     276             : 
     277           0 :                 rc4_crypt(&ctx->rc4, mtod(m, caddr_t) + moff,
     278           0 :                     mtod(n, caddr_t) + noff, len);
     279           0 :                 crc = ether_crc32_le_update(crc, mtod(n, caddr_t) + noff, len);
     280             : 
     281           0 :                 moff += len;
     282           0 :                 noff += len;
     283           0 :                 left -= len;
     284             :         }
     285             : 
     286             :         /* decrypt ICV and compare it with calculated ICV */
     287           0 :         m_copydata(m, moff, IEEE80211_WEP_CRCLEN, (caddr_t)&crc0);
     288           0 :         rc4_crypt(&ctx->rc4, (caddr_t)&crc0, (caddr_t)&crc0,
     289             :             IEEE80211_WEP_CRCLEN);
     290           0 :         crc = ~crc;
     291           0 :         if (crc != letoh32(crc0)) {
     292           0 :                 ic->ic_stats.is_rx_decryptcrc++;
     293           0 :                 m_freem(m0);
     294           0 :                 m_freem(n0);
     295           0 :                 return NULL;
     296             :         }
     297             : 
     298           0 :         m_freem(m0);
     299           0 :         return n0;
     300             :  nospace:
     301           0 :         ic->ic_stats.is_rx_nombuf++;
     302           0 :         m_freem(m0);
     303           0 :         m_freem(n0);
     304           0 :         return NULL;
     305           0 : }

Generated by: LCOV version 1.13