xref: /freebsd/sys/crypto/openssl/ossl.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2020 Netflix, Inc
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer,
11  *    without modification.
12  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
13  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
14  *    redistribution must be conditioned upon including a substantially
15  *    similar Disclaimer requirement for further binary redistribution.
16  *
17  * NO WARRANTY
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
21  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGES.
29  */
30 
31 /*
32  * A driver for the OpenCrypto framework which uses assembly routines
33  * from OpenSSL.
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 #include <sys/types.h>
40 #include <sys/bus.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 
45 #include <machine/fpu.h>
46 
47 #include <opencrypto/cryptodev.h>
48 #include <opencrypto/xform_auth.h>
49 
50 #include <crypto/openssl/ossl.h>
51 #include <crypto/openssl/ossl_chacha.h>
52 #include <crypto/openssl/ossl_cipher.h>
53 
54 #include "cryptodev_if.h"
55 
56 static MALLOC_DEFINE(M_OSSL, "ossl", "OpenSSL crypto");
57 
58 static void
59 ossl_identify(driver_t *driver, device_t parent)
60 {
61 
62 	if (device_find_child(parent, "ossl", -1) == NULL)
63 		BUS_ADD_CHILD(parent, 10, "ossl", -1);
64 }
65 
66 static int
67 ossl_probe(device_t dev)
68 {
69 
70 	device_set_desc(dev, "OpenSSL crypto");
71 	return (BUS_PROBE_DEFAULT);
72 }
73 
74 static int
75 ossl_attach(device_t dev)
76 {
77 	struct ossl_softc *sc;
78 
79 	sc = device_get_softc(dev);
80 
81 	ossl_cpuid(sc);
82 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct ossl_session),
83 	    CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC |
84 	    CRYPTOCAP_F_ACCEL_SOFTWARE);
85 	if (sc->sc_cid < 0) {
86 		device_printf(dev, "failed to allocate crypto driver id\n");
87 		return (ENXIO);
88 	}
89 
90 	return (0);
91 }
92 
93 static int
94 ossl_detach(device_t dev)
95 {
96 	struct ossl_softc *sc;
97 
98 	sc = device_get_softc(dev);
99 
100 	crypto_unregister_all(sc->sc_cid);
101 
102 	return (0);
103 }
104 
105 static struct auth_hash *
106 ossl_lookup_hash(const struct crypto_session_params *csp)
107 {
108 
109 	switch (csp->csp_auth_alg) {
110 	case CRYPTO_SHA1:
111 	case CRYPTO_SHA1_HMAC:
112 		return (&ossl_hash_sha1);
113 	case CRYPTO_SHA2_224:
114 	case CRYPTO_SHA2_224_HMAC:
115 		return (&ossl_hash_sha224);
116 	case CRYPTO_SHA2_256:
117 	case CRYPTO_SHA2_256_HMAC:
118 		return (&ossl_hash_sha256);
119 	case CRYPTO_SHA2_384:
120 	case CRYPTO_SHA2_384_HMAC:
121 		return (&ossl_hash_sha384);
122 	case CRYPTO_SHA2_512:
123 	case CRYPTO_SHA2_512_HMAC:
124 		return (&ossl_hash_sha512);
125 	case CRYPTO_POLY1305:
126 		return (&ossl_hash_poly1305);
127 	default:
128 		return (NULL);
129 	}
130 }
131 
132 static struct ossl_cipher*
133 ossl_lookup_cipher(const struct crypto_session_params *csp)
134 {
135 
136 	switch (csp->csp_cipher_alg) {
137 	case CRYPTO_AES_CBC:
138 		switch (csp->csp_cipher_klen * 8) {
139 		case 128:
140 		case 192:
141 		case 256:
142 			break;
143 		default:
144 			return (NULL);
145 		}
146 		return (&ossl_cipher_aes_cbc);
147 	case CRYPTO_CHACHA20:
148 		if (csp->csp_cipher_klen != CHACHA_KEY_SIZE)
149 			return (NULL);
150 		return (&ossl_cipher_chacha20);
151 	default:
152 		return (NULL);
153 	}
154 }
155 
156 static int
157 ossl_probesession(device_t dev, const struct crypto_session_params *csp)
158 {
159 	struct ossl_softc *sc = device_get_softc(dev);
160 
161 	if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
162 	    0)
163 		return (EINVAL);
164 	switch (csp->csp_mode) {
165 	case CSP_MODE_DIGEST:
166 		if (ossl_lookup_hash(csp) == NULL)
167 			return (EINVAL);
168 		break;
169 	case CSP_MODE_CIPHER:
170 		if (csp->csp_cipher_alg != CRYPTO_CHACHA20 && !sc->has_aes)
171 			return (EINVAL);
172 		if (ossl_lookup_cipher(csp) == NULL)
173 			return (EINVAL);
174 		break;
175 	case CSP_MODE_ETA:
176 		if (!sc->has_aes ||
177 		    csp->csp_cipher_alg == CRYPTO_CHACHA20 ||
178 		    ossl_lookup_hash(csp) == NULL ||
179 		    ossl_lookup_cipher(csp) == NULL)
180 			return (EINVAL);
181 		break;
182 	case CSP_MODE_AEAD:
183 		switch (csp->csp_cipher_alg) {
184 		case CRYPTO_CHACHA20_POLY1305:
185 			break;
186 		default:
187 			return (EINVAL);
188 		}
189 		break;
190 	default:
191 		return (EINVAL);
192 	}
193 
194 	return (CRYPTODEV_PROBE_ACCEL_SOFTWARE);
195 }
196 
197 static void
198 ossl_newsession_hash(struct ossl_session *s,
199     const struct crypto_session_params *csp)
200 {
201 	struct auth_hash *axf;
202 
203 	axf = ossl_lookup_hash(csp);
204 	s->hash.axf = axf;
205 	if (csp->csp_auth_mlen == 0)
206 		s->hash.mlen = axf->hashsize;
207 	else
208 		s->hash.mlen = csp->csp_auth_mlen;
209 
210 	if (csp->csp_auth_klen == 0) {
211 		axf->Init(&s->hash.ictx);
212 	} else {
213 		if (csp->csp_auth_key != NULL) {
214 			fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
215 			if (axf->Setkey != NULL) {
216 				axf->Init(&s->hash.ictx);
217 				axf->Setkey(&s->hash.ictx, csp->csp_auth_key,
218 				    csp->csp_auth_klen);
219 			} else {
220 				hmac_init_ipad(axf, csp->csp_auth_key,
221 				    csp->csp_auth_klen, &s->hash.ictx);
222 				hmac_init_opad(axf, csp->csp_auth_key,
223 				    csp->csp_auth_klen, &s->hash.octx);
224 			}
225 			fpu_kern_leave(curthread, NULL);
226 		}
227 	}
228 }
229 
230 static int
231 ossl_newsession_cipher(struct ossl_session *s,
232     const struct crypto_session_params *csp)
233 {
234 	struct ossl_cipher *cipher;
235 	int error = 0;
236 
237 	cipher = ossl_lookup_cipher(csp);
238 	if (cipher == NULL)
239 		return (EINVAL);
240 
241 	s->cipher.cipher = cipher;
242 
243 	if (csp->csp_cipher_key == NULL)
244 		return (0);
245 
246 	fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
247 	if (cipher->set_encrypt_key != NULL) {
248 		error = cipher->set_encrypt_key(csp->csp_cipher_key,
249 		    8 * csp->csp_cipher_klen, &s->cipher.enc_ctx);
250 		if (error != 0) {
251 			fpu_kern_leave(curthread, NULL);
252 			return (error);
253 		}
254 	}
255 	if (cipher->set_decrypt_key != NULL)
256 		error = cipher->set_decrypt_key(csp->csp_cipher_key,
257 		    8 * csp->csp_cipher_klen, &s->cipher.dec_ctx);
258 	fpu_kern_leave(curthread, NULL);
259 
260 	return (error);
261 }
262 
263 static int
264 ossl_newsession(device_t dev, crypto_session_t cses,
265     const struct crypto_session_params *csp)
266 {
267 	struct ossl_session *s;
268 	int error = 0;
269 
270 	s = crypto_get_driver_session(cses);
271 	switch (csp->csp_mode) {
272 	case CSP_MODE_DIGEST:
273 		ossl_newsession_hash(s, csp);
274 		break;
275 	case CSP_MODE_CIPHER:
276 		error = ossl_newsession_cipher(s, csp);
277 		break;
278 	case CSP_MODE_ETA:
279 		ossl_newsession_hash(s, csp);
280 		error = ossl_newsession_cipher(s, csp);
281 		break;
282 	}
283 
284 	return (error);
285 }
286 
287 static int
288 ossl_process_hash(struct ossl_session *s, struct cryptop *crp,
289     const struct crypto_session_params *csp)
290 {
291 	struct ossl_hash_context ctx;
292 	char digest[HASH_MAX_LEN];
293 	struct auth_hash *axf;
294 	int error;
295 
296 	axf = s->hash.axf;
297 
298 	if (crp->crp_auth_key == NULL) {
299 		ctx = s->hash.ictx;
300 	} else {
301 		if (axf->Setkey != NULL) {
302 			axf->Init(&ctx);
303 			axf->Setkey(&ctx, crp->crp_auth_key,
304 			    csp->csp_auth_klen);
305 		} else {
306 			hmac_init_ipad(axf, crp->crp_auth_key,
307 			    csp->csp_auth_klen, &ctx);
308 		}
309 	}
310 
311 	if (crp->crp_aad != NULL)
312 		error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
313 	else
314 		error = crypto_apply(crp, crp->crp_aad_start,
315 		    crp->crp_aad_length, axf->Update, &ctx);
316 	if (error)
317 		goto out;
318 
319 	error = crypto_apply(crp, crp->crp_payload_start,
320 	    crp->crp_payload_length, axf->Update, &ctx);
321 	if (error)
322 		goto out;
323 
324 	axf->Final(digest, &ctx);
325 
326 	if (csp->csp_auth_klen != 0 && axf->Setkey == NULL) {
327 		if (crp->crp_auth_key == NULL)
328 			ctx = s->hash.octx;
329 		else
330 			hmac_init_opad(axf, crp->crp_auth_key,
331 			    csp->csp_auth_klen, &ctx);
332 		axf->Update(&ctx, digest, axf->hashsize);
333 		axf->Final(digest, &ctx);
334 	}
335 
336 	if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
337 		char digest2[HASH_MAX_LEN];
338 
339 		crypto_copydata(crp, crp->crp_digest_start, s->hash.mlen,
340 		    digest2);
341 		if (timingsafe_bcmp(digest, digest2, s->hash.mlen) != 0)
342 			error = EBADMSG;
343 		explicit_bzero(digest2, sizeof(digest2));
344 	} else {
345 		crypto_copyback(crp, crp->crp_digest_start, s->hash.mlen,
346 		    digest);
347 	}
348 	explicit_bzero(digest, sizeof(digest));
349 
350 out:
351 	explicit_bzero(&ctx, sizeof(ctx));
352 	return (error);
353 }
354 
355 static int
356 ossl_process_eta(struct ossl_session *s, struct cryptop *crp,
357     const struct crypto_session_params *csp)
358 {
359 	int error;
360 
361 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
362 		error = s->cipher.cipher->process(&s->cipher, crp, csp);
363 		if (error == 0)
364 			error = ossl_process_hash(s, crp, csp);
365 	} else {
366 		error = ossl_process_hash(s, crp, csp);
367 		if (error == 0)
368 			error = s->cipher.cipher->process(&s->cipher, crp, csp);
369 	}
370 
371 	return (error);
372 }
373 
374 static int
375 ossl_process(device_t dev, struct cryptop *crp, int hint)
376 {
377 	const struct crypto_session_params *csp;
378 	struct ossl_session *s;
379 	int error;
380 	bool fpu_entered;
381 
382 	s = crypto_get_driver_session(crp->crp_session);
383 	csp = crypto_get_params(crp->crp_session);
384 
385 	if (is_fpu_kern_thread(0)) {
386 		fpu_entered = false;
387 	} else {
388 		fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
389 		fpu_entered = true;
390 	}
391 
392 	switch (csp->csp_mode) {
393 	case CSP_MODE_DIGEST:
394 		error = ossl_process_hash(s, crp, csp);
395 		break;
396 	case CSP_MODE_CIPHER:
397 		error = s->cipher.cipher->process(&s->cipher, crp, csp);
398 		break;
399 	case CSP_MODE_ETA:
400 		error = ossl_process_eta(s, crp, csp);
401 		break;
402 	case CSP_MODE_AEAD:
403 		if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
404 			error = ossl_chacha20_poly1305_encrypt(crp, csp);
405 		else
406 			error = ossl_chacha20_poly1305_decrypt(crp, csp);
407 		break;
408 	default:
409 		__assert_unreachable();
410 	}
411 
412 	if (fpu_entered)
413 		fpu_kern_leave(curthread, NULL);
414 
415 	crp->crp_etype = error;
416 	crypto_done(crp);
417 
418 	return (0);
419 }
420 
421 static device_method_t ossl_methods[] = {
422 	DEVMETHOD(device_identify,	ossl_identify),
423 	DEVMETHOD(device_probe,		ossl_probe),
424 	DEVMETHOD(device_attach,	ossl_attach),
425 	DEVMETHOD(device_detach,	ossl_detach),
426 
427 	DEVMETHOD(cryptodev_probesession, ossl_probesession),
428 	DEVMETHOD(cryptodev_newsession,	ossl_newsession),
429 	DEVMETHOD(cryptodev_process,	ossl_process),
430 
431 	DEVMETHOD_END
432 };
433 
434 static driver_t ossl_driver = {
435 	"ossl",
436 	ossl_methods,
437 	sizeof(struct ossl_softc)
438 };
439 
440 DRIVER_MODULE(ossl, nexus, ossl_driver, NULL, NULL);
441 MODULE_VERSION(ossl, 1);
442 MODULE_DEPEND(ossl, crypto, 1, 1, 1);
443