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