xref: /freebsd/sys/crypto/openssl/ossl.c (revision 6be3386466ab79a84b48429ae66244f21526d3df)
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 
53 #include "cryptodev_if.h"
54 
55 struct ossl_softc {
56 	int32_t sc_cid;
57 };
58 
59 struct ossl_session_hash {
60 	struct ossl_hash_context ictx;
61 	struct ossl_hash_context octx;
62 	struct auth_hash *axf;
63 	u_int mlen;
64 };
65 
66 struct ossl_session {
67 	struct ossl_session_hash hash;
68 };
69 
70 static MALLOC_DEFINE(M_OSSL, "ossl", "OpenSSL crypto");
71 
72 static void
73 ossl_identify(driver_t *driver, device_t parent)
74 {
75 
76 	if (device_find_child(parent, "ossl", -1) == NULL)
77 		BUS_ADD_CHILD(parent, 10, "ossl", -1);
78 }
79 
80 static int
81 ossl_probe(device_t dev)
82 {
83 
84 	device_set_desc(dev, "OpenSSL crypto");
85 	return (BUS_PROBE_DEFAULT);
86 }
87 
88 static int
89 ossl_attach(device_t dev)
90 {
91 	struct ossl_softc *sc;
92 
93 	sc = device_get_softc(dev);
94 
95 	ossl_cpuid();
96 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct ossl_session),
97 	    CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC |
98 	    CRYPTOCAP_F_ACCEL_SOFTWARE);
99 	if (sc->sc_cid < 0) {
100 		device_printf(dev, "failed to allocate crypto driver id\n");
101 		return (ENXIO);
102 	}
103 
104 	return (0);
105 }
106 
107 static int
108 ossl_detach(device_t dev)
109 {
110 	struct ossl_softc *sc;
111 
112 	sc = device_get_softc(dev);
113 
114 	crypto_unregister_all(sc->sc_cid);
115 
116 	return (0);
117 }
118 
119 static struct auth_hash *
120 ossl_lookup_hash(const struct crypto_session_params *csp)
121 {
122 
123 	switch (csp->csp_auth_alg) {
124 	case CRYPTO_SHA1:
125 	case CRYPTO_SHA1_HMAC:
126 		return (&ossl_hash_sha1);
127 	case CRYPTO_SHA2_224:
128 	case CRYPTO_SHA2_224_HMAC:
129 		return (&ossl_hash_sha224);
130 	case CRYPTO_SHA2_256:
131 	case CRYPTO_SHA2_256_HMAC:
132 		return (&ossl_hash_sha256);
133 	case CRYPTO_SHA2_384:
134 	case CRYPTO_SHA2_384_HMAC:
135 		return (&ossl_hash_sha384);
136 	case CRYPTO_SHA2_512:
137 	case CRYPTO_SHA2_512_HMAC:
138 		return (&ossl_hash_sha512);
139 	case CRYPTO_POLY1305:
140 		return (&ossl_hash_poly1305);
141 	default:
142 		return (NULL);
143 	}
144 }
145 
146 static int
147 ossl_probesession(device_t dev, const struct crypto_session_params *csp)
148 {
149 
150 	if ((csp->csp_flags & ~(CSP_F_SEPARATE_OUTPUT | CSP_F_SEPARATE_AAD)) !=
151 	    0)
152 		return (EINVAL);
153 	switch (csp->csp_mode) {
154 	case CSP_MODE_DIGEST:
155 		if (ossl_lookup_hash(csp) == NULL)
156 			return (EINVAL);
157 		break;
158 	case CSP_MODE_CIPHER:
159 		switch (csp->csp_cipher_alg) {
160 		case CRYPTO_CHACHA20:
161 			if (csp->csp_cipher_klen != CHACHA_KEY_SIZE)
162 				return (EINVAL);
163 			break;
164 		default:
165 			return (EINVAL);
166 		}
167 		break;
168 	case CSP_MODE_AEAD:
169 		switch (csp->csp_cipher_alg) {
170 		case CRYPTO_CHACHA20_POLY1305:
171 			break;
172 		default:
173 			return (EINVAL);
174 		}
175 		break;
176 	default:
177 		return (EINVAL);
178 	}
179 
180 	return (CRYPTODEV_PROBE_ACCEL_SOFTWARE);
181 }
182 
183 static void
184 ossl_newsession_hash(struct ossl_session *s,
185     const struct crypto_session_params *csp)
186 {
187 	struct auth_hash *axf;
188 
189 	axf = ossl_lookup_hash(csp);
190 	s->hash.axf = axf;
191 	if (csp->csp_auth_mlen == 0)
192 		s->hash.mlen = axf->hashsize;
193 	else
194 		s->hash.mlen = csp->csp_auth_mlen;
195 
196 	if (csp->csp_auth_klen == 0) {
197 		axf->Init(&s->hash.ictx);
198 	} else {
199 		if (csp->csp_auth_key != NULL) {
200 			fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
201 			if (axf->Setkey != NULL) {
202 				axf->Init(&s->hash.ictx);
203 				axf->Setkey(&s->hash.ictx, csp->csp_auth_key,
204 				    csp->csp_auth_klen);
205 			} else {
206 				hmac_init_ipad(axf, csp->csp_auth_key,
207 				    csp->csp_auth_klen, &s->hash.ictx);
208 				hmac_init_opad(axf, csp->csp_auth_key,
209 				    csp->csp_auth_klen, &s->hash.octx);
210 			}
211 			fpu_kern_leave(curthread, NULL);
212 		}
213 	}
214 }
215 
216 static int
217 ossl_newsession(device_t dev, crypto_session_t cses,
218     const struct crypto_session_params *csp)
219 {
220 	struct ossl_session *s;
221 
222 	s = crypto_get_driver_session(cses);
223 	switch (csp->csp_mode) {
224 	case CSP_MODE_DIGEST:
225 		ossl_newsession_hash(s, csp);
226 		break;
227 	}
228 
229 	return (0);
230 }
231 
232 static int
233 ossl_process_hash(struct ossl_session *s, struct cryptop *crp,
234     const struct crypto_session_params *csp)
235 {
236 	struct ossl_hash_context ctx;
237 	char digest[HASH_MAX_LEN];
238 	struct auth_hash *axf;
239 	int error;
240 
241 	axf = s->hash.axf;
242 
243 	if (crp->crp_auth_key == NULL) {
244 		ctx = s->hash.ictx;
245 	} else {
246 		if (axf->Setkey != NULL) {
247 			axf->Init(&ctx);
248 			axf->Setkey(&ctx, crp->crp_auth_key,
249 			    csp->csp_auth_klen);
250 		} else {
251 			hmac_init_ipad(axf, crp->crp_auth_key,
252 			    csp->csp_auth_klen, &ctx);
253 		}
254 	}
255 
256 	if (crp->crp_aad != NULL)
257 		error = axf->Update(&ctx, crp->crp_aad, crp->crp_aad_length);
258 	else
259 		error = crypto_apply(crp, crp->crp_aad_start,
260 		    crp->crp_aad_length, axf->Update, &ctx);
261 	if (error)
262 		goto out;
263 
264 	error = crypto_apply(crp, crp->crp_payload_start,
265 	    crp->crp_payload_length, axf->Update, &ctx);
266 	if (error)
267 		goto out;
268 
269 	axf->Final(digest, &ctx);
270 
271 	if (csp->csp_auth_klen != 0 && axf->Setkey == NULL) {
272 		if (crp->crp_auth_key == NULL)
273 			ctx = s->hash.octx;
274 		else
275 			hmac_init_opad(axf, crp->crp_auth_key,
276 			    csp->csp_auth_klen, &ctx);
277 		axf->Update(&ctx, digest, axf->hashsize);
278 		axf->Final(digest, &ctx);
279 	}
280 
281 	if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
282 		char digest2[HASH_MAX_LEN];
283 
284 		crypto_copydata(crp, crp->crp_digest_start, s->hash.mlen,
285 		    digest2);
286 		if (timingsafe_bcmp(digest, digest2, s->hash.mlen) != 0)
287 			error = EBADMSG;
288 		explicit_bzero(digest2, sizeof(digest2));
289 	} else {
290 		crypto_copyback(crp, crp->crp_digest_start, s->hash.mlen,
291 		    digest);
292 	}
293 	explicit_bzero(digest, sizeof(digest));
294 
295 out:
296 	explicit_bzero(&ctx, sizeof(ctx));
297 	return (error);
298 }
299 
300 static int
301 ossl_process(device_t dev, struct cryptop *crp, int hint)
302 {
303 	const struct crypto_session_params *csp;
304 	struct ossl_session *s;
305 	int error;
306 	bool fpu_entered;
307 
308 	s = crypto_get_driver_session(crp->crp_session);
309 	csp = crypto_get_params(crp->crp_session);
310 
311 	if (is_fpu_kern_thread(0)) {
312 		fpu_entered = false;
313 	} else {
314 		fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
315 		fpu_entered = true;
316 	}
317 
318 	switch (csp->csp_mode) {
319 	case CSP_MODE_DIGEST:
320 		error = ossl_process_hash(s, crp, csp);
321 		break;
322 	case CSP_MODE_CIPHER:
323 		error = ossl_chacha20(crp, csp);
324 		break;
325 	case CSP_MODE_AEAD:
326 		if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
327 			error = ossl_chacha20_poly1305_encrypt(crp, csp);
328 		else
329 			error = ossl_chacha20_poly1305_decrypt(crp, csp);
330 		break;
331 	default:
332 		__assert_unreachable();
333 	}
334 
335 	if (fpu_entered)
336 		fpu_kern_leave(curthread, NULL);
337 
338 	crp->crp_etype = error;
339 	crypto_done(crp);
340 
341 	return (0);
342 }
343 
344 static device_method_t ossl_methods[] = {
345 	DEVMETHOD(device_identify,	ossl_identify),
346 	DEVMETHOD(device_probe,		ossl_probe),
347 	DEVMETHOD(device_attach,	ossl_attach),
348 	DEVMETHOD(device_detach,	ossl_detach),
349 
350 	DEVMETHOD(cryptodev_probesession, ossl_probesession),
351 	DEVMETHOD(cryptodev_newsession,	ossl_newsession),
352 	DEVMETHOD(cryptodev_process,	ossl_process),
353 
354 	DEVMETHOD_END
355 };
356 
357 static driver_t ossl_driver = {
358 	"ossl",
359 	ossl_methods,
360 	sizeof(struct ossl_softc)
361 };
362 
363 static devclass_t ossl_devclass;
364 
365 DRIVER_MODULE(ossl, nexus, ossl_driver, ossl_devclass, NULL, NULL);
366 MODULE_VERSION(ossl, 1);
367 MODULE_DEPEND(ossl, crypto, 1, 1, 1);
368