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