xref: /freebsd/sys/net80211/ieee80211_crypto_gcmp.c (revision a54a240c1b579e2c30af125f3b1fdfd87f280078)
12d4583c4SAdrian Chadd /*-
22d4583c4SAdrian Chadd  * SPDX-License-Identifier: BSD-2-Clause
32d4583c4SAdrian Chadd  *
42d4583c4SAdrian Chadd  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
52d4583c4SAdrian Chadd  * All rights reserved.
62d4583c4SAdrian Chadd  * Copyright (c) 2025 Adrian Chadd <adrian@FreeBSD.org>.
72d4583c4SAdrian Chadd  *
82d4583c4SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
92d4583c4SAdrian Chadd  * modification, are permitted provided that the following conditions
102d4583c4SAdrian Chadd  * are met:
112d4583c4SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
122d4583c4SAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
132d4583c4SAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
142d4583c4SAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
152d4583c4SAdrian Chadd  *    documentation and/or other materials provided with the distribution.
162d4583c4SAdrian Chadd  *
172d4583c4SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182d4583c4SAdrian Chadd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192d4583c4SAdrian Chadd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202d4583c4SAdrian Chadd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212d4583c4SAdrian Chadd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222d4583c4SAdrian Chadd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232d4583c4SAdrian Chadd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242d4583c4SAdrian Chadd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252d4583c4SAdrian Chadd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262d4583c4SAdrian Chadd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272d4583c4SAdrian Chadd  */
282d4583c4SAdrian Chadd 
292d4583c4SAdrian Chadd /*
302d4583c4SAdrian Chadd  * IEEE 802.11 AES-GCMP crypto support.
312d4583c4SAdrian Chadd  *
322d4583c4SAdrian Chadd  * The AES-GCM crypto routines in sys/net80211/ieee80211_crypto_gcm.[ch]
332d4583c4SAdrian Chadd  * are derived from similar code in hostapd 2.11 (src/crypto/aes-gcm.c).
342d4583c4SAdrian Chadd  * The code is used with the consent of the author and its licence is
352d4583c4SAdrian Chadd  * included in the above source files.
362d4583c4SAdrian Chadd  */
372d4583c4SAdrian Chadd #include "opt_wlan.h"
382d4583c4SAdrian Chadd 
392d4583c4SAdrian Chadd #include <sys/param.h>
402d4583c4SAdrian Chadd #include <sys/systm.h>
412d4583c4SAdrian Chadd #include <sys/mbuf.h>
422d4583c4SAdrian Chadd #include <sys/malloc.h>
432d4583c4SAdrian Chadd #include <sys/kernel.h>
442d4583c4SAdrian Chadd #include <sys/module.h>
452d4583c4SAdrian Chadd 
462d4583c4SAdrian Chadd #include <sys/socket.h>
472d4583c4SAdrian Chadd 
482d4583c4SAdrian Chadd #include <net/if.h>
492d4583c4SAdrian Chadd #include <net/if_media.h>
502d4583c4SAdrian Chadd #include <net/ethernet.h>
512d4583c4SAdrian Chadd 
522d4583c4SAdrian Chadd #include <net80211/ieee80211_var.h>
532d4583c4SAdrian Chadd #include <net80211/ieee80211_crypto_gcm.h>
542d4583c4SAdrian Chadd 
552d4583c4SAdrian Chadd #include <crypto/rijndael/rijndael.h>
562d4583c4SAdrian Chadd 
572d4583c4SAdrian Chadd #define AES_BLOCK_LEN 16
582d4583c4SAdrian Chadd 
592d4583c4SAdrian Chadd /*
602d4583c4SAdrian Chadd  * Note: GCMP_MIC_LEN defined in ieee80211_crypto_gcm.h, as it is also
612d4583c4SAdrian Chadd  * used by the AES-GCM routines for sizing the S and T hashes which are
622d4583c4SAdrian Chadd  * used by GCMP as the MIC.
632d4583c4SAdrian Chadd  */
642d4583c4SAdrian Chadd #define	GCMP_PN_LEN	6
652d4583c4SAdrian Chadd #define	GCMP_IV_LEN	12
662d4583c4SAdrian Chadd 
672d4583c4SAdrian Chadd struct gcmp_ctx {
682d4583c4SAdrian Chadd 	struct ieee80211vap *cc_vap;	/* for diagnostics+statistics */
692d4583c4SAdrian Chadd 	struct ieee80211com *cc_ic;
702d4583c4SAdrian Chadd 	rijndael_ctx	     cc_aes;
712d4583c4SAdrian Chadd };
722d4583c4SAdrian Chadd 
732d4583c4SAdrian Chadd static	void *gcmp_attach(struct ieee80211vap *, struct ieee80211_key *);
742d4583c4SAdrian Chadd static	void gcmp_detach(struct ieee80211_key *);
752d4583c4SAdrian Chadd static	int gcmp_setkey(struct ieee80211_key *);
762d4583c4SAdrian Chadd static	void gcmp_setiv(struct ieee80211_key *, uint8_t *);
772d4583c4SAdrian Chadd static	int gcmp_encap(struct ieee80211_key *, struct mbuf *);
782d4583c4SAdrian Chadd static	int gcmp_decap(struct ieee80211_key *, struct mbuf *, int);
792d4583c4SAdrian Chadd static	int gcmp_enmic(struct ieee80211_key *, struct mbuf *, int);
802d4583c4SAdrian Chadd static	int gcmp_demic(struct ieee80211_key *, struct mbuf *, int);
812d4583c4SAdrian Chadd 
822d4583c4SAdrian Chadd static const struct ieee80211_cipher gcmp = {
832d4583c4SAdrian Chadd 	.ic_name	= "AES-GCMP",
842d4583c4SAdrian Chadd 	.ic_cipher	= IEEE80211_CIPHER_AES_GCM_128,
852d4583c4SAdrian Chadd 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
862d4583c4SAdrian Chadd 			  IEEE80211_WEP_EXTIVLEN,
872d4583c4SAdrian Chadd 	.ic_trailer	= GCMP_MIC_LEN,
882d4583c4SAdrian Chadd 	.ic_miclen	= 0,
892d4583c4SAdrian Chadd 	.ic_attach	= gcmp_attach,
902d4583c4SAdrian Chadd 	.ic_detach	= gcmp_detach,
912d4583c4SAdrian Chadd 	.ic_setkey	= gcmp_setkey,
922d4583c4SAdrian Chadd 	.ic_setiv	= gcmp_setiv,
932d4583c4SAdrian Chadd 	.ic_encap	= gcmp_encap,
942d4583c4SAdrian Chadd 	.ic_decap	= gcmp_decap,
952d4583c4SAdrian Chadd 	.ic_enmic	= gcmp_enmic,
962d4583c4SAdrian Chadd 	.ic_demic	= gcmp_demic,
972d4583c4SAdrian Chadd };
982d4583c4SAdrian Chadd 
992d4583c4SAdrian Chadd static const struct ieee80211_cipher gcmp_256 = {
1002d4583c4SAdrian Chadd 	.ic_name	= "AES-GCMP-256",
1012d4583c4SAdrian Chadd 	.ic_cipher	= IEEE80211_CIPHER_AES_GCM_256,
1022d4583c4SAdrian Chadd 	.ic_header	= IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
1032d4583c4SAdrian Chadd 			  IEEE80211_WEP_EXTIVLEN,
1042d4583c4SAdrian Chadd 	.ic_trailer	= GCMP_MIC_LEN,
1052d4583c4SAdrian Chadd 	.ic_miclen	= 0,
1062d4583c4SAdrian Chadd 	.ic_attach	= gcmp_attach,
1072d4583c4SAdrian Chadd 	.ic_detach	= gcmp_detach,
1082d4583c4SAdrian Chadd 	.ic_setkey	= gcmp_setkey,
1092d4583c4SAdrian Chadd 	.ic_setiv	= gcmp_setiv,
1102d4583c4SAdrian Chadd 	.ic_encap	= gcmp_encap,
1112d4583c4SAdrian Chadd 	.ic_decap	= gcmp_decap,
1122d4583c4SAdrian Chadd 	.ic_enmic	= gcmp_enmic,
1132d4583c4SAdrian Chadd 	.ic_demic	= gcmp_demic,
1142d4583c4SAdrian Chadd };
1152d4583c4SAdrian Chadd 
1162d4583c4SAdrian Chadd 
1172d4583c4SAdrian Chadd static	int gcmp_encrypt(struct ieee80211_key *, struct mbuf *, int hdrlen);
1182d4583c4SAdrian Chadd static	int gcmp_decrypt(struct ieee80211_key *, u_int64_t pn,
1192d4583c4SAdrian Chadd 		struct mbuf *, int hdrlen);
1202d4583c4SAdrian Chadd 
1212d4583c4SAdrian Chadd /* number of references from net80211 layer */
1222d4583c4SAdrian Chadd static	int nrefs = 0;
1232d4583c4SAdrian Chadd 
1242d4583c4SAdrian Chadd static void *
gcmp_attach(struct ieee80211vap * vap,struct ieee80211_key * k)1252d4583c4SAdrian Chadd gcmp_attach(struct ieee80211vap *vap, struct ieee80211_key *k)
1262d4583c4SAdrian Chadd {
1272d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx;
1282d4583c4SAdrian Chadd 
1292d4583c4SAdrian Chadd 	ctx = (struct gcmp_ctx *) IEEE80211_MALLOC(sizeof(struct gcmp_ctx),
1302d4583c4SAdrian Chadd 		M_80211_CRYPTO, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1312d4583c4SAdrian Chadd 	if (ctx == NULL) {
1322d4583c4SAdrian Chadd 		vap->iv_stats.is_crypto_nomem++;
1332d4583c4SAdrian Chadd 		return (NULL);
1342d4583c4SAdrian Chadd 	}
1352d4583c4SAdrian Chadd 	ctx->cc_vap = vap;
1362d4583c4SAdrian Chadd 	ctx->cc_ic = vap->iv_ic;
1372d4583c4SAdrian Chadd 	nrefs++;			/* NB: we assume caller locking */
1382d4583c4SAdrian Chadd 	return (ctx);
1392d4583c4SAdrian Chadd }
1402d4583c4SAdrian Chadd 
1412d4583c4SAdrian Chadd static void
gcmp_detach(struct ieee80211_key * k)1422d4583c4SAdrian Chadd gcmp_detach(struct ieee80211_key *k)
1432d4583c4SAdrian Chadd {
1442d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
1452d4583c4SAdrian Chadd 
1462d4583c4SAdrian Chadd 	IEEE80211_FREE(ctx, M_80211_CRYPTO);
1472d4583c4SAdrian Chadd 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
1482d4583c4SAdrian Chadd 	nrefs--;			/* NB: we assume caller locking */
1492d4583c4SAdrian Chadd }
1502d4583c4SAdrian Chadd 
1512d4583c4SAdrian Chadd static int
gcmp_get_trailer_len(struct ieee80211_key * k)1522d4583c4SAdrian Chadd gcmp_get_trailer_len(struct ieee80211_key *k)
1532d4583c4SAdrian Chadd {
1542d4583c4SAdrian Chadd 	return (k->wk_cipher->ic_trailer);
1552d4583c4SAdrian Chadd }
1562d4583c4SAdrian Chadd 
1572d4583c4SAdrian Chadd static int
gcmp_get_header_len(struct ieee80211_key * k)1582d4583c4SAdrian Chadd gcmp_get_header_len(struct ieee80211_key *k)
1592d4583c4SAdrian Chadd {
1602d4583c4SAdrian Chadd 	return (k->wk_cipher->ic_header);
1612d4583c4SAdrian Chadd }
1622d4583c4SAdrian Chadd 
1632d4583c4SAdrian Chadd static int
gcmp_setkey(struct ieee80211_key * k)1642d4583c4SAdrian Chadd gcmp_setkey(struct ieee80211_key *k)
1652d4583c4SAdrian Chadd {
1662d4583c4SAdrian Chadd 	uint32_t keylen;
1672d4583c4SAdrian Chadd 
1682d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
1692d4583c4SAdrian Chadd 
1702d4583c4SAdrian Chadd 	switch (k->wk_cipher->ic_cipher) {
1712d4583c4SAdrian Chadd 	case IEEE80211_CIPHER_AES_GCM_128:
1722d4583c4SAdrian Chadd 		keylen = 128;
1732d4583c4SAdrian Chadd 		break;
1742d4583c4SAdrian Chadd 	case IEEE80211_CIPHER_AES_GCM_256:
1752d4583c4SAdrian Chadd 		keylen = 256;
1762d4583c4SAdrian Chadd 		break;
1772d4583c4SAdrian Chadd 	default:
1782d4583c4SAdrian Chadd 		IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
1792d4583c4SAdrian Chadd 			"%s: Unexpected cipher (%u)",
1802d4583c4SAdrian Chadd 			__func__, k->wk_cipher->ic_cipher);
1812d4583c4SAdrian Chadd 		return (0);
1822d4583c4SAdrian Chadd 	}
1832d4583c4SAdrian Chadd 
1842d4583c4SAdrian Chadd 	if (k->wk_keylen != (keylen/NBBY)) {
1852d4583c4SAdrian Chadd 		IEEE80211_DPRINTF(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
1862d4583c4SAdrian Chadd 			"%s: Invalid key length %u, expecting %u\n",
1872d4583c4SAdrian Chadd 			__func__, k->wk_keylen, keylen/NBBY);
1882d4583c4SAdrian Chadd 		return (0);
1892d4583c4SAdrian Chadd 	}
1902d4583c4SAdrian Chadd 	if (k->wk_flags & IEEE80211_KEY_SWENCRYPT)
1912d4583c4SAdrian Chadd 		rijndael_set_key(&ctx->cc_aes, k->wk_key, k->wk_keylen*NBBY);
1922d4583c4SAdrian Chadd 	return (1);
1932d4583c4SAdrian Chadd }
1942d4583c4SAdrian Chadd 
1952d4583c4SAdrian Chadd static void
gcmp_setiv(struct ieee80211_key * k,uint8_t * ivp)1962d4583c4SAdrian Chadd gcmp_setiv(struct ieee80211_key *k, uint8_t *ivp)
1972d4583c4SAdrian Chadd {
1982d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
1992d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
2002d4583c4SAdrian Chadd 	uint8_t keyid;
2012d4583c4SAdrian Chadd 
2022d4583c4SAdrian Chadd 	keyid = ieee80211_crypto_get_keyid(vap, k) << 6;
2032d4583c4SAdrian Chadd 
2042d4583c4SAdrian Chadd 	k->wk_keytsc++;
2052d4583c4SAdrian Chadd 	ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
2062d4583c4SAdrian Chadd 	ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
2072d4583c4SAdrian Chadd 	ivp[2] = 0;				/* Reserved */
2082d4583c4SAdrian Chadd 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
2092d4583c4SAdrian Chadd 	ivp[4] = k->wk_keytsc >> 16;		/* PN2 */
2102d4583c4SAdrian Chadd 	ivp[5] = k->wk_keytsc >> 24;		/* PN3 */
2112d4583c4SAdrian Chadd 	ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
2122d4583c4SAdrian Chadd 	ivp[7] = k->wk_keytsc >> 40;		/* PN5 */
2132d4583c4SAdrian Chadd }
2142d4583c4SAdrian Chadd 
2152d4583c4SAdrian Chadd /*
2162d4583c4SAdrian Chadd  * Add privacy headers appropriate for the specified key.
2172d4583c4SAdrian Chadd  */
2182d4583c4SAdrian Chadd static int
gcmp_encap(struct ieee80211_key * k,struct mbuf * m)2192d4583c4SAdrian Chadd gcmp_encap(struct ieee80211_key *k, struct mbuf *m)
2202d4583c4SAdrian Chadd {
2212d4583c4SAdrian Chadd 	const struct ieee80211_frame *wh;
2222d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
2232d4583c4SAdrian Chadd 	struct ieee80211com *ic = ctx->cc_ic;
2242d4583c4SAdrian Chadd 	uint8_t *ivp;
2252d4583c4SAdrian Chadd 	int hdrlen;
2262d4583c4SAdrian Chadd 	int is_mgmt;
2272d4583c4SAdrian Chadd 
2282d4583c4SAdrian Chadd 	hdrlen = ieee80211_hdrspace(ic, mtod(m, void *));
2292d4583c4SAdrian Chadd 	wh = mtod(m, const struct ieee80211_frame *);
2302d4583c4SAdrian Chadd 	is_mgmt = IEEE80211_IS_MGMT(wh);
2312d4583c4SAdrian Chadd 
2322d4583c4SAdrian Chadd 	/*
2332d4583c4SAdrian Chadd 	 * Check to see if we need to insert IV/MIC.
2342d4583c4SAdrian Chadd 	 *
2352d4583c4SAdrian Chadd 	 * Some offload devices don't require the IV to be inserted
2362d4583c4SAdrian Chadd 	 * as part of the hardware encryption.
2372d4583c4SAdrian Chadd 	 */
2382d4583c4SAdrian Chadd 	if (is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIVMGT))
2392d4583c4SAdrian Chadd 		return (1);
2402d4583c4SAdrian Chadd 	if (!is_mgmt && (k->wk_flags & IEEE80211_KEY_NOIV))
2412d4583c4SAdrian Chadd 		return (1);
2422d4583c4SAdrian Chadd 
2432d4583c4SAdrian Chadd 	/*
2442d4583c4SAdrian Chadd 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
2452d4583c4SAdrian Chadd 	 */
2462d4583c4SAdrian Chadd 	M_PREPEND(m, gcmp_get_header_len(k), IEEE80211_M_NOWAIT);
2472d4583c4SAdrian Chadd 	if (m == NULL)
2482d4583c4SAdrian Chadd 		return (0);
2492d4583c4SAdrian Chadd 	ivp = mtod(m, uint8_t *);
2502d4583c4SAdrian Chadd 	ovbcopy(ivp + gcmp_get_header_len(k), ivp, hdrlen);
2512d4583c4SAdrian Chadd 	ivp += hdrlen;
2522d4583c4SAdrian Chadd 
2532d4583c4SAdrian Chadd 	gcmp_setiv(k, ivp);
2542d4583c4SAdrian Chadd 
2552d4583c4SAdrian Chadd 	/*
2562d4583c4SAdrian Chadd 	 * Finally, do software encrypt if needed.
2572d4583c4SAdrian Chadd 	 */
2582d4583c4SAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWENCRYPT) &&
2592d4583c4SAdrian Chadd 	    !gcmp_encrypt(k, m, hdrlen))
2602d4583c4SAdrian Chadd 		return (0);
2612d4583c4SAdrian Chadd 
2622d4583c4SAdrian Chadd 	return (1);
2632d4583c4SAdrian Chadd }
2642d4583c4SAdrian Chadd 
2652d4583c4SAdrian Chadd /*
2662d4583c4SAdrian Chadd  * Add MIC to the frame as needed.
2672d4583c4SAdrian Chadd  */
2682d4583c4SAdrian Chadd static int
gcmp_enmic(struct ieee80211_key * k,struct mbuf * m,int force)2692d4583c4SAdrian Chadd gcmp_enmic(struct ieee80211_key *k, struct mbuf *m, int force)
2702d4583c4SAdrian Chadd {
2712d4583c4SAdrian Chadd 	return (1);
2722d4583c4SAdrian Chadd }
2732d4583c4SAdrian Chadd 
2742d4583c4SAdrian Chadd static __inline uint64_t
READ_6(uint8_t b0,uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint8_t b5)2752d4583c4SAdrian Chadd READ_6(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5)
2762d4583c4SAdrian Chadd {
2772d4583c4SAdrian Chadd 	uint32_t iv32 = (b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24);
2782d4583c4SAdrian Chadd 	uint16_t iv16 = (b4 << 0) | (b5 << 8);
2792d4583c4SAdrian Chadd 	return ((((uint64_t)iv16) << 32) | iv32);
2802d4583c4SAdrian Chadd }
2812d4583c4SAdrian Chadd 
2822d4583c4SAdrian Chadd /*
2832d4583c4SAdrian Chadd  * Validate and strip privacy headers (and trailer) for a
2842d4583c4SAdrian Chadd  * received frame. The specified key should be correct but
2852d4583c4SAdrian Chadd  * is also verified.
2862d4583c4SAdrian Chadd  */
2872d4583c4SAdrian Chadd static int
gcmp_decap(struct ieee80211_key * k,struct mbuf * m,int hdrlen)2882d4583c4SAdrian Chadd gcmp_decap(struct ieee80211_key *k, struct mbuf *m, int hdrlen)
2892d4583c4SAdrian Chadd {
2902d4583c4SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
2912d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = k->wk_private;
2922d4583c4SAdrian Chadd 	struct ieee80211vap *vap = ctx->cc_vap;
2932d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
2942d4583c4SAdrian Chadd 	uint8_t *ivp, tid;
2952d4583c4SAdrian Chadd 	uint64_t pn;
2962d4583c4SAdrian Chadd 	bool noreplaycheck;
2972d4583c4SAdrian Chadd 
2982d4583c4SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
2992d4583c4SAdrian Chadd 
3002d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) != 0)
3012d4583c4SAdrian Chadd 		goto finish;
3022d4583c4SAdrian Chadd 
3032d4583c4SAdrian Chadd 	/*
3042d4583c4SAdrian Chadd 	 * Header should have extended IV and sequence number;
3052d4583c4SAdrian Chadd 	 * verify the former and validate the latter.
3062d4583c4SAdrian Chadd 	 */
3072d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
3082d4583c4SAdrian Chadd 	ivp = mtod(m, uint8_t *) + hdrlen;
3092d4583c4SAdrian Chadd 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
3102d4583c4SAdrian Chadd 		/*
3112d4583c4SAdrian Chadd 		 * No extended IV; discard frame.
3122d4583c4SAdrian Chadd 		 */
3132d4583c4SAdrian Chadd 		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
3142d4583c4SAdrian Chadd 			"%s", "missing ExtIV for AES-GCM cipher");
3152d4583c4SAdrian Chadd 		vap->iv_stats.is_rx_gcmpformat++;
3162d4583c4SAdrian Chadd 		return (0);
3172d4583c4SAdrian Chadd 	}
3182d4583c4SAdrian Chadd 	tid = ieee80211_gettid(wh);
3192d4583c4SAdrian Chadd 	pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
3202d4583c4SAdrian Chadd 
3212d4583c4SAdrian Chadd 	noreplaycheck = (k->wk_flags & IEEE80211_KEY_NOREPLAY) != 0;
3222d4583c4SAdrian Chadd 	noreplaycheck |= (rxs != NULL) &&
3232d4583c4SAdrian Chadd 	    (rxs->c_pktflags & IEEE80211_RX_F_PN_VALIDATED) != 0;
3242d4583c4SAdrian Chadd 	if (pn <= k->wk_keyrsc[tid] && !noreplaycheck) {
3252d4583c4SAdrian Chadd 		/*
3262d4583c4SAdrian Chadd 		 * Replay violation.
3272d4583c4SAdrian Chadd 		 */
3282d4583c4SAdrian Chadd 		ieee80211_notify_replay_failure(vap, wh, k, pn, tid);
3292d4583c4SAdrian Chadd 		vap->iv_stats.is_rx_gcmpreplay++;
3302d4583c4SAdrian Chadd 		return (0);
3312d4583c4SAdrian Chadd 	}
3322d4583c4SAdrian Chadd 
3332d4583c4SAdrian Chadd 	/*
3342d4583c4SAdrian Chadd 	 * Check if the device handled the decrypt in hardware.
3352d4583c4SAdrian Chadd 	 * If so we just strip the header; otherwise we need to
3362d4583c4SAdrian Chadd 	 * handle the decrypt in software.  Note that for the
3372d4583c4SAdrian Chadd 	 * latter we leave the header in place for use in the
3382d4583c4SAdrian Chadd 	 * decryption work.
3392d4583c4SAdrian Chadd 	 */
3402d4583c4SAdrian Chadd 	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
3412d4583c4SAdrian Chadd 	    !gcmp_decrypt(k, pn, m, hdrlen))
3422d4583c4SAdrian Chadd 		return (0);
3432d4583c4SAdrian Chadd 
3442d4583c4SAdrian Chadd finish:
3452d4583c4SAdrian Chadd 	/*
3462d4583c4SAdrian Chadd 	 * Copy up 802.11 header and strip crypto bits.
3472d4583c4SAdrian Chadd 	 */
3482d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) == 0) {
3492d4583c4SAdrian Chadd 		ovbcopy(mtod(m, void *), mtod(m, uint8_t *) +
3502d4583c4SAdrian Chadd 		    gcmp_get_header_len(k), hdrlen);
3512d4583c4SAdrian Chadd 		m_adj(m, gcmp_get_header_len(k));
3522d4583c4SAdrian Chadd 	}
3532d4583c4SAdrian Chadd 
3542d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_MIC_STRIP) == 0)
3552d4583c4SAdrian Chadd 		m_adj(m, -gcmp_get_trailer_len(k));
3562d4583c4SAdrian Chadd 
3572d4583c4SAdrian Chadd 	/*
3582d4583c4SAdrian Chadd 	 * Ok to update rsc now.
3592d4583c4SAdrian Chadd 	 */
3602d4583c4SAdrian Chadd 	if ((rxs == NULL) || (rxs->c_pktflags & IEEE80211_RX_F_IV_STRIP) == 0) {
3612d4583c4SAdrian Chadd 		/*
3622d4583c4SAdrian Chadd 		 * Do not go backwards in the IEEE80211_KEY_NOREPLAY cases
3632d4583c4SAdrian Chadd 		 * or in case hardware has checked but frames are arriving
3642d4583c4SAdrian Chadd 		 * reordered (e.g., LinuxKPI drivers doing RSS which we are
3652d4583c4SAdrian Chadd 		 * not prepared for at all).
3662d4583c4SAdrian Chadd 		 */
3672d4583c4SAdrian Chadd 		if (pn > k->wk_keyrsc[tid])
3682d4583c4SAdrian Chadd 			k->wk_keyrsc[tid] = pn;
3692d4583c4SAdrian Chadd 	}
3702d4583c4SAdrian Chadd 
3712d4583c4SAdrian Chadd 	return (1);
3722d4583c4SAdrian Chadd }
3732d4583c4SAdrian Chadd 
3742d4583c4SAdrian Chadd /*
3752d4583c4SAdrian Chadd  * Verify and strip MIC from the frame.
3762d4583c4SAdrian Chadd  */
3772d4583c4SAdrian Chadd static int
gcmp_demic(struct ieee80211_key * k,struct mbuf * m,int force)3782d4583c4SAdrian Chadd gcmp_demic(struct ieee80211_key *k, struct mbuf *m, int force)
3792d4583c4SAdrian Chadd {
3802d4583c4SAdrian Chadd 	return (1);
3812d4583c4SAdrian Chadd }
3822d4583c4SAdrian Chadd 
3832d4583c4SAdrian Chadd /**
3842d4583c4SAdrian Chadd  * @brief Calculate the AAD required for this frame for AES-GCM.
3852d4583c4SAdrian Chadd  *
3862d4583c4SAdrian Chadd  * Note: This code was first copied over from ieee80211_crypto_ccmp.c, so
3872d4583c4SAdrian Chadd  * it has some CCMP-isms.
3882d4583c4SAdrian Chadd  *
3892d4583c4SAdrian Chadd  * NOTE: the first two bytes are a 16 bit big-endian length, which are used
3902d4583c4SAdrian Chadd  * by AES-CCM.  AES-GCM doesn't require the length at the beginning.
3912d4583c4SAdrian Chadd  *
3922d4583c4SAdrian Chadd  * @param wh	802.11 frame to calculate the AAD over
3932d4583c4SAdrian Chadd  * @param aad	AAD buffer, GCM_AAD_LEN bytes
3942d4583c4SAdrian Chadd  * @param The AAD length in bytes.
3952d4583c4SAdrian Chadd  */
3962d4583c4SAdrian Chadd static int
gcmp_init_aad(const struct ieee80211_frame * wh,uint8_t * aad)3972d4583c4SAdrian Chadd gcmp_init_aad(const struct ieee80211_frame *wh, uint8_t *aad)
3982d4583c4SAdrian Chadd {
3992d4583c4SAdrian Chadd 	int aad_len;
4002d4583c4SAdrian Chadd 
4012d4583c4SAdrian Chadd 	memset(aad, 0, GCM_AAD_LEN);
4022d4583c4SAdrian Chadd 
4032d4583c4SAdrian Chadd #define	IS_QOS_DATA(wh)	IEEE80211_QOS_HAS_SEQ(wh)
4042d4583c4SAdrian Chadd 	/* AAD:
4052d4583c4SAdrian Chadd 	 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
4062d4583c4SAdrian Chadd 	 * A1 | A2 | A3
4072d4583c4SAdrian Chadd 	 * SC with bits 4..15 (seq#) masked to zero
4082d4583c4SAdrian Chadd 	 * A4 (if present)
4092d4583c4SAdrian Chadd 	 * QC (if present)
4102d4583c4SAdrian Chadd 	 */
4112d4583c4SAdrian Chadd 	aad[0] = 0;	/* AAD length >> 8 */
4122d4583c4SAdrian Chadd 	/* NB: aad[1] set below */
4132d4583c4SAdrian Chadd 
4142d4583c4SAdrian Chadd 	/*
4152d4583c4SAdrian Chadd 	 * TODO: go back over this in 802.11-2020 and triple check
4162d4583c4SAdrian Chadd 	 * the AAD assembly with regards to packet flags.
4172d4583c4SAdrian Chadd 	 */
4182d4583c4SAdrian Chadd 
4192d4583c4SAdrian Chadd 	aad[2] = wh->i_fc[0] & 0x8f;	/* XXX magic #s */
4202d4583c4SAdrian Chadd 	/*
4212d4583c4SAdrian Chadd 	 * TODO: 12.5.3.3.3 - bit 14 should always be set; bit 15 masked to 0
4222d4583c4SAdrian Chadd 	 * if QoS control field, unmasked otherwise
4232d4583c4SAdrian Chadd 	 */
4242d4583c4SAdrian Chadd 	aad[3] = wh->i_fc[1] & 0xc7;	/* XXX magic #s */
4252d4583c4SAdrian Chadd 	/* NB: we know 3 addresses are contiguous */
4262d4583c4SAdrian Chadd 	memcpy(aad + 4, wh->i_addr1, 3 * IEEE80211_ADDR_LEN);
4272d4583c4SAdrian Chadd 	aad[22] = wh->i_seq[0] & IEEE80211_SEQ_FRAG_MASK;
4282d4583c4SAdrian Chadd 	aad[23] = 0; /* all bits masked */
4292d4583c4SAdrian Chadd 	/*
4302d4583c4SAdrian Chadd 	 * Construct variable-length portion of AAD based
4312d4583c4SAdrian Chadd 	 * on whether this is a 4-address frame/QOS frame.
4322d4583c4SAdrian Chadd 	 * We always zero-pad to 32 bytes before running it
4332d4583c4SAdrian Chadd 	 * through the cipher.
4342d4583c4SAdrian Chadd 	 */
4352d4583c4SAdrian Chadd 	if (IEEE80211_IS_DSTODS(wh)) {
4362d4583c4SAdrian Chadd 		IEEE80211_ADDR_COPY(aad + 24,
4372d4583c4SAdrian Chadd 			((const struct ieee80211_frame_addr4 *)wh)->i_addr4);
4382d4583c4SAdrian Chadd 		if (IS_QOS_DATA(wh)) {
4392d4583c4SAdrian Chadd 			const struct ieee80211_qosframe_addr4 *qwh4 =
4402d4583c4SAdrian Chadd 				(const struct ieee80211_qosframe_addr4 *) wh;
4412d4583c4SAdrian Chadd 			aad[30] = qwh4->i_qos[0] & 0x0f;/* just priority bits */
4422d4583c4SAdrian Chadd 			aad[31] = 0;
4432d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + IEEE80211_ADDR_LEN + 2;
4442d4583c4SAdrian Chadd 		} else {
4452d4583c4SAdrian Chadd 			*(uint16_t *)&aad[30] = 0;
4462d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + IEEE80211_ADDR_LEN;
4472d4583c4SAdrian Chadd 		}
4482d4583c4SAdrian Chadd 	} else {
4492d4583c4SAdrian Chadd 		if (IS_QOS_DATA(wh)) {
4502d4583c4SAdrian Chadd 			const struct ieee80211_qosframe *qwh =
4512d4583c4SAdrian Chadd 				(const struct ieee80211_qosframe*) wh;
4522d4583c4SAdrian Chadd 			aad[24] = qwh->i_qos[0] & 0x0f;	/* just priority bits */
4532d4583c4SAdrian Chadd 			aad[25] = 0;
4542d4583c4SAdrian Chadd 			aad_len = aad[1] = 22 + 2;
4552d4583c4SAdrian Chadd 		} else {
4562d4583c4SAdrian Chadd 			*(uint16_t *)&aad[24] = 0;
4572d4583c4SAdrian Chadd 			aad_len = aad[1] = 22;
4582d4583c4SAdrian Chadd 		}
4592d4583c4SAdrian Chadd 		*(uint16_t *)&aad[26] = 0;
4602d4583c4SAdrian Chadd 		*(uint32_t *)&aad[28] = 0;
4612d4583c4SAdrian Chadd 	}
4622d4583c4SAdrian Chadd #undef	IS_QOS_DATA
4632d4583c4SAdrian Chadd 
4642d4583c4SAdrian Chadd 	return (aad_len);
4652d4583c4SAdrian Chadd }
4662d4583c4SAdrian Chadd 
4672d4583c4SAdrian Chadd /*
4682d4583c4SAdrian Chadd  * Populate the 12 byte / 96 bit IV buffer.
4692d4583c4SAdrian Chadd  */
4702d4583c4SAdrian Chadd static int
gcmp_init_iv(uint8_t * iv,const struct ieee80211_frame * wh,u_int64_t pn)4712d4583c4SAdrian Chadd gcmp_init_iv(uint8_t *iv, const struct ieee80211_frame *wh, u_int64_t pn)
4722d4583c4SAdrian Chadd {
4732d4583c4SAdrian Chadd 	uint8_t j_pn[GCMP_PN_LEN];
4742d4583c4SAdrian Chadd 
4752d4583c4SAdrian Chadd 	/* Construct the pn buffer */
4762d4583c4SAdrian Chadd 	j_pn[0] = pn >> 40;
4772d4583c4SAdrian Chadd 	j_pn[1] = pn >> 32;
4782d4583c4SAdrian Chadd 	j_pn[2] = pn >> 24;
4792d4583c4SAdrian Chadd 	j_pn[3] = pn >> 16;
4802d4583c4SAdrian Chadd 	j_pn[4] = pn >> 8;
4812d4583c4SAdrian Chadd 	j_pn[5] = pn >> 0;
4822d4583c4SAdrian Chadd 
4832d4583c4SAdrian Chadd 	memcpy(iv, wh->i_addr2, IEEE80211_ADDR_LEN);
4842d4583c4SAdrian Chadd 	memcpy(iv + IEEE80211_ADDR_LEN, j_pn, GCMP_PN_LEN);
4852d4583c4SAdrian Chadd 
4862d4583c4SAdrian Chadd 	return (GCMP_IV_LEN); /* 96 bits */
4872d4583c4SAdrian Chadd }
4882d4583c4SAdrian Chadd 
4892d4583c4SAdrian Chadd /*
4902d4583c4SAdrian Chadd  * @brief Encrypt an mbuf.
4912d4583c4SAdrian Chadd  *
4922d4583c4SAdrian Chadd  * This uses a temporary memory buffer to encrypt; the
4932d4583c4SAdrian Chadd  * current AES-GCM code expects things in a contiguous buffer
4942d4583c4SAdrian Chadd  * and this avoids the need of breaking out the GCTR and
4952d4583c4SAdrian Chadd  * GHASH routines into using mbuf iterators.
4962d4583c4SAdrian Chadd  *
4972d4583c4SAdrian Chadd  * @param key	ieee80211_key to use
4982d4583c4SAdrian Chadd  * @param mbuf	802.11 frame to encrypt
4992d4583c4SAdrian Chadd  * @param hdrlen	the length of the 802.11 header, including any padding
5002d4583c4SAdrian Chadd  * @returns 0 if error, > 0 if OK.
5012d4583c4SAdrian Chadd  */
5022d4583c4SAdrian Chadd static int
gcmp_encrypt(struct ieee80211_key * key,struct mbuf * m0,int hdrlen)5032d4583c4SAdrian Chadd gcmp_encrypt(struct ieee80211_key *key, struct mbuf *m0, int hdrlen)
5042d4583c4SAdrian Chadd {
5052d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = key->wk_private;
5062d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
5072d4583c4SAdrian Chadd 	struct mbuf *m = m0;
5082d4583c4SAdrian Chadd 	int data_len, aad_len, iv_len, ret;
5092d4583c4SAdrian Chadd 	uint8_t aad[GCM_AAD_LEN];
5102d4583c4SAdrian Chadd 	uint8_t T[GCMP_MIC_LEN];
5112d4583c4SAdrian Chadd 	uint8_t iv[GCMP_IV_LEN];
5122d4583c4SAdrian Chadd 	uint8_t *p_pktbuf = NULL;
5132d4583c4SAdrian Chadd 	uint8_t *c_pktbuf = NULL;
5142d4583c4SAdrian Chadd 
5152d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
5162d4583c4SAdrian Chadd 	data_len = m->m_pkthdr.len - (hdrlen + gcmp_get_header_len(key));
5172d4583c4SAdrian Chadd 
5182d4583c4SAdrian Chadd 	ctx->cc_vap->iv_stats.is_crypto_gcmp++;
5192d4583c4SAdrian Chadd 
5202d4583c4SAdrian Chadd 	p_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
5212d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
5222d4583c4SAdrian Chadd 	if (p_pktbuf == NULL) {
523*a54a240cSAdrian Chadd 		IEEE80211_NOTE_MAC(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
524*a54a240cSAdrian Chadd 		    wh->i_addr2, "%s",
525*a54a240cSAdrian Chadd 		    "AES-GCM encrypt failed; couldn't allocate buffer");
5262d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
5272d4583c4SAdrian Chadd 		return (0);
5282d4583c4SAdrian Chadd 	}
5292d4583c4SAdrian Chadd 	c_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
5302d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
5312d4583c4SAdrian Chadd 	if (c_pktbuf == NULL) {
532*a54a240cSAdrian Chadd 		IEEE80211_NOTE_MAC(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
533*a54a240cSAdrian Chadd 		    wh->i_addr2, "%s",
534*a54a240cSAdrian Chadd 		    "AES-GCM encrypt failed; couldn't allocate buffer");
5352d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
5362d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
5372d4583c4SAdrian Chadd 		return (0);
5382d4583c4SAdrian Chadd 	}
5392d4583c4SAdrian Chadd 
5402d4583c4SAdrian Chadd 	/* Initialise AAD */
5412d4583c4SAdrian Chadd 	aad_len = gcmp_init_aad(wh, aad);
5422d4583c4SAdrian Chadd 
5432d4583c4SAdrian Chadd 	/* Initialise local Nonce to work on */
5442d4583c4SAdrian Chadd 	/* TODO: rename iv stuff here to nonce */
5452d4583c4SAdrian Chadd 	iv_len = gcmp_init_iv(iv, wh, key->wk_keytsc);
5462d4583c4SAdrian Chadd 
5472d4583c4SAdrian Chadd 	/* Copy mbuf data part into plaintext pktbuf */
5482d4583c4SAdrian Chadd 	m_copydata(m0, hdrlen + gcmp_get_header_len(key), data_len,
5492d4583c4SAdrian Chadd 	    p_pktbuf);
5502d4583c4SAdrian Chadd 
5512d4583c4SAdrian Chadd 	/* Run encrypt */
5522d4583c4SAdrian Chadd 	/*
5532d4583c4SAdrian Chadd 	 * Note: aad + 2 to skip over the 2 byte length populated
5542d4583c4SAdrian Chadd 	 * at the beginning, since it's based on the AAD code in CCMP.
5552d4583c4SAdrian Chadd 	 */
5562d4583c4SAdrian Chadd 	ieee80211_crypto_aes_gcm_ae(&ctx->cc_aes, iv, iv_len,
5572d4583c4SAdrian Chadd 	    p_pktbuf, data_len, aad + 2, aad_len, c_pktbuf, T);
5582d4583c4SAdrian Chadd 
5592d4583c4SAdrian Chadd 	/* Copy data back over mbuf */
5602d4583c4SAdrian Chadd 	m_copyback(m0, hdrlen + gcmp_get_header_len(key), data_len,
5612d4583c4SAdrian Chadd 	    c_pktbuf);
5622d4583c4SAdrian Chadd 
5632d4583c4SAdrian Chadd 	/* Append MIC */
5642d4583c4SAdrian Chadd 	ret = m_append(m0, gcmp_get_trailer_len(key), T);
5652d4583c4SAdrian Chadd 	if (ret == 0) {
566*a54a240cSAdrian Chadd 		IEEE80211_NOTE_MAC(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
567*a54a240cSAdrian Chadd 		    wh->i_addr2, "%s",
568*a54a240cSAdrian Chadd 		    "AES-GCM encrypt failed; couldn't append T");
5692d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nospc++;
5702d4583c4SAdrian Chadd 	}
5712d4583c4SAdrian Chadd 
5722d4583c4SAdrian Chadd 	IEEE80211_FREE(p_pktbuf, M_TEMP);
5732d4583c4SAdrian Chadd 	IEEE80211_FREE(c_pktbuf, M_TEMP);
5742d4583c4SAdrian Chadd 
5752d4583c4SAdrian Chadd 	return (ret);
5762d4583c4SAdrian Chadd }
5772d4583c4SAdrian Chadd 
5782d4583c4SAdrian Chadd /*
5792d4583c4SAdrian Chadd  * @brief Decrypt an mbuf.
5802d4583c4SAdrian Chadd  *
5812d4583c4SAdrian Chadd  * This uses a temporary memory buffer to decrypt; the
5822d4583c4SAdrian Chadd  * current AES-GCM code expects things in a contiguous buffer
5832d4583c4SAdrian Chadd  * and this avoids the need of breaking out the GCTR and
5842d4583c4SAdrian Chadd  * GHASH routines into using mbuf iterators.
5852d4583c4SAdrian Chadd  *
5862d4583c4SAdrian Chadd  * @param key	ieee80211_key to use
5872d4583c4SAdrian Chadd  * @param mbuf	802.11 frame to decrypt
5882d4583c4SAdrian Chadd  * @param hdrlen	the length of the 802.11 header, including any padding
5892d4583c4SAdrian Chadd  * @returns 0 if error, > 0 if OK.
5902d4583c4SAdrian Chadd  */
5912d4583c4SAdrian Chadd static int
gcmp_decrypt(struct ieee80211_key * key,u_int64_t pn,struct mbuf * m,int hdrlen)5922d4583c4SAdrian Chadd gcmp_decrypt(struct ieee80211_key *key, u_int64_t pn, struct mbuf *m,
5932d4583c4SAdrian Chadd     int hdrlen)
5942d4583c4SAdrian Chadd {
5952d4583c4SAdrian Chadd 	const struct ieee80211_rx_stats *rxs;
5962d4583c4SAdrian Chadd 	struct gcmp_ctx *ctx = key->wk_private;
5972d4583c4SAdrian Chadd 	struct ieee80211_frame *wh;
5982d4583c4SAdrian Chadd 	int data_len, aad_len, iv_len, ret;
5992d4583c4SAdrian Chadd 	uint8_t aad[GCM_AAD_LEN];
6002d4583c4SAdrian Chadd 	uint8_t T[GCMP_MIC_LEN];
6012d4583c4SAdrian Chadd 	uint8_t iv[GCMP_IV_LEN];
6022d4583c4SAdrian Chadd 	uint8_t *p_pktbuf = NULL;
6032d4583c4SAdrian Chadd 	uint8_t *c_pktbuf = NULL;
6042d4583c4SAdrian Chadd 
6052d4583c4SAdrian Chadd 	rxs = ieee80211_get_rx_params_ptr(m);
6062d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_DECRYPTED) != 0)
6072d4583c4SAdrian Chadd 		return (1);
6082d4583c4SAdrian Chadd 
6092d4583c4SAdrian Chadd 	wh = mtod(m, struct ieee80211_frame *);
6102d4583c4SAdrian Chadd 
6112d4583c4SAdrian Chadd 	/* Data length doesn't include the MIC at the end */
6122d4583c4SAdrian Chadd 	data_len = m->m_pkthdr.len -
6132d4583c4SAdrian Chadd 	    (hdrlen + gcmp_get_header_len(key) + GCMP_MIC_LEN);
6142d4583c4SAdrian Chadd 
6152d4583c4SAdrian Chadd 	ctx->cc_vap->iv_stats.is_crypto_gcmp++;
6162d4583c4SAdrian Chadd 
6172d4583c4SAdrian Chadd 	p_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
6182d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
6192d4583c4SAdrian Chadd 	if (p_pktbuf == NULL) {
6202d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
6212d4583c4SAdrian Chadd 		return (0);
6222d4583c4SAdrian Chadd 	}
6232d4583c4SAdrian Chadd 	c_pktbuf = IEEE80211_MALLOC(data_len, M_TEMP,
6242d4583c4SAdrian Chadd 	    IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
6252d4583c4SAdrian Chadd 	if (c_pktbuf == NULL) {
6262d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_crypto_gcmp_nomem++;
6272d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
6282d4583c4SAdrian Chadd 		return (0);
6292d4583c4SAdrian Chadd 	}
6302d4583c4SAdrian Chadd 
6312d4583c4SAdrian Chadd 	/* Initialise AAD */
6322d4583c4SAdrian Chadd 	aad_len = gcmp_init_aad(wh, aad);
6332d4583c4SAdrian Chadd 
6342d4583c4SAdrian Chadd 	/* Initialise local IV copy to work on */
6352d4583c4SAdrian Chadd 	iv_len = gcmp_init_iv(iv, wh, pn);
6362d4583c4SAdrian Chadd 
6372d4583c4SAdrian Chadd 	/* Copy mbuf into ciphertext pktbuf */
6382d4583c4SAdrian Chadd 	m_copydata(m, hdrlen + gcmp_get_header_len(key), data_len,
6392d4583c4SAdrian Chadd 	    c_pktbuf);
6402d4583c4SAdrian Chadd 
6412d4583c4SAdrian Chadd 	/* Copy the MIC into the tag buffer */
6422d4583c4SAdrian Chadd 	m_copydata(m, hdrlen + gcmp_get_header_len(key) + data_len,
6432d4583c4SAdrian Chadd 	    GCMP_MIC_LEN, T);
6442d4583c4SAdrian Chadd 
6452d4583c4SAdrian Chadd 	/* Run decrypt */
6462d4583c4SAdrian Chadd 	/*
6472d4583c4SAdrian Chadd 	 * Note: aad + 2 to skip over the 2 byte length populated
6482d4583c4SAdrian Chadd 	 * at the beginning, since it's based on the AAD code in CCMP.
6492d4583c4SAdrian Chadd 	 */
6502d4583c4SAdrian Chadd 	ret = ieee80211_crypto_aes_gcm_ad(&ctx->cc_aes, iv, iv_len,
6512d4583c4SAdrian Chadd 	    c_pktbuf, data_len, aad + 2, aad_len, T, p_pktbuf);
6522d4583c4SAdrian Chadd 
6532d4583c4SAdrian Chadd 	/* If the MIC was stripped by HW/driver we are done. */
6542d4583c4SAdrian Chadd 	if ((rxs != NULL) && (rxs->c_pktflags & IEEE80211_RX_F_MIC_STRIP) != 0)
6552d4583c4SAdrian Chadd 		goto skip_ok;
6562d4583c4SAdrian Chadd 
6572d4583c4SAdrian Chadd 	if (ret != 0) {
6582d4583c4SAdrian Chadd 		/* Decrypt failure */
6592d4583c4SAdrian Chadd 		ctx->cc_vap->iv_stats.is_rx_gcmpmic++;
660*a54a240cSAdrian Chadd 		IEEE80211_NOTE_MAC(ctx->cc_vap, IEEE80211_MSG_CRYPTO,
661*a54a240cSAdrian Chadd 		    wh->i_addr2, "%s", "AES-GCM decrypt failed; MIC mismatch");
6622d4583c4SAdrian Chadd 		IEEE80211_FREE(p_pktbuf, M_TEMP);
6632d4583c4SAdrian Chadd 		IEEE80211_FREE(c_pktbuf, M_TEMP);
6642d4583c4SAdrian Chadd 		return (0);
6652d4583c4SAdrian Chadd 	}
6662d4583c4SAdrian Chadd 
6672d4583c4SAdrian Chadd skip_ok:
6682d4583c4SAdrian Chadd 	/* Copy data back over mbuf */
6692d4583c4SAdrian Chadd 	m_copyback(m, hdrlen + gcmp_get_header_len(key), data_len,
6702d4583c4SAdrian Chadd 	    p_pktbuf);
6712d4583c4SAdrian Chadd 
6722d4583c4SAdrian Chadd 	IEEE80211_FREE(p_pktbuf, M_TEMP);
6732d4583c4SAdrian Chadd 	IEEE80211_FREE(c_pktbuf, M_TEMP);
6742d4583c4SAdrian Chadd 
6752d4583c4SAdrian Chadd 	return (1);
6762d4583c4SAdrian Chadd }
6772d4583c4SAdrian Chadd 
6782d4583c4SAdrian Chadd /*
6792d4583c4SAdrian Chadd  * Module glue.
6802d4583c4SAdrian Chadd  */
6812d4583c4SAdrian Chadd IEEE80211_CRYPTO_MODULE(gcmp, 1);
6822d4583c4SAdrian Chadd IEEE80211_CRYPTO_MODULE_ADD(gcmp_256);
683