1 /*
2  * Octeon Crypto for OCF
3  *
4  * Written by David McCullough <[email protected]>
5  * Copyright (C) 2009 David McCullough
6  *
7  * LICENSE TERMS
8  *
9  * The free distribution and use of this software in both source and binary
10  * form is allowed (with or without changes) provided that:
11  *
12  *   1. distributions of this source code include the above copyright
13  *      notice, this list of conditions and the following disclaimer;
14  *
15  *   2. distributions in binary form include the above copyright
16  *      notice, this list of conditions and the following disclaimer
17  *      in the documentation and/or other associated materials;
18  *
19  *   3. the copyright holder's name is not used to endorse products
20  *      built using this software without specific written permission.
21  *
22  * DISCLAIMER
23  *
24  * This software is provided 'as is' with no explicit or implied warranties
25  * in respect of its properties, including, but not limited to, correctness
26  * and/or fitness for purpose.
27  * ---------------------------------------------------------------------------
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/uio.h>
41 
42 #include <opencrypto/cryptodev.h>
43 
44 #include <contrib/octeon-sdk/cvmx.h>
45 
46 #include <mips/cavium/cryptocteon/cryptocteonvar.h>
47 
48 #include "cryptodev_if.h"
49 
50 struct cryptocteon_softc {
51 	int32_t			sc_cid;		/* opencrypto id */
52 };
53 
54 int cryptocteon_debug = 0;
55 TUNABLE_INT("hw.cryptocteon.debug", &cryptocteon_debug);
56 
57 static void cryptocteon_identify(driver_t *, device_t);
58 static int cryptocteon_probe(device_t);
59 static int cryptocteon_attach(device_t);
60 
61 static int cryptocteon_process(device_t, struct cryptop *, int);
62 static int cryptocteon_probesession(device_t,
63     const struct crypto_session_params *);
64 static int cryptocteon_newsession(device_t, crypto_session_t,
65     const struct crypto_session_params *);
66 
67 static void
cryptocteon_identify(driver_t * drv,device_t parent)68 cryptocteon_identify(driver_t *drv, device_t parent)
69 {
70 	if (octeon_has_feature(OCTEON_FEATURE_CRYPTO))
71 		BUS_ADD_CHILD(parent, 0, "cryptocteon", 0);
72 }
73 
74 static int
cryptocteon_probe(device_t dev)75 cryptocteon_probe(device_t dev)
76 {
77 	device_set_desc(dev, "Octeon Secure Coprocessor");
78 	return (0);
79 }
80 
81 static int
cryptocteon_attach(device_t dev)82 cryptocteon_attach(device_t dev)
83 {
84 	struct cryptocteon_softc *sc;
85 
86 	sc = device_get_softc(dev);
87 
88 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct octo_sess),
89 	    CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC |
90 	    CRYPTOCAP_F_ACCEL_SOFTWARE);
91 	if (sc->sc_cid < 0) {
92 		device_printf(dev, "crypto_get_driverid ret %d\n", sc->sc_cid);
93 		return (ENXIO);
94 	}
95 
96 	return (0);
97 }
98 
99 static bool
cryptocteon_auth_supported(const struct crypto_session_params * csp)100 cryptocteon_auth_supported(const struct crypto_session_params *csp)
101 {
102 	u_int hash_len;
103 
104 	switch (csp->csp_auth_alg) {
105 	case CRYPTO_SHA1_HMAC:
106 		hash_len = SHA1_HASH_LEN;
107 		break;
108 	default:
109 		return (false);
110 	}
111 
112 	if (csp->csp_auth_klen > hash_len)
113 		return (false);
114 	return (true);
115 }
116 
117 static bool
cryptocteon_cipher_supported(const struct crypto_session_params * csp)118 cryptocteon_cipher_supported(const struct crypto_session_params *csp)
119 {
120 
121 	switch (csp->csp_cipher_alg) {
122 	case CRYPTO_AES_CBC:
123 		if (csp->csp_ivlen != 16)
124 			return (false);
125 		if (csp->csp_cipher_klen != 16 &&
126 		    csp->csp_cipher_klen != 24 &&
127 		    csp->csp_cipher_klen != 32)
128 			return (false);
129 		break;
130 	default:
131 		return (false);
132 	}
133 
134 	return (true);
135 }
136 
137 static int
cryptocteon_probesession(device_t dev,const struct crypto_session_params * csp)138 cryptocteon_probesession(device_t dev, const struct crypto_session_params *csp)
139 {
140 
141 	if (csp->csp_flags != 0)
142 		return (EINVAL);
143 	switch (csp->csp_mode) {
144 	case CSP_MODE_DIGEST:
145 		if (!cryptocteon_auth_supported(csp))
146 			return (EINVAL);
147 		break;
148 	case CSP_MODE_CIPHER:
149 		if (!cryptocteon_cipher_supported(csp))
150 			return (EINVAL);
151 		break;
152 	case CSP_MODE_ETA:
153 		if (!cryptocteon_auth_supported(csp) ||
154 		    !cryptocteon_cipher_supported(csp))
155 			return (EINVAL);
156 		break;
157 	default:
158 		return (EINVAL);
159 	}
160 	return (CRYPTODEV_PROBE_ACCEL_SOFTWARE);
161 }
162 
163 static void
cryptocteon_calc_hash(const struct crypto_session_params * csp,const char * key,struct octo_sess * ocd)164 cryptocteon_calc_hash(const struct crypto_session_params *csp, const char *key,
165     struct octo_sess *ocd)
166 {
167 	char hash_key[SHA1_HASH_LEN];
168 
169 	memset(hash_key, 0, sizeof(hash_key));
170 	memcpy(hash_key, key, csp->csp_auth_klen);
171 	octo_calc_hash(csp->csp_auth_alg == CRYPTO_SHA1_HMAC, hash_key,
172 	    ocd->octo_hminner, ocd->octo_hmouter);
173 }
174 
175 /* Generate a new octo session. */
176 static int
cryptocteon_newsession(device_t dev,crypto_session_t cses,const struct crypto_session_params * csp)177 cryptocteon_newsession(device_t dev, crypto_session_t cses,
178     const struct crypto_session_params *csp)
179 {
180 	struct cryptocteon_softc *sc;
181 	struct octo_sess *ocd;
182 
183 	sc = device_get_softc(dev);
184 
185 	ocd = crypto_get_driver_session(cses);
186 
187 	ocd->octo_encklen = csp->csp_cipher_klen;
188 	if (csp->csp_cipher_key != NULL)
189 		memcpy(ocd->octo_enckey, csp->csp_cipher_key,
190 		    ocd->octo_encklen);
191 
192 	if (csp->csp_auth_key != NULL)
193 		cryptocteon_calc_hash(csp, csp->csp_auth_key, ocd);
194 
195 	ocd->octo_mlen = csp->csp_auth_mlen;
196 	if (csp->csp_auth_mlen == 0) {
197 		switch (csp->csp_auth_alg) {
198 		case CRYPTO_SHA1_HMAC:
199 			ocd->octo_mlen = SHA1_HASH_LEN;
200 			break;
201 		}
202 	}
203 
204 	switch (csp->csp_mode) {
205 	case CSP_MODE_DIGEST:
206 		switch (csp->csp_auth_alg) {
207 		case CRYPTO_SHA1_HMAC:
208 			ocd->octo_encrypt = octo_null_sha1_encrypt;
209 			ocd->octo_decrypt = octo_null_sha1_encrypt;
210 			break;
211 		}
212 		break;
213 	case CSP_MODE_CIPHER:
214 		switch (csp->csp_cipher_alg) {
215 		case CRYPTO_AES_CBC:
216 			ocd->octo_encrypt = octo_aes_cbc_encrypt;
217 			ocd->octo_decrypt = octo_aes_cbc_decrypt;
218 			break;
219 		}
220 		break;
221 	case CSP_MODE_ETA:
222 		switch (csp->csp_cipher_alg) {
223 		case CRYPTO_AES_CBC:
224 			switch (csp->csp_auth_alg) {
225 			case CRYPTO_SHA1_HMAC:
226 				ocd->octo_encrypt = octo_aes_cbc_sha1_encrypt;
227 				ocd->octo_decrypt = octo_aes_cbc_sha1_decrypt;
228 				break;
229 			}
230 			break;
231 		}
232 		break;
233 	}
234 
235 	KASSERT(ocd->octo_encrypt != NULL && ocd->octo_decrypt != NULL,
236 	    ("%s: missing function pointers", __func__));
237 
238 	return (0);
239 }
240 
241 /*
242  * Process a request.
243  */
244 static int
cryptocteon_process(device_t dev,struct cryptop * crp,int hint)245 cryptocteon_process(device_t dev, struct cryptop *crp, int hint)
246 {
247 	const struct crypto_session_params *csp;
248 	struct octo_sess *od;
249 	size_t iovcnt, iovlen;
250 	struct mbuf *m = NULL;
251 	struct uio *uiop = NULL;
252 	unsigned char *ivp = NULL;
253 	unsigned char iv_data[16];
254 	unsigned char icv[SHA1_HASH_LEN], icv2[SHA1_HASH_LEN];
255 	int auth_off, auth_len, crypt_off, crypt_len;
256 	struct cryptocteon_softc *sc;
257 
258 	sc = device_get_softc(dev);
259 
260 	crp->crp_etype = 0;
261 
262 	od = crypto_get_driver_session(crp->crp_session);
263 	csp = crypto_get_params(crp->crp_session);
264 
265 	/*
266 	 * The crypto routines assume that the regions to auth and
267 	 * cipher are exactly 8 byte multiples and aligned on 8
268 	 * byte logical boundaries within the iovecs.
269 	 */
270 	if (crp->crp_aad_length % 8 != 0 || crp->crp_payload_length % 8 != 0) {
271 		crp->crp_etype = EFBIG;
272 		goto done;
273 	}
274 
275 	/*
276 	 * As currently written, the crypto routines assume the AAD and
277 	 * payload are adjacent.
278 	 */
279 	if (crp->crp_aad_length != 0 && crp->crp_payload_start !=
280 	    crp->crp_aad_start + crp->crp_aad_length) {
281 		crp->crp_etype = EFBIG;
282 		goto done;
283 	}
284 
285 	crypt_off = crp->crp_payload_start;
286 	crypt_len = crp->crp_payload_length;
287 	if (crp->crp_aad_length != 0) {
288 		auth_off = crp->crp_aad_start;
289 		auth_len = crp->crp_aad_length + crp->crp_payload_length;
290 	} else {
291 		auth_off = crypt_off;
292 		auth_len = crypt_len;
293 	}
294 
295 	/*
296 	 * do some error checking outside of the loop for m and IOV processing
297 	 * this leaves us with valid m or uiop pointers for later
298 	 */
299 	switch (crp->crp_buf.cb_type) {
300 	case CRYPTO_BUF_MBUF:
301 	{
302 		unsigned frags;
303 
304 		m = crp->crp_buf.cb_mbuf;
305 		for (frags = 0; m != NULL; frags++)
306 			m = m->m_next;
307 
308 		if (frags >= UIO_MAXIOV) {
309 			printf("%s,%d: %d frags > UIO_MAXIOV", __FILE__, __LINE__, frags);
310 			crp->crp_etype = EFBIG;
311 			goto done;
312 		}
313 
314 		m = crp->crp_buf.cb_mbuf;
315 		break;
316 	}
317 	case CRYPTO_BUF_UIO:
318 		uiop = crp->crp_buf.cb_uio;
319 		if (uiop->uio_iovcnt > UIO_MAXIOV) {
320 			printf("%s,%d: %d uio_iovcnt > UIO_MAXIOV", __FILE__, __LINE__,
321 			       uiop->uio_iovcnt);
322 			crp->crp_etype = EFBIG;
323 			goto done;
324 		}
325 		break;
326 	default:
327 		break;
328 	}
329 
330 	if (csp->csp_cipher_alg != 0) {
331 		if (crp->crp_flags & CRYPTO_F_IV_SEPARATE)
332 			ivp = crp->crp_iv;
333 		else {
334 			crypto_copydata(crp, crp->crp_iv_start, csp->csp_ivlen,
335 			    iv_data);
336 			ivp = iv_data;
337 		}
338 	}
339 
340 	/*
341 	 * setup the I/O vector to cover the buffer
342 	 */
343 	switch (crp->crp_buf.cb_type) {
344 	case CRYPTO_BUF_MBUF:
345 		iovcnt = 0;
346 		iovlen = 0;
347 
348 		while (m != NULL) {
349 			od->octo_iov[iovcnt].iov_base = mtod(m, void *);
350 			od->octo_iov[iovcnt].iov_len = m->m_len;
351 
352 			m = m->m_next;
353 			iovlen += od->octo_iov[iovcnt++].iov_len;
354 		}
355 		break;
356 	case CRYPTO_BUF_UIO:
357 		iovlen = 0;
358 		for (iovcnt = 0; iovcnt < uiop->uio_iovcnt; iovcnt++) {
359 			od->octo_iov[iovcnt].iov_base = uiop->uio_iov[iovcnt].iov_base;
360 			od->octo_iov[iovcnt].iov_len = uiop->uio_iov[iovcnt].iov_len;
361 
362 			iovlen += od->octo_iov[iovcnt].iov_len;
363 		}
364 		break;
365 	case CRYPTO_BUF_CONTIG:
366 		iovlen = crp->crp_buf.cb_buf_len;
367 		od->octo_iov[0].iov_base = crp->crp_buf.cb_buf;
368 		od->octo_iov[0].iov_len = crp->crp_buf.cb_buf_len;
369 		iovcnt = 1;
370 		break;
371 	default:
372 		panic("can't happen");
373 	}
374 
375 	/*
376 	 * setup a new explicit key
377 	 */
378 	if (crp->crp_cipher_key != NULL)
379 		memcpy(od->octo_enckey, crp->crp_cipher_key, od->octo_encklen);
380 	if (crp->crp_auth_key != NULL)
381 		cryptocteon_calc_hash(csp, crp->crp_auth_key, od);
382 
383 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
384 		(*od->octo_encrypt)(od, od->octo_iov, iovcnt, iovlen,
385 		    auth_off, auth_len, crypt_off, crypt_len, icv, ivp);
386 	else
387 		(*od->octo_decrypt)(od, od->octo_iov, iovcnt, iovlen,
388 		    auth_off, auth_len, crypt_off, crypt_len, icv, ivp);
389 
390 	if (csp->csp_auth_alg != 0) {
391 		if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
392 			crypto_copydata(crp, crp->crp_digest_start,
393 			    od->octo_mlen, icv2);
394 			if (timingsafe_bcmp(icv, icv2, od->octo_mlen) != 0)
395 				crp->crp_etype = EBADMSG;
396 		} else
397 			crypto_copyback(crp, crp->crp_digest_start,
398 			    od->octo_mlen, icv);
399 	}
400 done:
401 	crypto_done(crp);
402 	return (0);
403 }
404 
405 static device_method_t cryptocteon_methods[] = {
406 	/* device methods */
407 	DEVMETHOD(device_identify,	cryptocteon_identify),
408 	DEVMETHOD(device_probe,		cryptocteon_probe),
409 	DEVMETHOD(device_attach,	cryptocteon_attach),
410 
411 	/* crypto device methods */
412 	DEVMETHOD(cryptodev_probesession, cryptocteon_probesession),
413 	DEVMETHOD(cryptodev_newsession,	cryptocteon_newsession),
414 	DEVMETHOD(cryptodev_process,	cryptocteon_process),
415 	{ 0, 0 }
416 };
417 
418 static driver_t cryptocteon_driver = {
419 	"cryptocteon",
420 	cryptocteon_methods,
421 	sizeof (struct cryptocteon_softc),
422 };
423 static devclass_t cryptocteon_devclass;
424 DRIVER_MODULE(cryptocteon, nexus, cryptocteon_driver, cryptocteon_devclass, 0, 0);
425