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 /*      $NetBSD: ieee80211_crypto_ccmp.c,v 1.19 2020/11/03 15:06:50 mlelstv Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * Alternatively, this software may be distributed under the terms of the
   19  * GNU General Public License ("GPL") version 2 as published by the Free
   20  * Software Foundation.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 #ifdef __FreeBSD__
   36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_crypto_ccmp.c,v 1.7 2005/07/11 03:06:23 sam Exp $");
   37 #endif
   38 #ifdef __NetBSD__
   39 __KERNEL_RCSID(0, "$NetBSD: ieee80211_crypto_ccmp.c,v 1.19 2020/11/03 15:06:50 mlelstv Exp $");
   40 #endif
   41 
   42 /*
   43  * IEEE 802.11i AES-CCMP crypto support.
   44  *
   45  * Part of this module is derived from similar code in the Host
   46  * AP driver. The code is used with the consent of the author and
   47  * its license is included below.
   48  */
   49 #include <sys/param.h>
   50 #include <sys/kernel.h>
   51 #include <sys/kmem.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/systm.h>
   54 
   55 #include <sys/socket.h>
   56 
   57 #include <net/if.h>
   58 #include <net/if_ether.h>
   59 #include <net/if_media.h>
   60 
   61 #include <net80211/ieee80211_var.h>
   62 
   63 #include <crypto/aes/aes.h>
   64 #include <crypto/aes/aes_ccm.h>
   65 #include <crypto/aes/aes_ccm_mbuf.h>
   66 
   67 #define AES_BLOCK_LEN 16
   68 
   69 struct ccmp_ctx {
   70         struct aesenc cc_aes;
   71         struct ieee80211com *cc_ic;     /* for diagnostics */
   72 };
   73 
   74 static  void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
   75 static  void ccmp_detach(struct ieee80211_key *);
   76 static  int ccmp_setkey(struct ieee80211_key *);
   77 static  int ccmp_encap(struct ieee80211_key *k, struct mbuf *, u_int8_t keyid);
   78 static  int ccmp_decap(struct ieee80211_key *, struct mbuf *, int);
   79 static  int ccmp_enmic(struct ieee80211_key *, struct mbuf *, int);
   80 static  int ccmp_demic(struct ieee80211_key *, struct mbuf *, int);
   81 
   82 const struct ieee80211_cipher ieee80211_cipher_ccmp = {
   83         .ic_name        = "AES-CCM",
   84         .ic_cipher      = IEEE80211_CIPHER_AES_CCM,
   85         .ic_header      = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
   86                           IEEE80211_WEP_EXTIVLEN,
   87         .ic_trailer     = IEEE80211_WEP_MICLEN,
   88         .ic_miclen      = 0,
   89         .ic_attach      = ccmp_attach,
   90         .ic_detach      = ccmp_detach,
   91         .ic_setkey      = ccmp_setkey,
   92         .ic_encap       = ccmp_encap,
   93         .ic_decap       = ccmp_decap,
   94         .ic_enmic       = ccmp_enmic,
   95         .ic_demic       = ccmp_demic,
   96 };
   97 
   98 #define ccmp    ieee80211_cipher_ccmp
   99 
  100 static  int ccmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
  101 static  int ccmp_decrypt(struct ieee80211_key *, u_int64_t pn,
  102                 struct mbuf *, int hdrlen);
  103 
  104 static void *
  105 ccmp_attach(struct ieee80211com *ic, struct ieee80211_key *k)
  106 {
  107         struct ccmp_ctx *ctx;
  108 
  109         ctx = kmem_intr_zalloc(sizeof(*ctx), KM_NOSLEEP);
  110         if (ctx == NULL) {
  111                 ic->ic_stats.is_crypto_nomem++;
  112                 return NULL;
  113         }
  114         ctx->cc_ic = ic;
  115         return ctx;
  116 }
  117 
  118 static void
  119 ccmp_detach(struct ieee80211_key *k)
  120 {
  121         struct ccmp_ctx *ctx = k->wk_private;
  122 
  123         kmem_intr_free(ctx, sizeof(*ctx));
  124 }
  125 
  126 static int
  127 ccmp_setkey(struct ieee80211_key *k)
  128 {
  129         struct ccmp_ctx *ctx = k->wk_private;
  130 
  131         if (k->wk_keylen != (128/NBBY)) {
  132                 IEEE80211_DPRINTF(ctx->cc_ic, IEEE80211_MSG_CRYPTO,
  133                         "%s: Invalid key length %u, expecting %u\n",
  134                         __func__, k->wk_keylen, 128/NBBY);
  135                 return 0;
  136         }
  137         if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
  138                 aes_setenckey128(&ctx->cc_aes, k->wk_key);
  139         return 1;
  140 }
  141 
  142 /*
  143  * Add privacy headers appropriate for the specified key.
  144  */
  145 static int
  146 ccmp_encap(struct ieee80211_key *k, struct mbuf *m, u_int8_t keyid)
  147 {
  148         struct ccmp_ctx *ctx = k->wk_private;
  149         struct ieee80211com *ic = ctx->cc_ic;
  150         u_int8_t *ivp;
  151         int hdrlen;
  152 
  153         hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
  154         ivp = mtod(m, u_int8_t *) + hdrlen;
  155 
  156         k->wk_keytsc++;         /* XXX wrap at 48 bits */
  157         ivp[0] = k->wk_keytsc >> 0;             /* PN0 */
  158         ivp[1] = k->wk_keytsc >> 8;             /* PN1 */
  159         ivp[2] = 0;                             /* Reserved */
  160         ivp[3] = keyid | IEEE80211_WEP_EXTIV;   /* KeyID | ExtID */
  161         ivp[4] = k->wk_keytsc >> 16;            /* PN2 */
  162         ivp[5] = k->wk_keytsc >> 24;            /* PN3 */
  163         ivp[6] = k->wk_keytsc >> 32;            /* PN4 */
  164         ivp[7] = k->wk_keytsc >> 40;            /* PN5 */
  165 
  166         /*
  167          * Finally, do software encrypt if neeed.
  168          */
  169         if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
  170             !ccmp_encrypt(k, m, hdrlen))
  171                 return 0;
  172 
  173         return 1;
  174 }
  175 
  176 /*
  177  * Add MIC to the frame as needed.
  178  */
  179 static int
  180 ccmp_enmic(struct ieee80211_key *k, struct mbuf *m,
  181     int force)
  182 {
  183 
  184         return 1;
  185 }
  186 
  187 static __inline uint64_t
  188 READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
  189 {
  190         uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
  191         uint16_t iv16 = (b4 << 0) | (b5 << 8);
  192         return (((uint64_t)iv16) << 32) | iv32;
  193 }
  194 
  195 /*
  196  * Validate and strip privacy headers (and trailer) for a
  197  * received frame. The specified key should be correct but
  198  * is also verified.
  199  */
  200 static int
  201 ccmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
  202 {
  203         struct ccmp_ctx *ctx = k->wk_private;
  204         struct ieee80211_frame *wh;
  205         uint8_t *ivp;
  206         uint64_t pn;
  207 
  208         /*
  209          * Header should have extended IV and sequence number;
  210          * verify the former and validate the latter.
  211          */
  212         wh = mtod(m, struct ieee80211_frame *);
  213         ivp = mtod(m, uint8_t *) + hdrlen;
  214         if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
  215                 /*
  216                  * No extended IV; discard frame.
  217                  */
  218                 IEEE80211_DPRINTF(ctx->cc_ic, IEEE80211_MSG_CRYPTO,
  219                         "[%s] Missing ExtIV for AES-CCM cipher\n",
  220                         ether_sprintf(wh->i_addr2));
  221                 ctx->cc_ic->ic_stats.is_rx_ccmpformat++;
  222                 return 0;
  223         }
  224         pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
  225         if (pn <= k->wk_keyrsc) {
  226                 /*
  227                  * Replay violation.
  228                  */
  229                 ieee80211_notify_replay_failure(ctx->cc_ic, wh, k, pn);
  230                 ctx->cc_ic->ic_stats.is_rx_ccmpreplay++;
  231                 return 0;
  232         }
  233 
  234         /*
  235          * Check if the device handled the decrypt in hardware.
  236          * If so we just strip the header; otherwise we need to
  237          * handle the decrypt in software.  Note that for the
  238          * latter we leave the header in place for use in the
  239          * decryption work.
  240          */
  241         if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) &&
  242             !ccmp_decrypt(k, pn, m, hdrlen))
  243                 return 0;
  244 
  245         /*
  246          * Copy up 802.11 header and strip crypto bits.
  247          */
  248         memmove(mtod(m, u_int8_t *) + ccmp.ic_header, mtod(m, void *), hdrlen);
  249         m_adj(m, ccmp.ic_header);
  250         m_adj(m, -ccmp.ic_trailer);
  251 
  252         /*
  253          * Ok to update rsc now.
  254          */
  255         k->wk_keyrsc = pn;
  256 
  257         return 1;
  258 }
  259 
  260 /*
  261  * Verify and strip MIC from the frame.
  262  */
  263 static int
  264 ccmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
  265 {
  266         return 1;
  267 }
  268 
  269 /*
  270  * Host AP crypt: host-based CCMP encryption implementation for Host AP driver
  271  *
  272  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
  273  *
  274  * This program is free software; you can redistribute it and/or modify
  275  * it under the terms of the GNU General Public License version 2 as
  276  * published by the Free Software Foundation. See README and COPYING for
  277  * more details.
  278  *
  279  * Alternatively, this software may be distributed under the terms of BSD
  280  * license.
  281  */
  282 
  283 static void
  284 ccmp_init_blocks(struct aesenc *ctx, struct ieee80211_frame *wh,
  285     u_int64_t pn, size_t data_len, struct aes_ccm *aes_ccm)
  286 {
  287         uint8_t nonce[13];
  288         uint8_t ad[32];
  289         uint8_t qos;
  290         size_t adlen;
  291 
  292 #define IS_4ADDRESS(wh) \
  293         ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
  294 #define IS_QOS_DATA(wh) ieee80211_has_qos(wh)
  295 
  296         /* nonce[0] is qos, determined later */
  297         IEEE80211_ADDR_COPY(nonce + 1, wh->i_addr2);
  298         nonce[7] = pn >> 40;
  299         nonce[8] = pn >> 32;
  300         nonce[9] = pn >> 24;
  301         nonce[10] = pn >> 16;
  302         nonce[11] = pn >> 8;
  303         nonce[12] = pn >> 0;
  304 
  305         ad[0] = wh->i_fc[0] & 0x8f;     /* XXX magic #s */
  306         ad[1] = wh->i_fc[1] & 0xc7;     /* XXX magic #s */
  307         /* NB: we know 3 addresses are contiguous */
  308         memcpy(ad + 2, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
  309         ad[20] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
  310         ad[21] = 0; /* all bits masked */
  311 
  312         /*
  313          * Construct variable-length portion of AAD based
  314          * on whether this is a 4-address frame/QOS frame.
  315          *
  316          * We also fill in the priority bits of the CCM
  317          * initial block as we know whether or not we have
  318          * a QOS frame.
  319          */
  320         if (IS_4ADDRESS(wh)) {
  321                 IEEE80211_ADDR_COPY(ad + 22,
  322                     ((const struct ieee80211_frame_addr4 *)wh)->i_addr4);
  323                 if (IS_QOS_DATA(wh)) {
  324                         const struct ieee80211_qosframe_addr4 *qwh4 =
  325                             (const struct ieee80211_qosframe_addr4 *)wh;
  326                         qos = qwh4->i_qos[0] & 0x0f; /* just priority bits */
  327                         ad[28] = qos;
  328                         ad[29] = 0;
  329                         adlen = 22 + IEEE80211_ADDR_LEN + 2;
  330                 } else {
  331                         qos = 0;
  332                         adlen = 22 + IEEE80211_ADDR_LEN;
  333                 }
  334         } else {
  335                 if (IS_QOS_DATA(wh)) {
  336                         const struct ieee80211_qosframe *qwh =
  337                             (const struct ieee80211_qosframe *)wh;
  338                         qos = qwh->i_qos[0] & 0x0f; /* just priority bits */
  339                         ad[22] = qos;
  340                         ad[23] = 0;
  341                         adlen = 22 + 2;
  342                 } else {
  343                         qos = 0;
  344                         adlen = 22;
  345                 }
  346         }
  347         nonce[0] = qos;
  348 
  349         aes_ccm_init(aes_ccm, AES_128_NROUNDS, ctx, 2 /* L, counter octets */,
  350             IEEE80211_WEP_MICLEN, nonce, sizeof nonce, ad, adlen, data_len);
  351 
  352 #undef  IS_QOS_DATA
  353 #undef  IS_4ADDRESS
  354 }
  355 
  356 static int
  357 ccmp_encrypt(struct ieee80211_key *key, struct mbuf *m, int hdrlen)
  358 {
  359         struct ccmp_ctx *ctx = key->wk_private;
  360         struct ieee80211_frame *wh;
  361         struct aes_ccm aes_ccm;
  362         size_t data_len;
  363         uint8_t mic[IEEE80211_WEP_MICLEN];
  364 
  365         KASSERT(hdrlen >= 0);
  366         KASSERT(hdrlen < m->m_pkthdr.len);
  367         KASSERT(ccmp.ic_header <= m->m_pkthdr.len - hdrlen);
  368 
  369         ctx->cc_ic->ic_stats.is_crypto_ccmp++;
  370 
  371         wh = mtod(m, struct ieee80211_frame *);
  372         data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header);
  373         ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, data_len, &aes_ccm);
  374         aes_ccm_enc_mbuf(&aes_ccm, m, hdrlen + ccmp.ic_header, data_len, mic);
  375 
  376         return m_append(m, ccmp.ic_trailer, mic);
  377 }
  378 
  379 static int
  380 ccmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m,
  381     int hdrlen)
  382 {
  383         struct ccmp_ctx *ctx = key->wk_private;
  384         struct ieee80211_frame *wh;
  385         struct aes_ccm aes_ccm;
  386         size_t data_len;
  387         uint8_t mic[IEEE80211_WEP_MICLEN];
  388 
  389         KASSERT(hdrlen >= 0);
  390         KASSERT(hdrlen < m->m_pkthdr.len);
  391         KASSERT(ccmp.ic_header < m->m_pkthdr.len - hdrlen);
  392         KASSERT(ccmp.ic_trailer < m->m_pkthdr.len - (hdrlen + ccmp.ic_header));
  393 
  394         ctx->cc_ic->ic_stats.is_crypto_ccmp++;
  395 
  396         wh = mtod(m, struct ieee80211_frame *);
  397         data_len = m->m_pkthdr.len - (hdrlen + ccmp.ic_header + ccmp.ic_trailer);
  398         ccmp_init_blocks(&ctx->cc_aes, wh, pn, data_len, &aes_ccm);
  399         m_copydata(m, m->m_pkthdr.len - ccmp.ic_trailer, ccmp.ic_trailer, mic);
  400 
  401         if (!aes_ccm_dec_mbuf(&aes_ccm, m, hdrlen + ccmp.ic_header, data_len,
  402                 mic)) {
  403                 IEEE80211_DPRINTF(ctx->cc_ic, IEEE80211_MSG_CRYPTO,
  404                     "[%s] AES-CCM decrypt failed; MIC mismatch\n",
  405                     ether_sprintf(wh->i_addr2));
  406                 ctx->cc_ic->ic_stats.is_rx_ccmpmic++;
  407                 return 0;
  408         }
  409 
  410         return 1;
  411 }
  412 
  413 IEEE80211_CRYPTO_SETUP(ccmp_register)
  414 {
  415         ieee80211_crypto_register(&ccmp);
  416 }

Cache object: cd0367c1114c4fe8870537064ef8048e


[ 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.