net80211_crypto_ccmp.c revision a399b7655a1d835aa8606c2b29e4e777baac8635
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Use is subject to license terms.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copyright (c) 2001 Atsushi Onoe
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
a399b7655a1d835aa8606c2b29e4e777baac8635zf * All rights reserved.
a399b7655a1d835aa8606c2b29e4e777baac8635zf *
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Redistribution and use in source and binary forms, with or without
a399b7655a1d835aa8606c2b29e4e777baac8635zf * modification, are permitted provided that the following conditions
a399b7655a1d835aa8606c2b29e4e777baac8635zf * are met:
a399b7655a1d835aa8606c2b29e4e777baac8635zf * 1. Redistributions of source code must retain the above copyright
a399b7655a1d835aa8606c2b29e4e777baac8635zf * notice, this list of conditions and the following disclaimer.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * 2. Redistributions in binary form must reproduce the above copyright
a399b7655a1d835aa8606c2b29e4e777baac8635zf * notice, this list of conditions and the following disclaimer in the
a399b7655a1d835aa8606c2b29e4e777baac8635zf * documentation and/or other materials provided with the distribution.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * 3. The name of the author may not be used to endorse or promote products
a399b7655a1d835aa8606c2b29e4e777baac8635zf * derived from this software without specific prior written permission.
a399b7655a1d835aa8606c2b29e4e777baac8635zf *
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Alternatively, this software may be distributed under the terms of the
a399b7655a1d835aa8606c2b29e4e777baac8635zf * GNU General Public License ("GPL") version 2 as published by the Free
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Software Foundation.
a399b7655a1d835aa8606c2b29e4e777baac8635zf *
a399b7655a1d835aa8606c2b29e4e777baac8635zf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
a399b7655a1d835aa8606c2b29e4e777baac8635zf * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
a399b7655a1d835aa8606c2b29e4e777baac8635zf * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
a399b7655a1d835aa8606c2b29e4e777baac8635zf * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
a399b7655a1d835aa8606c2b29e4e777baac8635zf * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
a399b7655a1d835aa8606c2b29e4e777baac8635zf * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
a399b7655a1d835aa8606c2b29e4e777baac8635zf * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
a399b7655a1d835aa8606c2b29e4e777baac8635zf * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
a399b7655a1d835aa8606c2b29e4e777baac8635zf * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
a399b7655a1d835aa8606c2b29e4e777baac8635zf * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf#pragma ident "%Z%%M% %I% %E% SMI"
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * IEEE 802.11i CCMP crypto support.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/byteorder.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/crypto/common.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/crypto/api.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/crc32.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include <sys/random.h>
a399b7655a1d835aa8606c2b29e4e777baac8635zf#include "net80211_impl.h"
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstruct ccmp_ctx {
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct ieee80211com *cc_ic; /* for diagnostics */
a399b7655a1d835aa8606c2b29e4e777baac8635zf};
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void ccmp_detach(struct ieee80211_key *);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int ccmp_setkey(struct ieee80211_key *);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int ccmp_encap(struct ieee80211_key *k, mblk_t *, uint8_t);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int ccmp_decap(struct ieee80211_key *, mblk_t *, int);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int ccmp_enmic(struct ieee80211_key *, mblk_t *, int);
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int ccmp_demic(struct ieee80211_key *, mblk_t *, int);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfconst struct ieee80211_cipher ccmp = {
a399b7655a1d835aa8606c2b29e4e777baac8635zf "AES-CCM",
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_CIPHER_AES_CCM,
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_WEP_EXTIVLEN,
a399b7655a1d835aa8606c2b29e4e777baac8635zf IEEE80211_WEP_MICLEN,
a399b7655a1d835aa8606c2b29e4e777baac8635zf 0,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_attach,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_detach,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_setkey,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_encap,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_decap,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_enmic,
a399b7655a1d835aa8606c2b29e4e777baac8635zf ccmp_demic,
a399b7655a1d835aa8606c2b29e4e777baac8635zf};
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/* ARGSUSED */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void *
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_attach(struct ieee80211com *ic, struct ieee80211_key *k)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct ccmp_ctx *ctx;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf ctx = kmem_zalloc(sizeof (struct ccmp_ctx), KM_SLEEP);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (ctx == NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (NULL);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf ctx->cc_ic = ic;
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (ctx);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic void
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_detach(struct ieee80211_key *k)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct ccmp_ctx *ctx = k->wk_private;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (ctx != NULL)
a399b7655a1d835aa8606c2b29e4e777baac8635zf kmem_free(ctx, sizeof (struct ccmp_ctx));
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_setkey(struct ieee80211_key *k)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (k->wk_keylen != (128/NBBY))
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Add privacy headers appropriate for the specified key.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint8_t *ivp;
a399b7655a1d835aa8606c2b29e4e777baac8635zf int hdrlen;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf hdrlen = ieee80211_hdrspace(mp->b_rptr);
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp = mp->b_rptr;
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp += hdrlen;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf k->wk_keytsc++; /* wrap at 48 bits */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[0] = k->wk_keytsc >> 0; /* PN0 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[1] = k->wk_keytsc >> 8; /* PN1 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[2] = 0; /* Reserved */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[3] = keyid | IEEE80211_WEP_EXTIV; /* KeyID | ExtID */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[4] = k->wk_keytsc >> 16; /* PN2 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[5] = k->wk_keytsc >> 24; /* PN3 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[6] = k->wk_keytsc >> 32; /* PN4 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp[7] = k->wk_keytsc >> 40; /* PN5 */
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * NB: software CCMP is not supported.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Validate and strip privacy headers (and trailer) for a
a399b7655a1d835aa8606c2b29e4e777baac8635zf * received frame. The specified key should be correct but
a399b7655a1d835aa8606c2b29e4e777baac8635zf * is also verified.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf struct ieee80211_frame tmp;
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint8_t *ivp;
a399b7655a1d835aa8606c2b29e4e777baac8635zf uint64_t pn;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Header should have extended IV and sequence number;
a399b7655a1d835aa8606c2b29e4e777baac8635zf * verify the former and validate the latter.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf ivp = mp->b_rptr + hdrlen;
a399b7655a1d835aa8606c2b29e4e777baac8635zf if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * No extended IV; discard frame.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf pn = ieee80211_read_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (pn <= k->wk_keyrsc) {
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Replay violation.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf }
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * NB: software CCMP is not supported.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (0);
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Copy up 802.11 header and strip crypto bits.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf bcopy(mp->b_rptr, &tmp, hdrlen);
a399b7655a1d835aa8606c2b29e4e777baac8635zf bcopy(&tmp, mp->b_rptr + ccmp.ic_header, hdrlen);
a399b7655a1d835aa8606c2b29e4e777baac8635zf mp->b_rptr += ccmp.ic_header;
a399b7655a1d835aa8606c2b29e4e777baac8635zf mp->b_wptr -= ccmp.ic_trailer;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf /*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Ok to update rsc now.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf k->wk_keyrsc = pn;
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Add MIC to the frame as needed.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf/* ARGSUSED */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}
a399b7655a1d835aa8606c2b29e4e777baac8635zf
a399b7655a1d835aa8606c2b29e4e777baac8635zf/*
a399b7655a1d835aa8606c2b29e4e777baac8635zf * Verify and strip MIC from the frame.
a399b7655a1d835aa8606c2b29e4e777baac8635zf */
a399b7655a1d835aa8606c2b29e4e777baac8635zf/* ARGSUSED */
a399b7655a1d835aa8606c2b29e4e777baac8635zfstatic int
a399b7655a1d835aa8606c2b29e4e777baac8635zfccmp_demic(struct ieee80211_key *k, mblk_t *mp, int force)
a399b7655a1d835aa8606c2b29e4e777baac8635zf{
a399b7655a1d835aa8606c2b29e4e777baac8635zf return (1);
a399b7655a1d835aa8606c2b29e4e777baac8635zf}