1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2001 Atsushi Onoe
8  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * Alternatively, this software may be distributed under the terms of the
23  * GNU General Public License ("GPL") version 2 as published by the Free
24  * Software Foundation.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 /*
41  * IEEE 802.11i CCMP crypto support.
42  */
43 #include <sys/byteorder.h>
44 #include <sys/crypto/common.h>
45 #include <sys/crypto/api.h>
46 #include <sys/crc32.h>
47 #include <sys/random.h>
48 #include "net80211_impl.h"
49 
50 struct ccmp_ctx {
51 	struct ieee80211com *cc_ic;	/* for diagnostics */
52 };
53 
54 static void *ccmp_attach(struct ieee80211com *, struct ieee80211_key *);
55 static void ccmp_detach(struct ieee80211_key *);
56 static int ccmp_setkey(struct ieee80211_key *);
57 static int ccmp_encap(struct ieee80211_key *k, mblk_t *, uint8_t);
58 static int ccmp_decap(struct ieee80211_key *, mblk_t *, int);
59 static int ccmp_enmic(struct ieee80211_key *, mblk_t *, int);
60 static int ccmp_demic(struct ieee80211_key *, mblk_t *, int);
61 
62 const struct ieee80211_cipher ccmp = {
63 	"AES-CCM",
64 	IEEE80211_CIPHER_AES_CCM,
65 	IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
66 	    IEEE80211_WEP_EXTIVLEN,
67 	IEEE80211_WEP_MICLEN,
68 	0,
69 	ccmp_attach,
70 	ccmp_detach,
71 	ccmp_setkey,
72 	ccmp_encap,
73 	ccmp_decap,
74 	ccmp_enmic,
75 	ccmp_demic,
76 };
77 
78 /* ARGSUSED */
79 static void *
80 ccmp_attach(struct ieee80211com *ic, struct ieee80211_key *k)
81 {
82 	struct ccmp_ctx *ctx;
83 
84 	ctx = kmem_zalloc(sizeof (struct ccmp_ctx), KM_SLEEP);
85 	if (ctx == NULL)
86 		return (NULL);
87 
88 	ctx->cc_ic = ic;
89 	return (ctx);
90 }
91 
92 static void
93 ccmp_detach(struct ieee80211_key *k)
94 {
95 	struct ccmp_ctx *ctx = k->wk_private;
96 
97 	if (ctx != NULL)
98 		kmem_free(ctx, sizeof (struct ccmp_ctx));
99 }
100 
101 static int
102 ccmp_setkey(struct ieee80211_key *k)
103 {
104 	if (k->wk_keylen != (128/NBBY))
105 		return (0);
106 
107 	return (1);
108 }
109 
110 /*
111  * Add privacy headers appropriate for the specified key.
112  */
113 static int
114 ccmp_encap(struct ieee80211_key *k, mblk_t *mp, uint8_t keyid)
115 {
116 	uint8_t *ivp;
117 	int hdrlen;
118 
119 	hdrlen = ieee80211_hdrspace(mp->b_rptr);
120 	/*
121 	 * Copy down 802.11 header and add the IV, KeyID, and ExtIV.
122 	 */
123 	ivp = mp->b_rptr;
124 	ivp += hdrlen;
125 
126 	k->wk_keytsc++;				/* wrap at 48 bits */
127 	ivp[0] = k->wk_keytsc >> 0;		/* PN0 */
128 	ivp[1] = k->wk_keytsc >> 8;		/* PN1 */
129 	ivp[2] = 0;				/* Reserved */
130 	ivp[3] = keyid | IEEE80211_WEP_EXTIV;	/* KeyID | ExtID */
131 	ivp[4] = k->wk_keytsc >> 16;		/* PN2 */
132 	ivp[5] = k->wk_keytsc >> 24;		/* PN3 */
133 	ivp[6] = k->wk_keytsc >> 32;		/* PN4 */
134 	ivp[7] = k->wk_keytsc >> 40;		/* PN5 */
135 
136 	/*
137 	 * NB: software CCMP is not supported.
138 	 */
139 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
140 		return (0);
141 
142 	return (1);
143 }
144 
145 /*
146  * Validate and strip privacy headers (and trailer) for a
147  * received frame. The specified key should be correct but
148  * is also verified.
149  */
150 static int
151 ccmp_decap(struct ieee80211_key *k, mblk_t *mp, int hdrlen)
152 {
153 	struct ieee80211_frame tmp;
154 	uint8_t *ivp;
155 	uint64_t pn;
156 
157 	/*
158 	 * Header should have extended IV and sequence number;
159 	 * verify the former and validate the latter.
160 	 */
161 	ivp = mp->b_rptr + hdrlen;
162 	if ((ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) == 0) {
163 		/*
164 		 * No extended IV; discard frame.
165 		 */
166 		return (0);
167 	}
168 
169 	pn = ieee80211_read_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
170 	if (pn <= k->wk_keyrsc) {
171 		/*
172 		 * Replay violation.
173 		 */
174 		return (0);
175 	}
176 
177 	/*
178 	 * NB: software CCMP is not supported.
179 	 */
180 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
181 		return (0);
182 
183 	/*
184 	 * Copy up 802.11 header and strip crypto bits.
185 	 */
186 	bcopy(mp->b_rptr, &tmp, hdrlen);
187 	bcopy(&tmp, mp->b_rptr + ccmp.ic_header, hdrlen);
188 	mp->b_rptr += ccmp.ic_header;
189 	mp->b_wptr -= ccmp.ic_trailer;
190 
191 	/*
192 	 * Ok to update rsc now.
193 	 */
194 	k->wk_keyrsc = pn;
195 
196 	return (1);
197 }
198 
199 /*
200  * Add MIC to the frame as needed.
201  */
202 /* ARGSUSED */
203 static int
204 ccmp_enmic(struct ieee80211_key *k, mblk_t *mp, int force)
205 {
206 	return (1);
207 }
208 
209 /*
210  * Verify and strip MIC from the frame.
211  */
212 /* ARGSUSED */
213 static int
214 ccmp_demic(struct ieee80211_key *k, mblk_t *mp, int force)
215 {
216 	return (1);
217 }
218