xref: /freebsd/sys/crypto/openssl/ossl.c (revision e0c4386e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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/types.h>
37 #include <sys/bus.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 
42 #include <machine/fpu.h>
43 
44 #include <opencrypto/cryptodev.h>
45 #include <opencrypto/xform_auth.h>
46 
47 #include <crypto/openssl/ossl.h>
48 #include <crypto/openssl/ossl_chacha.h>
49 #include <crypto/openssl/ossl_cipher.h>
50 
51 #include "cryptodev_if.h"
52 
53 static MALLOC_DEFINE(M_OSSL, "ossl", "OpenSSL crypto");
54 
55 static void
56 ossl_identify(driver_t *driver, device_t parent)
57 {
58 
59 	if (device_find_child(parent, "ossl", -1) == NULL)
60 		BUS_ADD_CHILD(parent, 10, "ossl", -1);
61 }
62 
63 static int
64 ossl_probe(device_t dev)
65 {
66 
67 	device_set_desc(dev, "OpenSSL crypto");
68 	return (BUS_PROBE_DEFAULT);
69 }
70 
71 static int
72 ossl_attach(device_t dev)
73 {
74 	struct ossl_softc *sc;
75 
76 	sc = device_get_softc(dev);
77 
78 	sc->has_aes = sc->has_aes_gcm = false;
79 
80 	ossl_cpuid(sc);
81 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct ossl_session),
82 	    CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC |
83 	    CRYPTOCAP_F_ACCEL_SOFTWARE);
84 	if (sc->sc_cid < 0) {
85 		device_printf(dev, "failed to allocate crypto driver id\n");
86 		return (ENXIO);
87 	}
88 
89 	return (0);
90 }
91 
92 static int
93 ossl_detach(device_t dev)
94 {
95 	struct ossl_softc *sc;
96 
97 	sc = device_get_softc(dev);
98 
99 	crypto_unregister_all(sc->sc_cid);
100 
101 	return (0);
102 }
103 
104 static struct auth_hash *
105 ossl_lookup_hash(const struct crypto_session_params *csp)
106 {
107 
108 	switch (csp->csp_auth_alg) {
109 	case CRYPTO_SHA1:
110 	case CRYPTO_SHA1_HMAC:
111 		return (&ossl_hash_sha1);
112 	case CRYPTO_SHA2_224:
113 	case CRYPTO_SHA2_224_HMAC:
114 		return (&ossl_hash_sha224);
115 	case CRYPTO_SHA2_256:
116 	case CRYPTO_SHA2_256_HMAC:
117 		return (&ossl_hash_sha256);
118 	case CRYPTO_SHA2_384:
119 	case CRYPTO_SHA2_384_HMAC:
120 		return (&ossl_hash_sha384);
121 	case CRYPTO_SHA2_512:
122 	case CRYPTO_SHA2_512_HMAC:
123 		return (&ossl_hash_sha512);
124 	case CRYPTO_POLY1305:
125 		return (&ossl_hash_poly1305);
126 	default:
127 		return (NULL);
128 	}
129 }
130 
131 static struct ossl_cipher*
132 ossl_lookup_cipher(const struct crypto_session_params *csp)
133 {
134 
135 	switch (csp->csp_cipher_alg) {
136 	case CRYPTO_AES_CBC:
137 		switch (csp->csp_cipher_klen * 8) {
138 		case 128:
139 		case 192:
140 		case 256:
141 			break;
142 		default:
143 			return (NULL);
144 		}
145 		return (&ossl_cipher_aes_cbc);
146 	case CRYPTO_AES_NIST_GCM_16:
147 		switch (csp->csp_cipher_klen * 8) {
148 		case 128:
149 		case 192:
150 		case 256:
151 			break;
152 		default:
153 			return (NULL);
154 		}
155 		return (&ossl_cipher_aes_gcm);
156 	case CRYPTO_CHACHA20:
157 		if (csp->csp_cipher_klen != CHACHA_KEY_SIZE)
158 			return (NULL);
159 		return (&ossl_cipher_chacha20);
160 	default:
161 		return (NULL);
162 	}
163 }
164 
165 static int
166 ossl_probesession(device_t dev, const struct crypto_session_params *csp)
167 {
168 	struct ossl_softc *sc = device_get_softc(dev);
169 
170 	if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
171 	    0)
172 		return (EINVAL);
173 	switch (csp->csp_mode) {
174 	case CSP_MODE_DIGEST:
175 		if (ossl_lookup_hash(csp) == NULL)
176 			return (EINVAL);
177 		break;
178 	case CSP_MODE_CIPHER:
179 		if (csp->csp_cipher_alg != CRYPTO_CHACHA20 && !sc->has_aes)
180 			return (EINVAL);
181 		if (ossl_lookup_cipher(csp) == NULL)
182 			return (EINVAL);
183 		break;
184 	case CSP_MODE_ETA:
185 		if (!sc->has_aes ||
186 		    csp->csp_cipher_alg == CRYPTO_CHACHA20 ||
187 		    ossl_lookup_hash(csp) == NULL ||
188 		    ossl_lookup_cipher(csp) == NULL)
189 			return (EINVAL);
190 		break;
191 	case CSP_MODE_AEAD:
192 		switch (csp->csp_cipher_alg) {
193 		case CRYPTO_CHACHA20_POLY1305:
194 			break;
195 		case CRYPTO_AES_NIST_GCM_16:
196 			if (!sc->has_aes_gcm || ossl_lookup_cipher(csp) == NULL)
197 				return (EINVAL);
198 			if (csp->csp_ivlen != AES_GCM_IV_LEN)
199 				return (EINVAL);
200 			if (csp->csp_auth_mlen != 0 &&
201 			    csp->csp_auth_mlen != GMAC_DIGEST_LEN)
202 				return (EINVAL);
203 			break;
204 		default:
205 			return (EINVAL);
206 		}
207 		break;
208 	default:
209 		return (EINVAL);
210 	}
211 
212 	return (CRYPTODEV_PROBE_ACCEL_SOFTWARE);
213 }
214 
215 static void
216 ossl_newsession_hash(struct ossl_session *s,
217     const struct crypto_session_params *csp)
218 {
219 	struct auth_hash *axf;
220 
221 	axf = ossl_lookup_hash(csp);
222 	s->hash.axf = axf;
223 	if (csp->csp_auth_mlen == 0)
224 		s->hash.mlen = axf->hashsize;
225 	else
226 		s->hash.mlen = csp->csp_auth_mlen;
227 
228 	if (csp->csp_auth_klen == 0) {
229 		axf->Init(&s->hash.ictx);
230 	} else {
231 		if (csp->csp_auth_key != NULL) {
232 			fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
233 			if (axf->Setkey != NULL) {
234 				axf->Init(&s->hash.ictx);
235 				axf->Setkey(&s->hash.ictx, csp->csp_auth_key,
236 				    csp->csp_auth_klen);
237 			} else {
238 				hmac_init_ipad(axf, csp->csp_auth_key,
239 				    csp->csp_auth_klen, &s->hash.ictx);
240 				hmac_init_opad(axf, csp->csp_auth_key,
241 				    csp->csp_auth_klen, &s->hash.octx);
242 			}
243 			fpu_kern_leave(curthread, NULL);
244 		}
245 	}
246 }
247 
248 static int
249 ossl_newsession_cipher(struct ossl_session *s,
250     const struct crypto_session_params *csp)
251 {
252 	struct ossl_cipher *cipher;
253 	int error = 0;
254 
255 	cipher = ossl_lookup_cipher(csp);
256 	if (cipher == NULL)
257 		return (EINVAL);
258 
259 	s->cipher.cipher = cipher;
260 
261 	if (csp->csp_cipher_key == NULL)
262 		return (0);
263 
264 	fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
265 	if (cipher->set_encrypt_key != NULL) {
266 		error = cipher->set_encrypt_key(csp->csp_cipher_key,
267 		    8 * csp->csp_cipher_klen, &s->cipher.enc_ctx);
268 		if (error != 0) {
269 			fpu_kern_leave(curthread, NULL);
270 			return (error);
271 		}
272 	}
273 	if (cipher->set_decrypt_key != NULL)
274 		error = cipher->set_decrypt_key(csp->csp_cipher_key,
275 		    8 * csp->csp_cipher_klen, &s->cipher.dec_ctx);
276 	fpu_kern_leave(curthread, NULL);
277 
278 	return (error);
279 }
280 
281 static int
282 ossl_newsession(device_t dev, crypto_session_t cses,
283     const struct crypto_session_params *csp)
284 {
285 	struct ossl_session *s;
286 	int error = 0;
287 
288 	s = crypto_get_driver_session(cses);
289 	switch (csp->csp_mode) {
290 	case CSP_MODE_DIGEST:
291 		ossl_newsession_hash(s, csp);
292 		break;
293 	case CSP_MODE_CIPHER:
294 		error = ossl_newsession_cipher(s, csp);
295 		break;
296 	case CSP_MODE_ETA:
297 		ossl_newsession_hash(s, csp);
298 		error = ossl_newsession_cipher(s, csp);
299 		break;
300 	case CSP_MODE_AEAD:
301 		if (csp->csp_cipher_alg != CRYPTO_CHACHA20_POLY1305)
302 			error = ossl_newsession_cipher(s, csp);
303 		break;
304 	default:
305 		__assert_unreachable();
306 	}
307 
308 	return (error);
309 }
310 
311 static int
312 ossl_process_hash(struct ossl_session *s, struct cryptop *crp,
313     const struct crypto_session_params *csp)
314 {
315 	struct ossl_hash_context ctx;
316 	char digest[HASH_MAX_LEN];
317 	struct auth_hash *axf;
318 	int error;
319 
320 	axf = s->hash.axf;
321 
322 	if (crp->crp_auth_key == NULL) {
323 		ctx = s->hash.ictx;
324 	} else {
325 		if (axf->Setkey != NULL) {
326 			axf->Init(&ctx);
327 			axf->Setkey(&ctx, crp->crp_auth_key,
328 			    csp->csp_auth_klen);
329 		} else {
330 			hmac_init_ipad(axf, crp->crp_auth_key,
331 			    csp->csp_auth_klen, &ctx);
332 		}
333 	}
334 
335 	if (crp->crp_aad != NULL)
336 		error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
337 	else
338 		error = crypto_apply(crp, crp->crp_aad_start,
339 		    crp->crp_aad_length, axf->Update, &ctx);
340 	if (error)
341 		goto out;
342 
343 	error = crypto_apply(crp, crp->crp_payload_start,
344 	    crp->crp_payload_length, axf->Update, &ctx);
345 	if (error)
346 		goto out;
347 
348 	axf->Final(digest, &ctx);
349 
350 	if (csp->csp_auth_klen != 0 && axf->Setkey == NULL) {
351 		if (crp->crp_auth_key == NULL)
352 			ctx = s->hash.octx;
353 		else
354 			hmac_init_opad(axf, crp->crp_auth_key,
355 			    csp->csp_auth_klen, &ctx);
356 		axf->Update(&ctx, digest, axf->hashsize);
357 		axf->Final(digest, &ctx);
358 	}
359 
360 	if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
361 		char digest2[HASH_MAX_LEN];
362 
363 		crypto_copydata(crp, crp->crp_digest_start, s->hash.mlen,
364 		    digest2);
365 		if (timingsafe_bcmp(digest, digest2, s->hash.mlen) != 0)
366 			error = EBADMSG;
367 		explicit_bzero(digest2, sizeof(digest2));
368 	} else {
369 		crypto_copyback(crp, crp->crp_digest_start, s->hash.mlen,
370 		    digest);
371 	}
372 	explicit_bzero(digest, sizeof(digest));
373 
374 out:
375 	explicit_bzero(&ctx, sizeof(ctx));
376 	return (error);
377 }
378 
379 static int
380 ossl_process_cipher(struct ossl_session *s, struct cryptop *crp,
381     const struct crypto_session_params *csp)
382 {
383 	return (s->cipher.cipher->process(&s->cipher, crp, csp));
384 }
385 
386 static int
387 ossl_process_eta(struct ossl_session *s, struct cryptop *crp,
388     const struct crypto_session_params *csp)
389 {
390 	int error;
391 
392 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
393 		error = s->cipher.cipher->process(&s->cipher, crp, csp);
394 		if (error == 0)
395 			error = ossl_process_hash(s, crp, csp);
396 	} else {
397 		error = ossl_process_hash(s, crp, csp);
398 		if (error == 0)
399 			error = s->cipher.cipher->process(&s->cipher, crp, csp);
400 	}
401 
402 	return (error);
403 }
404 
405 static int
406 ossl_process_aead(struct ossl_session *s, struct cryptop *crp,
407     const struct crypto_session_params *csp)
408 {
409 	if (csp->csp_cipher_alg == CRYPTO_CHACHA20_POLY1305) {
410 		if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
411 			return (ossl_chacha20_poly1305_encrypt(crp, csp));
412 		else
413 			return (ossl_chacha20_poly1305_decrypt(crp, csp));
414 	} else {
415 		return (s->cipher.cipher->process(&s->cipher, crp, csp));
416 	}
417 }
418 
419 static int
420 ossl_process(device_t dev, struct cryptop *crp, int hint)
421 {
422 	const struct crypto_session_params *csp;
423 	struct ossl_session *s;
424 	int error;
425 	bool fpu_entered;
426 
427 	s = crypto_get_driver_session(crp->crp_session);
428 	csp = crypto_get_params(crp->crp_session);
429 
430 	if (is_fpu_kern_thread(0)) {
431 		fpu_entered = false;
432 	} else {
433 		fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
434 		fpu_entered = true;
435 	}
436 
437 	switch (csp->csp_mode) {
438 	case CSP_MODE_DIGEST:
439 		error = ossl_process_hash(s, crp, csp);
440 		break;
441 	case CSP_MODE_CIPHER:
442 		error = ossl_process_cipher(s, crp, csp);
443 		break;
444 	case CSP_MODE_ETA:
445 		error = ossl_process_eta(s, crp, csp);
446 		break;
447 	case CSP_MODE_AEAD:
448 		error = ossl_process_aead(s, crp, csp);
449 		break;
450 	default:
451 		__assert_unreachable();
452 	}
453 
454 	if (fpu_entered)
455 		fpu_kern_leave(curthread, NULL);
456 
457 	crp->crp_etype = error;
458 	crypto_done(crp);
459 
460 	return (0);
461 }
462 
463 static device_method_t ossl_methods[] = {
464 	DEVMETHOD(device_identify,	ossl_identify),
465 	DEVMETHOD(device_probe,		ossl_probe),
466 	DEVMETHOD(device_attach,	ossl_attach),
467 	DEVMETHOD(device_detach,	ossl_detach),
468 
469 	DEVMETHOD(cryptodev_probesession, ossl_probesession),
470 	DEVMETHOD(cryptodev_newsession,	ossl_newsession),
471 	DEVMETHOD(cryptodev_process,	ossl_process),
472 
473 	DEVMETHOD_END
474 };
475 
476 static driver_t ossl_driver = {
477 	"ossl",
478 	ossl_methods,
479 	sizeof(struct ossl_softc)
480 };
481 
482 DRIVER_MODULE(ossl, nexus, ossl_driver, NULL, NULL);
483 MODULE_VERSION(ossl, 1);
484 MODULE_DEPEND(ossl, crypto, 1, 1, 1);
485