The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_crypto_ccmp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD: releng/11.0/sys/net80211/ieee80211_crypto_ccmp.c 288526 2015-10-03 00:50:13Z adrian $");
   28 
   29 /*
   30  * IEEE 802.11i AES-CCMP crypto support.
   31  *
   32  * Part of this module is derived from similar code in the Host
   33  * AP driver. The code is used with the consent of the author and
   34  * it's license is included below.
   35  */
   36 #include "opt_wlan.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h> 
   40 #include <sys/mbuf.h>   
   41 #include <sys/malloc.h>
   42 #include <sys/kernel.h>
   43 #include <sys/module.h>
   44 
   45 #include <sys/socket.h>
   46 
   47 #include <net/if.h>
   48 #include <net/if_media.h>
   49 #include <net/ethernet.h>
   50 
   51 #include <net80211/ieee80211_var.h>
   52 
   53 #include <crypto/rijndael/rijndael.h>
   54 
   55 #define AES_BLOCK_LEN 16
   56 
   57 struct ccmp_ctx {
   58         struct ieee80211vap *cc_vap;    /* for diagnostics+statistics */
   59         struct ieee80211com *cc_ic;
   60         rijndael_ctx         cc_aes;
   61 };
   62 
   63 static  void *ccmp_attach(struct ieee80211vap *, struct ieee80211_key *);
   64 static  void ccmp_detach(struct ieee80211_key *);
   65 static  int ccmp_setkey(struct ieee80211_key *);
   66 static  void ccmp_setiv(struct ieee80211_key *, uint8_t *);
   67 static  int ccmp_encap(struct ieee80211_key *, struct mbuf *);
   68 static  int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
   69 static  int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
   70 static  int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
   71 
   72 static const struct ieee80211_cipher ccmp = {
   73         .ic_name        = "AES-CCM",
   74         .ic_cipher      = IEEE80211_CIPHER_AES_CCM,
   75         .ic_header      = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
   76                           IEEE80211_WEP_EXTIVLEN,
   77         .ic_trailer     = IEEE80211_WEP_MICLEN,
   78         .ic_miclen      = 0,
   79         .ic_attach      = ccmp_attach,
   80         .ic_detach      = ccmp_detach,
   81         .ic_setkey      = ccmp_setkey,
   82         .ic_setiv       = ccmp_setiv,
   83         .ic_encap       = ccmp_encap,
   84         .ic_decap       = ccmp_decap,
   85         .ic_enmic       = ccmp_enmic,
   86         .ic_demic       = ccmp_demic,
   87 };
   88 
   89 static  int ccmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
   90 static  int ccmp_decrypt(struct ieee80211_key *, u_int64_t pn,
   91                 struct mbuf *, int hdrlen);
   92 
   93 /* number of references from net80211 layer */
   94 static  int nrefs = 0;
   95 
   96 static void *
   97 ccmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
   98 {
   99         struct ccmp_ctx *ctx;
  100 
  101         ctx = (struct ccmp_ctx *) IEEE80211_MALLOC(sizeof(struct ccmp_ctx),
  102                 M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
  103         if (ctx == NULL) {
  104                 vap->iv_stats.is_crypto_nomem++;
  105                 return NULL;
  106         }
  107         ctx->cc_vap = vap;
  108         ctx->cc_ic = vap->iv_ic;
  109         nrefs++;                        /* NB: we assume caller locking */
  110         return ctx;
  111 }
  112 
  113 static void
  114 ccmp_detach(struct ieee80211_key *k)
  115 {
  116         struct ccmp_ctx *ctx = k->wk_private;
  117 
  118         IEEE80211_FREE(ctx, M_80211_CRYPTO);
  119         KASSERT(nrefs > 0, ("imbalanced attach/detach"));
  120         nrefs--;                        /* NB: we assume caller locking */
  121 }
  122 
  123 static int
  124 ccmp_setkey(struct ieee80211_key *k)
  125 {
  126         struct ccmp_ctx *ctx = k->wk_private;
  127 
  128         if (k->wk_keylen != (128/NBBY)) {
  129                 IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
  130                         "%s: Invalid key length %u, expecting %u\n",
  131                         __func__, k->wk_keylen, 128/NBBY);
  132                 return 0;
  133         }
  134         if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
  135                 rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
  136         return 1;
  137 }
  138 
  139 static void
  140 ccmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
  141 {
  142         struct ccmp_ctx *ctx = k->wk_private;
  143         struct ieee80211vap *vap = ctx->cc_vap;
  144         uint8_t keyid;
  145 
  146         keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
  147 
  148         k->wk_keytsc++;
  149         ivp[0] = k->wk_keytsc >> 0;             /* PN0 */
  150         ivp[1] = k->wk_keytsc >> 8;             /* PN1 */
  151         ivp[2] = 0;                             /* Reserved */
  152         ivp[3] = keyid | IEEE80211_WEP_EXTIV;   /* KeyID | ExtID */
  153         ivp[4] = k->wk_keytsc >> 16;            /* PN2 */
  154         ivp[5] = k->wk_keytsc >> 24;            /* PN3 */
  155         ivp[6] = k->wk_keytsc >> 32;            /* PN4 */
  156         ivp[7] = k->wk_keytsc >> 40;            /* PN5 */
  157 }
  158 
  159 /*
  160  * Add privacy headers appropriate for the specified key.
  161  */
  162 static int
  163 ccmp_encap(struct ieee80211_key *k, struct mbuf *m)
  164 {
  165         struct ccmp_ctx *ctx = k->wk_private;
  166         struct ieee80211com *ic = ctx->cc_ic;
  167         uint8_t *ivp;
  168         int hdrlen;
  169 
  170         hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
  171 
  172         /*
  173          * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
  174          */
  175         M_PREPEND(m, ccmp.ic_header, M_NOWAIT);
  176         if (m == NULL)
  177                 return 0;
  178         ivp = mtod(m, uint8_t *);
  179         ovbcopy(ivp + ccmp.ic_header, ivp, hdrlen);
  180         ivp += hdrlen;
  181 
  182         ccmp_setiv(k, ivp);
  183 
  184         /*
  185          * Finally, do software encrypt if needed.
  186          */
  187         if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
  188             !ccmp_encrypt(k, m, hdrlen))
  189                 return 0;
  190 
  191         return 1;
  192 }
  193 
  194 /*
  195  * Add MIC to the frame as needed.
  196  */
  197 static int
  198 ccmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
  199 {
  200 
  201         return 1;
  202 }
  203 
  204 static __inline uint64_t
  205 READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
  206 {
  207         uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
  208         uint16_t iv16 = (b4 << 0) | (b5 << 8);
  209         return (((uint64_t)iv16) << 32) | iv32;
  210 }
  211 
  212 /*
  213  * Validate and strip privacy headers (and trailer) for a
  214  * received frame. The specified key should be correct but
  215  * is also verified.
  216  */
  217 static int
  218 ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
  219 {
  220         struct ccmp_ctx *ctx = k->wk_private;
  221         struct ieee80211vap *vap = ctx->cc_vap;
  222         struct ieee80211_frame *wh;
  223         uint8_t *ivp, tid;
  224         uint64_t pn;
  225 
  226         /*
  227          * Header should have extended IV and sequence number;
  228          * verify the former and validate the latter.
  229          */
  230         wh = mtod(m, struct ieee80211_frame *);
  231         ivp = mtod(m, uint8_t *) + hdrlen;
  232         if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
  233                 /*
  234                  * No extended IV; discard frame.
  235                  */
  236                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
  237                         "%s", "missing ExtIV for AES-CCM cipher");
  238                 vap->iv_stats.is_rx_ccmpformat++;
  239                 return 0;
  240         }
  241         tid = ieee80211_gettid(wh);
  242         pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
  243         if (pn <= k->wk_keyrsc[tid] &&
  244             (k->wk_flags & IEEE80211_KEY_NOREPLAY) == 0) {
  245                 /*
  246                  * Replay violation.
  247                  */
  248                 ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
  249                 vap->iv_stats.is_rx_ccmpreplay++;
  250                 return 0;
  251         }
  252 
  253         /*
  254          * Check if the device handled the decrypt in hardware.
  255          * If so we just strip the header; otherwise we need to
  256          * handle the decrypt in software.  Note that for the
  257          * latter we leave the header in place for use in the
  258          * decryption work.
  259          */
  260         if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
  261             !ccmp_decrypt(k, pn, m, hdrlen))
  262                 return 0;
  263 
  264         /*
  265          * Copy up 802.11 header and strip crypto bits.
  266          */
  267         ovbcopy(mtod(m, void *), mtod(m, uint8_t *) + ccmp.ic_header, hdrlen);
  268         m_adj(m, ccmp.ic_header);
  269         m_adj(m, -ccmp.ic_trailer);
  270 
  271         /*
  272          * Ok to update rsc now.
  273          */
  274         k->wk_keyrsc[tid] = pn;
  275 
  276         return 1;
  277 }
  278 
  279 /*
  280  * Verify and strip MIC from the frame.
  281  */
  282 static int
  283 ccmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
  284 {
  285         return 1;
  286 }
  287 
  288 static __inline void
  289 xor_block(uint8_t *b, const uint8_t *a, size_t len)
  290 {
  291         int i;
  292         for (i = 0; i < len; i++)
  293                 b[i] ^= a[i];
  294 }
  295 
  296 /*
  297  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
  298  *
  299  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  300  *
  301  * This program is free software; you can redistribute it and/or modify
  302  * it under the terms of the GNU General Public License version 2 as
  303  * published by the Free Software Foundation. See README and COPYING for
  304  * more details.
  305  *
  306  * Alternatively, this software may be distributed under the terms of BSD
  307  * license.
  308  */
  309 
  310 static void
  311 ccmp_init_blocks(rijndael_ctx *ctx, struct ieee80211_frame *wh,
  312         u_int64_t pn, size_t dlen,
  313         uint8_t b0[AES_BLOCK_LEN], uint8_t aad[2 * AES_BLOCK_LEN],
  314         uint8_t auth[AES_BLOCK_LEN], uint8_t s0[AES_BLOCK_LEN])
  315 {
  316 #define IS_QOS_DATA(wh) IEEE80211_QOS_HAS_SEQ(wh)
  317 
  318         /* CCM Initial Block:
  319          * Flag (Include authentication header, M=3 (8-octet MIC),
  320          *       L=1 (2-octet Dlen))
  321          * Nonce: 0x00 | A2 | PN
  322          * Dlen */
  323         b0[0] = 0x59;
  324         /* NB: b0[1] set below */
  325         IEEE80211_ADDR_COPY(b0 + 2, wh->i_addr2);
  326         b0[8] = pn >> 40;
  327         b0[9] = pn >> 32;
  328         b0[10] = pn >> 24;
  329         b0[11] = pn >> 16;
  330         b0[12] = pn >> 8;
  331         b0[13] = pn >> 0;
  332         b0[14] = (dlen >> 8) & 0xff;
  333         b0[15] = dlen & 0xff;
  334 
  335         /* AAD:
  336          * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
  337          * A1 | A2 | A3
  338          * SC with bits 4..15 (seq#) masked to zero
  339          * A4 (if present)
  340          * QC (if present)
  341          */
  342         aad[0] = 0;     /* AAD length >> 8 */
  343         /* NB: aad[1] set below */
  344         aad[2] = wh->i_fc[0] & 0x8f;    /* XXX magic #s */
  345         aad[3] = wh->i_fc[1] & 0xc7;    /* XXX magic #s */
  346         /* NB: we know 3 addresses are contiguous */
  347         memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
  348         aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
  349         aad[23] = 0; /* all bits masked */
  350         /*
  351          * Construct variable-length portion of AAD based
  352          * on whether this is a 4-address frame/QOS frame.
  353          * We always zero-pad to 32 bytes before running it
  354          * through the cipher.
  355          *
  356          * We also fill in the priority bits of the CCM
  357          * initial block as we know whether or not we have
  358          * a QOS frame.
  359          */
  360         if (IEEE80211_IS_DSTODS(wh)) {
  361                 IEEE80211_ADDR_COPY(aad + 24,
  362                         ((struct ieee80211_frame_addr4 *)wh)->i_addr4);
  363                 if (IS_QOS_DATA(wh)) {
  364                         struct ieee80211_qosframe_addr4 *qwh4 =
  365                                 (struct ieee80211_qosframe_addr4 *) wh;
  366                         aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */
  367                         aad[31] = 0;
  368                         b0[1] = aad[30];
  369                         aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
  370                 } else {
  371                         *(uint16_t *)&aad[30] = 0;
  372                         b0[1] = 0;
  373                         aad[1] = 22 + IEEE80211_ADDR_LEN;
  374                 }
  375         } else {
  376                 if (IS_QOS_DATA(wh)) {
  377                         struct ieee80211_qosframe *qwh =
  378                                 (struct ieee80211_qosframe*) wh;
  379                         aad[24] = qwh->i_qos[0] & 0x0f; /* just priority bits */
  380                         aad[25] = 0;
  381                         b0[1] = aad[24];
  382                         aad[1] = 22 + 2;
  383                 } else {
  384                         *(uint16_t *)&aad[24] = 0;
  385                         b0[1] = 0;
  386                         aad[1] = 22;
  387                 }
  388                 *(uint16_t *)&aad[26] = 0;
  389                 *(uint32_t *)&aad[28] = 0;
  390         }
  391 
  392         /* Start with the first block and AAD */
  393         rijndael_encrypt(ctx, b0, auth);
  394         xor_block(auth, aad, AES_BLOCK_LEN);
  395         rijndael_encrypt(ctx, auth, auth);
  396         xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
  397         rijndael_encrypt(ctx, auth, auth);
  398         b0[0] &= 0x07;
  399         b0[14] = b0[15] = 0;
  400         rijndael_encrypt(ctx, b0, s0);
  401 #undef  IS_QOS_DATA
  402 }
  403 
  404 #define CCMP_ENCRYPT(_i, _b, _b0, _pos, _e, _len) do {  \
  405         /* Authentication */                            \
  406         xor_block(_b, _pos, _len);                      \
  407         rijndael_encrypt(&ctx->cc_aes, _b, _b);         \
  408         /* Encryption, with counter */                  \
  409         _b0[14] = (_i >> 8) & 0xff;                     \
  410         _b0[15] = _i & 0xff;                            \
  411         rijndael_encrypt(&ctx->cc_aes, _b0, _e);        \
  412         xor_block(_pos, _e, _len);                      \
  413 } while (0)
  414 
  415 static int
  416 ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
  417 {
  418         struct ccmp_ctx *ctx = key->wk_private;
  419         struct ieee80211_frame *wh;
  420         struct mbuf *m = m0;
  421         int data_len, i, space;
  422         uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN],
  423                 e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN];
  424         uint8_t *pos;
  425 
  426         ctx->cc_vap->iv_stats.is_crypto_ccmp++;
  427 
  428         wh = mtod(m, struct ieee80211_frame *);
  429         data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header);
  430         ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc,
  431                 data_len, b0, aad, b, s0);
  432 
  433         i = 1;
  434         pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
  435         /* NB: assumes header is entirely in first mbuf */
  436         space = m->m_len - (hdrlen + ccmp.ic_header);
  437         for (;;) {
  438                 if (space > data_len)
  439                         space = data_len;
  440                 /*
  441                  * Do full blocks.
  442                  */
  443                 while (space >= AES_BLOCK_LEN) {
  444                         CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN);
  445                         pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
  446                         data_len -= AES_BLOCK_LEN;
  447                         i++;
  448                 }
  449                 if (data_len <= 0)              /* no more data */
  450                         break;
  451                 m = m->m_next;
  452                 if (m == NULL) {                /* last buffer */
  453                         if (space != 0) {
  454                                 /*
  455                                  * Short last block.
  456                                  */
  457                                 CCMP_ENCRYPT(i, b, b0, pos, e, space);
  458                         }
  459                         break;
  460                 }
  461                 if (space != 0) {
  462                         uint8_t *pos_next;
  463                         int space_next;
  464                         int len, dl, sp;
  465                         struct mbuf *n;
  466 
  467                         /*
  468                          * Block straddles one or more mbufs, gather data
  469                          * into the block buffer b, apply the cipher, then
  470                          * scatter the results back into the mbuf chain.
  471                          * The buffer will automatically get space bytes
  472                          * of data at offset 0 copied in+out by the
  473                          * CCMP_ENCRYPT request so we must take care of
  474                          * the remaining data.
  475                          */
  476                         n = m;
  477                         dl = data_len;
  478                         sp = space;
  479                         for (;;) {
  480                                 pos_next = mtod(n, uint8_t *);
  481                                 len = min(dl, AES_BLOCK_LEN);
  482                                 space_next = len > sp ? len - sp : 0;
  483                                 if (n->m_len >= space_next) {
  484                                         /*
  485                                          * This mbuf has enough data; just grab
  486                                          * what we need and stop.
  487                                          */
  488                                         xor_block(b+sp, pos_next, space_next);
  489                                         break;
  490                                 }
  491                                 /*
  492                                  * This mbuf's contents are insufficient,
  493                                  * take 'em all and prepare to advance to
  494                                  * the next mbuf.
  495                                  */
  496                                 xor_block(b+sp, pos_next, n->m_len);
  497                                 sp += n->m_len, dl -= n->m_len;
  498                                 n = n->m_next;
  499                                 if (n == NULL)
  500                                         break;
  501                         }
  502 
  503                         CCMP_ENCRYPT(i, b, b0, pos, e, space);
  504 
  505                         /* NB: just like above, but scatter data to mbufs */
  506                         dl = data_len;
  507                         sp = space;
  508                         for (;;) {
  509                                 pos_next = mtod(m, uint8_t *);
  510                                 len = min(dl, AES_BLOCK_LEN);
  511                                 space_next = len > sp ? len - sp : 0;
  512                                 if (m->m_len >= space_next) {
  513                                         xor_block(pos_next, e+sp, space_next);
  514                                         break;
  515                                 }
  516                                 xor_block(pos_next, e+sp, m->m_len);
  517                                 sp += m->m_len, dl -= m->m_len;
  518                                 m = m->m_next;
  519                                 if (m == NULL)
  520                                         goto done;
  521                         }
  522                         /*
  523                          * Do bookkeeping.  m now points to the last mbuf
  524                          * we grabbed data from.  We know we consumed a
  525                          * full block of data as otherwise we'd have hit
  526                          * the end of the mbuf chain, so deduct from data_len.
  527                          * Otherwise advance the block number (i) and setup
  528                          * pos+space to reflect contents of the new mbuf.
  529                          */
  530                         data_len -= AES_BLOCK_LEN;
  531                         i++;
  532                         pos = pos_next + space_next;
  533                         space = m->m_len - space_next;
  534                 } else {
  535                         /*
  536                          * Setup for next buffer.
  537                          */
  538                         pos = mtod(m, uint8_t *);
  539                         space = m->m_len;
  540                 }
  541         }
  542 done:
  543         /* tack on MIC */
  544         xor_block(b, s0, ccmp.ic_trailer);
  545         return m_append(m0, ccmp.ic_trailer, b);
  546 }
  547 #undef CCMP_ENCRYPT
  548 
  549 #define CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) do {  \
  550         /* Decrypt, with counter */                     \
  551         _b0[14] = (_i >> 8) & 0xff;                     \
  552         _b0[15] = _i & 0xff;                            \
  553         rijndael_encrypt(&ctx->cc_aes, _b0, _b);        \
  554         xor_block(_pos, _b, _len);                      \
  555         /* Authentication */                            \
  556         xor_block(_a, _pos, _len);                      \
  557         rijndael_encrypt(&ctx->cc_aes, _a, _a);         \
  558 } while (0)
  559 
  560 static int
  561 ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m, int hdrlen)
  562 {
  563         struct ccmp_ctx *ctx = key->wk_private;
  564         struct ieee80211vap *vap = ctx->cc_vap;
  565         struct ieee80211_frame *wh;
  566         uint8_t aad[2 * AES_BLOCK_LEN];
  567         uint8_t b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN];
  568         uint8_t mic[AES_BLOCK_LEN];
  569         size_t data_len;
  570         int i;
  571         uint8_t *pos;
  572         u_int space;
  573 
  574         ctx->cc_vap->iv_stats.is_crypto_ccmp++;
  575 
  576         wh = mtod(m, struct ieee80211_frame *);
  577         data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header + ccmp.ic_trailer);
  578         ccmp_init_blocks(&ctx->cc_aes, wh, pn, data_len, b0, aad, a, b);
  579         m_copydata(m, m->m_pkthdr.len - ccmp.ic_trailer, ccmp.ic_trailer, mic);
  580         xor_block(mic, b, ccmp.ic_trailer);
  581 
  582         i = 1;
  583         pos = mtod(m, uint8_t *) + hdrlen + ccmp.ic_header;
  584         space = m->m_len - (hdrlen + ccmp.ic_header);
  585         for (;;) {
  586                 if (space > data_len)
  587                         space = data_len;
  588                 while (space >= AES_BLOCK_LEN) {
  589                         CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN);
  590                         pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
  591                         data_len -= AES_BLOCK_LEN;
  592                         i++;
  593                 }
  594                 if (data_len <= 0)              /* no more data */
  595                         break;
  596                 m = m->m_next;
  597                 if (m == NULL) {                /* last buffer */
  598                         if (space != 0)         /* short last block */
  599                                 CCMP_DECRYPT(i, b, b0, pos, a, space);
  600                         break;
  601                 }
  602                 if (space != 0) {
  603                         uint8_t *pos_next;
  604                         u_int space_next;
  605                         u_int len;
  606 
  607                         /*
  608                          * Block straddles buffers, split references.  We
  609                          * do not handle splits that require >2 buffers
  610                          * since rx'd frames are never badly fragmented
  611                          * because drivers typically recv in clusters.
  612                          */
  613                         pos_next = mtod(m, uint8_t *);
  614                         len = min(data_len, AES_BLOCK_LEN);
  615                         space_next = len > space ? len - space : 0;
  616                         KASSERT(m->m_len >= space_next,
  617                                 ("not enough data in following buffer, "
  618                                 "m_len %u need %u\n", m->m_len, space_next));
  619 
  620                         xor_block(b+space, pos_next, space_next);
  621                         CCMP_DECRYPT(i, b, b0, pos, a, space);
  622                         xor_block(pos_next, b+space, space_next);
  623                         data_len -= len;
  624                         i++;
  625 
  626                         pos = pos_next + space_next;
  627                         space = m->m_len - space_next;
  628                 } else {
  629                         /*
  630                          * Setup for next buffer.
  631                          */
  632                         pos = mtod(m, uint8_t *);
  633                         space = m->m_len;
  634                 }
  635         }
  636         if (memcmp(mic, a, ccmp.ic_trailer) != 0) {
  637                 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
  638                     "%s", "AES-CCM decrypt failed; MIC mismatch");
  639                 vap->iv_stats.is_rx_ccmpmic++;
  640                 return 0;
  641         }
  642         return 1;
  643 }
  644 #undef CCMP_DECRYPT
  645 
  646 /*
  647  * Module glue.
  648  */
  649 IEEE80211_CRYPTO_MODULE(ccmp, 1);

Cache object: cb2d645d0f0f43f90f49de9a4e887dbc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.