1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621 |
- /* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */
- /*-
- * Copyright (c) 2001 Theo de Raadt
- * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
- * Copyright (c) 2014 The FreeBSD Foundation
- * All rights reserved.
- *
- * Portions of this software were developed by John-Mark Gurney
- * under sponsorship of the FreeBSD Foundation and
- * Rubicon Communications, LLC (Netgate).
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Effort sponsored in part by the Defense Advanced Research Projects
- * Agency (DARPA) and Air Force Research Laboratory, Air Force
- * Materiel Command, USAF, under agreement number F30602-01-2-0537.
- */
- #include <sys/cdefs.h>
- __FBSDID("$FreeBSD$");
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/malloc.h>
- #include <sys/mbuf.h>
- #include <sys/lock.h>
- #include <sys/mutex.h>
- #include <sys/proc.h>
- #include <sys/sysctl.h>
- #include <sys/errno.h>
- #include <sys/random.h>
- #include <sys/conf.h>
- #include <sys/kernel.h>
- #include <sys/module.h>
- #include <sys/fcntl.h>
- #include <sys/bus.h>
- #include <sys/sdt.h>
- #include <sys/syscallsubr.h>
- #include <opencrypto/cryptodev.h>
- #include <opencrypto/xform.h>
- SDT_PROVIDER_DECLARE(opencrypto);
- SDT_PROBE_DEFINE1(opencrypto, dev, ioctl, error, "int"/*line number*/);
- #ifdef COMPAT_FREEBSD12
- /*
- * Previously, most ioctls were performed against a cloned descriptor
- * of /dev/crypto obtained via CRIOGET. Now all ioctls are performed
- * against /dev/crypto directly.
- */
- #define CRIOGET _IOWR('c', 100, uint32_t)
- #endif
- /* the following are done against the cloned descriptor */
- #ifdef COMPAT_FREEBSD32
- #include <sys/mount.h>
- #include <compat/freebsd32/freebsd32.h>
- struct session_op32 {
- uint32_t cipher;
- uint32_t mac;
- uint32_t keylen;
- uint32_t key;
- int mackeylen;
- uint32_t mackey;
- uint32_t ses;
- };
- struct session2_op32 {
- uint32_t cipher;
- uint32_t mac;
- uint32_t keylen;
- uint32_t key;
- int mackeylen;
- uint32_t mackey;
- uint32_t ses;
- int crid;
- int pad[4];
- };
- struct crypt_op32 {
- uint32_t ses;
- uint16_t op;
- uint16_t flags;
- u_int len;
- uint32_t src, dst;
- uint32_t mac;
- uint32_t iv;
- };
- struct crypt_aead32 {
- uint32_t ses;
- uint16_t op;
- uint16_t flags;
- u_int len;
- u_int aadlen;
- u_int ivlen;
- uint32_t src;
- uint32_t dst;
- uint32_t aad;
- uint32_t tag;
- uint32_t iv;
- };
- struct crparam32 {
- uint32_t crp_p;
- u_int crp_nbits;
- };
- struct crypt_kop32 {
- u_int crk_op;
- u_int crk_status;
- u_short crk_iparams;
- u_short crk_oparams;
- u_int crk_crid;
- struct crparam32 crk_param[CRK_MAXPARAM];
- };
- #define CIOCGSESSION32 _IOWR('c', 101, struct session_op32)
- #define CIOCCRYPT32 _IOWR('c', 103, struct crypt_op32)
- #define CIOCKEY32 _IOWR('c', 104, struct crypt_kop32)
- #define CIOCGSESSION232 _IOWR('c', 106, struct session2_op32)
- #define CIOCKEY232 _IOWR('c', 107, struct crypt_kop32)
- #define CIOCCRYPTAEAD32 _IOWR('c', 109, struct crypt_aead32)
- static void
- session_op_from_32(const struct session_op32 *from, struct session2_op *to)
- {
- memset(to, 0, sizeof(*to));
- CP(*from, *to, cipher);
- CP(*from, *to, mac);
- CP(*from, *to, keylen);
- PTRIN_CP(*from, *to, key);
- CP(*from, *to, mackeylen);
- PTRIN_CP(*from, *to, mackey);
- CP(*from, *to, ses);
- to->crid = CRYPTOCAP_F_HARDWARE;
- }
- static void
- session2_op_from_32(const struct session2_op32 *from, struct session2_op *to)
- {
- session_op_from_32((const struct session_op32 *)from, to);
- CP(*from, *to, crid);
- }
- static void
- session_op_to_32(const struct session2_op *from, struct session_op32 *to)
- {
- CP(*from, *to, cipher);
- CP(*from, *to, mac);
- CP(*from, *to, keylen);
- PTROUT_CP(*from, *to, key);
- CP(*from, *to, mackeylen);
- PTROUT_CP(*from, *to, mackey);
- CP(*from, *to, ses);
- }
- static void
- session2_op_to_32(const struct session2_op *from, struct session2_op32 *to)
- {
- session_op_to_32(from, (struct session_op32 *)to);
- CP(*from, *to, crid);
- }
- static void
- crypt_op_from_32(const struct crypt_op32 *from, struct crypt_op *to)
- {
- CP(*from, *to, ses);
- CP(*from, *to, op);
- CP(*from, *to, flags);
- CP(*from, *to, len);
- PTRIN_CP(*from, *to, src);
- PTRIN_CP(*from, *to, dst);
- PTRIN_CP(*from, *to, mac);
- PTRIN_CP(*from, *to, iv);
- }
- static void
- crypt_op_to_32(const struct crypt_op *from, struct crypt_op32 *to)
- {
- CP(*from, *to, ses);
- CP(*from, *to, op);
- CP(*from, *to, flags);
- CP(*from, *to, len);
- PTROUT_CP(*from, *to, src);
- PTROUT_CP(*from, *to, dst);
- PTROUT_CP(*from, *to, mac);
- PTROUT_CP(*from, *to, iv);
- }
- static void
- crypt_aead_from_32(const struct crypt_aead32 *from, struct crypt_aead *to)
- {
- CP(*from, *to, ses);
- CP(*from, *to, op);
- CP(*from, *to, flags);
- CP(*from, *to, len);
- CP(*from, *to, aadlen);
- CP(*from, *to, ivlen);
- PTRIN_CP(*from, *to, src);
- PTRIN_CP(*from, *to, dst);
- PTRIN_CP(*from, *to, aad);
- PTRIN_CP(*from, *to, tag);
- PTRIN_CP(*from, *to, iv);
- }
- static void
- crypt_aead_to_32(const struct crypt_aead *from, struct crypt_aead32 *to)
- {
- CP(*from, *to, ses);
- CP(*from, *to, op);
- CP(*from, *to, flags);
- CP(*from, *to, len);
- CP(*from, *to, aadlen);
- CP(*from, *to, ivlen);
- PTROUT_CP(*from, *to, src);
- PTROUT_CP(*from, *to, dst);
- PTROUT_CP(*from, *to, aad);
- PTROUT_CP(*from, *to, tag);
- PTROUT_CP(*from, *to, iv);
- }
- static void
- crparam_from_32(const struct crparam32 *from, struct crparam *to)
- {
- PTRIN_CP(*from, *to, crp_p);
- CP(*from, *to, crp_nbits);
- }
- static void
- crparam_to_32(const struct crparam *from, struct crparam32 *to)
- {
- PTROUT_CP(*from, *to, crp_p);
- CP(*from, *to, crp_nbits);
- }
- static void
- crypt_kop_from_32(const struct crypt_kop32 *from, struct crypt_kop *to)
- {
- int i;
- CP(*from, *to, crk_op);
- CP(*from, *to, crk_status);
- CP(*from, *to, crk_iparams);
- CP(*from, *to, crk_oparams);
- CP(*from, *to, crk_crid);
- for (i = 0; i < CRK_MAXPARAM; i++)
- crparam_from_32(&from->crk_param[i], &to->crk_param[i]);
- }
- static void
- crypt_kop_to_32(const struct crypt_kop *from, struct crypt_kop32 *to)
- {
- int i;
- CP(*from, *to, crk_op);
- CP(*from, *to, crk_status);
- CP(*from, *to, crk_iparams);
- CP(*from, *to, crk_oparams);
- CP(*from, *to, crk_crid);
- for (i = 0; i < CRK_MAXPARAM; i++)
- crparam_to_32(&from->crk_param[i], &to->crk_param[i]);
- }
- #endif
- static void
- session2_op_from_op(const struct session_op *from, struct session2_op *to)
- {
- memset(to, 0, sizeof(*to));
- memcpy(to, from, sizeof(*from));
- to->crid = CRYPTOCAP_F_HARDWARE;
- }
- static void
- session2_op_to_op(const struct session2_op *from, struct session_op *to)
- {
- memcpy(to, from, sizeof(*to));
- }
- struct csession {
- TAILQ_ENTRY(csession) next;
- crypto_session_t cses;
- volatile u_int refs;
- uint32_t ses;
- struct mtx lock; /* for op submission */
- struct enc_xform *txform;
- int hashsize;
- int ivsize;
- int mode;
- void *key;
- void *mackey;
- };
- struct cryptop_data {
- struct csession *cse;
- char *buf;
- char *obuf;
- char *aad;
- bool done;
- };
- struct fcrypt {
- TAILQ_HEAD(csessionlist, csession) csessions;
- int sesn;
- struct mtx lock;
- };
- static bool use_outputbuffers;
- SYSCTL_BOOL(_kern_crypto, OID_AUTO, cryptodev_use_output, CTLFLAG_RW,
- &use_outputbuffers, 0,
- "Use separate output buffers for /dev/crypto requests.");
- static bool use_separate_aad;
- SYSCTL_BOOL(_kern_crypto, OID_AUTO, cryptodev_separate_aad, CTLFLAG_RW,
- &use_separate_aad, 0,
- "Use separate AAD buffer for /dev/crypto requests.");
- static struct timeval warninterval = { .tv_sec = 60, .tv_usec = 0 };
- SYSCTL_TIMEVAL_SEC(_kern, OID_AUTO, cryptodev_warn_interval, CTLFLAG_RW,
- &warninterval,
- "Delay in seconds between warnings of deprecated /dev/crypto algorithms");
- /*
- * Check a crypto identifier to see if it requested
- * a software device/driver. This can be done either
- * by device name/class or through search constraints.
- */
- static int
- checkforsoftware(int *cridp)
- {
- int crid;
- crid = *cridp;
- if (!crypto_devallowsoft) {
- if (crid & CRYPTOCAP_F_SOFTWARE) {
- if (crid & CRYPTOCAP_F_HARDWARE) {
- *cridp = CRYPTOCAP_F_HARDWARE;
- return 0;
- }
- return EINVAL;
- }
- if ((crid & CRYPTOCAP_F_HARDWARE) == 0 &&
- (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0)
- return EINVAL;
- }
- return 0;
- }
- static int
- cse_create(struct fcrypt *fcr, struct session2_op *sop)
- {
- struct crypto_session_params csp;
- struct csession *cse;
- struct enc_xform *txform;
- struct auth_hash *thash;
- void *key = NULL;
- void *mackey = NULL;
- crypto_session_t cses;
- int crid, error;
- switch (sop->cipher) {
- case 0:
- txform = NULL;
- break;
- case CRYPTO_AES_CBC:
- txform = &enc_xform_rijndael128;
- break;
- case CRYPTO_AES_XTS:
- txform = &enc_xform_aes_xts;
- break;
- case CRYPTO_NULL_CBC:
- txform = &enc_xform_null;
- break;
- case CRYPTO_CAMELLIA_CBC:
- txform = &enc_xform_camellia;
- break;
- case CRYPTO_AES_ICM:
- txform = &enc_xform_aes_icm;
- break;
- case CRYPTO_AES_NIST_GCM_16:
- txform = &enc_xform_aes_nist_gcm;
- break;
- case CRYPTO_CHACHA20:
- txform = &enc_xform_chacha20;
- break;
- case CRYPTO_AES_CCM_16:
- txform = &enc_xform_ccm;
- break;
- default:
- CRYPTDEB("invalid cipher");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- switch (sop->mac) {
- case 0:
- thash = NULL;
- break;
- case CRYPTO_POLY1305:
- thash = &auth_hash_poly1305;
- break;
- case CRYPTO_SHA1_HMAC:
- thash = &auth_hash_hmac_sha1;
- break;
- case CRYPTO_SHA2_224_HMAC:
- thash = &auth_hash_hmac_sha2_224;
- break;
- case CRYPTO_SHA2_256_HMAC:
- thash = &auth_hash_hmac_sha2_256;
- break;
- case CRYPTO_SHA2_384_HMAC:
- thash = &auth_hash_hmac_sha2_384;
- break;
- case CRYPTO_SHA2_512_HMAC:
- thash = &auth_hash_hmac_sha2_512;
- break;
- case CRYPTO_RIPEMD160_HMAC:
- thash = &auth_hash_hmac_ripemd_160;
- break;
- #ifdef COMPAT_FREEBSD12
- case CRYPTO_AES_128_NIST_GMAC:
- case CRYPTO_AES_192_NIST_GMAC:
- case CRYPTO_AES_256_NIST_GMAC:
- /* Should always be paired with GCM. */
- if (sop->cipher != CRYPTO_AES_NIST_GCM_16) {
- CRYPTDEB("GMAC without GCM");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- break;
- #endif
- case CRYPTO_AES_NIST_GMAC:
- switch (sop->mackeylen * 8) {
- case 128:
- thash = &auth_hash_nist_gmac_aes_128;
- break;
- case 192:
- thash = &auth_hash_nist_gmac_aes_192;
- break;
- case 256:
- thash = &auth_hash_nist_gmac_aes_256;
- break;
- default:
- CRYPTDEB("invalid GMAC key length");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- break;
- case CRYPTO_AES_CCM_CBC_MAC:
- switch (sop->mackeylen) {
- case 16:
- thash = &auth_hash_ccm_cbc_mac_128;
- break;
- case 24:
- thash = &auth_hash_ccm_cbc_mac_192;
- break;
- case 32:
- thash = &auth_hash_ccm_cbc_mac_256;
- break;
- default:
- CRYPTDEB("Invalid CBC MAC key size %d", sop->keylen);
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- break;
- case CRYPTO_SHA1:
- thash = &auth_hash_sha1;
- break;
- case CRYPTO_SHA2_224:
- thash = &auth_hash_sha2_224;
- break;
- case CRYPTO_SHA2_256:
- thash = &auth_hash_sha2_256;
- break;
- case CRYPTO_SHA2_384:
- thash = &auth_hash_sha2_384;
- break;
- case CRYPTO_SHA2_512:
- thash = &auth_hash_sha2_512;
- break;
- case CRYPTO_NULL_HMAC:
- thash = &auth_hash_null;
- break;
- case CRYPTO_BLAKE2B:
- thash = &auth_hash_blake2b;
- break;
- case CRYPTO_BLAKE2S:
- thash = &auth_hash_blake2s;
- break;
- default:
- CRYPTDEB("invalid mac");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- if (txform == NULL && thash == NULL) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- memset(&csp, 0, sizeof(csp));
- if (use_outputbuffers)
- csp.csp_flags |= CSP_F_SEPARATE_OUTPUT;
- if (sop->cipher == CRYPTO_AES_NIST_GCM_16) {
- switch (sop->mac) {
- #ifdef COMPAT_FREEBSD12
- case CRYPTO_AES_128_NIST_GMAC:
- case CRYPTO_AES_192_NIST_GMAC:
- case CRYPTO_AES_256_NIST_GMAC:
- if (sop->keylen != sop->mackeylen) {
- SDT_PROBE1(opencrypto, dev, ioctl, error,
- __LINE__);
- return (EINVAL);
- }
- break;
- #endif
- case 0:
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- csp.csp_mode = CSP_MODE_AEAD;
- } else if (sop->cipher == CRYPTO_AES_CCM_16) {
- switch (sop->mac) {
- #ifdef COMPAT_FREEBSD12
- case CRYPTO_AES_CCM_CBC_MAC:
- if (sop->keylen != sop->mackeylen) {
- SDT_PROBE1(opencrypto, dev, ioctl, error,
- __LINE__);
- return (EINVAL);
- }
- thash = NULL;
- break;
- #endif
- case 0:
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- csp.csp_mode = CSP_MODE_AEAD;
- } else if (txform != NULL && thash != NULL)
- csp.csp_mode = CSP_MODE_ETA;
- else if (txform != NULL)
- csp.csp_mode = CSP_MODE_CIPHER;
- else
- csp.csp_mode = CSP_MODE_DIGEST;
- switch (csp.csp_mode) {
- case CSP_MODE_AEAD:
- case CSP_MODE_ETA:
- if (use_separate_aad)
- csp.csp_flags |= CSP_F_SEPARATE_AAD;
- break;
- }
- if (txform != NULL) {
- csp.csp_cipher_alg = txform->type;
- csp.csp_cipher_klen = sop->keylen;
- if (sop->keylen > txform->maxkey ||
- sop->keylen < txform->minkey) {
- CRYPTDEB("invalid cipher parameters");
- error = EINVAL;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- key = malloc(csp.csp_cipher_klen, M_XDATA, M_WAITOK);
- error = copyin(sop->key, key, csp.csp_cipher_klen);
- if (error) {
- CRYPTDEB("invalid key");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- csp.csp_cipher_key = key;
- csp.csp_ivlen = txform->ivsize;
- }
- if (thash != NULL) {
- csp.csp_auth_alg = thash->type;
- csp.csp_auth_klen = sop->mackeylen;
- if (sop->mackeylen > thash->keysize || sop->mackeylen < 0) {
- CRYPTDEB("invalid mac key length");
- error = EINVAL;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- if (csp.csp_auth_klen != 0) {
- mackey = malloc(csp.csp_auth_klen, M_XDATA, M_WAITOK);
- error = copyin(sop->mackey, mackey, csp.csp_auth_klen);
- if (error) {
- CRYPTDEB("invalid mac key");
- SDT_PROBE1(opencrypto, dev, ioctl, error,
- __LINE__);
- goto bail;
- }
- csp.csp_auth_key = mackey;
- }
- if (csp.csp_auth_alg == CRYPTO_AES_NIST_GMAC)
- csp.csp_ivlen = AES_GCM_IV_LEN;
- if (csp.csp_auth_alg == CRYPTO_AES_CCM_CBC_MAC)
- csp.csp_ivlen = AES_CCM_IV_LEN;
- }
- crid = sop->crid;
- error = checkforsoftware(&crid);
- if (error) {
- CRYPTDEB("checkforsoftware");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- error = crypto_newsession(&cses, &csp, crid);
- if (error) {
- CRYPTDEB("crypto_newsession");
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- cse = malloc(sizeof(struct csession), M_XDATA, M_WAITOK | M_ZERO);
- mtx_init(&cse->lock, "cryptodev", "crypto session lock", MTX_DEF);
- refcount_init(&cse->refs, 1);
- cse->key = key;
- cse->mackey = mackey;
- cse->mode = csp.csp_mode;
- cse->cses = cses;
- cse->txform = txform;
- if (thash != NULL)
- cse->hashsize = thash->hashsize;
- else if (csp.csp_cipher_alg == CRYPTO_AES_NIST_GCM_16)
- cse->hashsize = AES_GMAC_HASH_LEN;
- else if (csp.csp_cipher_alg == CRYPTO_AES_CCM_16)
- cse->hashsize = AES_CBC_MAC_HASH_LEN;
- cse->ivsize = csp.csp_ivlen;
- mtx_lock(&fcr->lock);
- TAILQ_INSERT_TAIL(&fcr->csessions, cse, next);
- cse->ses = fcr->sesn++;
- mtx_unlock(&fcr->lock);
- sop->ses = cse->ses;
- /* return hardware/driver id */
- sop->crid = crypto_ses2hid(cse->cses);
- bail:
- if (error) {
- free(key, M_XDATA);
- free(mackey, M_XDATA);
- }
- return (error);
- }
- static struct csession *
- cse_find(struct fcrypt *fcr, u_int ses)
- {
- struct csession *cse;
- mtx_lock(&fcr->lock);
- TAILQ_FOREACH(cse, &fcr->csessions, next) {
- if (cse->ses == ses) {
- refcount_acquire(&cse->refs);
- mtx_unlock(&fcr->lock);
- return (cse);
- }
- }
- mtx_unlock(&fcr->lock);
- return (NULL);
- }
- static void
- cse_free(struct csession *cse)
- {
- if (!refcount_release(&cse->refs))
- return;
- crypto_freesession(cse->cses);
- mtx_destroy(&cse->lock);
- if (cse->key)
- free(cse->key, M_XDATA);
- if (cse->mackey)
- free(cse->mackey, M_XDATA);
- free(cse, M_XDATA);
- }
- static bool
- cse_delete(struct fcrypt *fcr, u_int ses)
- {
- struct csession *cse;
- mtx_lock(&fcr->lock);
- TAILQ_FOREACH(cse, &fcr->csessions, next) {
- if (cse->ses == ses) {
- TAILQ_REMOVE(&fcr->csessions, cse, next);
- mtx_unlock(&fcr->lock);
- cse_free(cse);
- return (true);
- }
- }
- mtx_unlock(&fcr->lock);
- return (false);
- }
- static struct cryptop_data *
- cod_alloc(struct csession *cse, size_t aad_len, size_t len)
- {
- struct cryptop_data *cod;
- cod = malloc(sizeof(struct cryptop_data), M_XDATA, M_WAITOK | M_ZERO);
- cod->cse = cse;
- if (crypto_get_params(cse->cses)->csp_flags & CSP_F_SEPARATE_AAD) {
- if (aad_len != 0)
- cod->aad = malloc(aad_len, M_XDATA, M_WAITOK);
- cod->buf = malloc(len, M_XDATA, M_WAITOK);
- } else
- cod->buf = malloc(aad_len + len, M_XDATA, M_WAITOK);
- if (crypto_get_params(cse->cses)->csp_flags & CSP_F_SEPARATE_OUTPUT)
- cod->obuf = malloc(len, M_XDATA, M_WAITOK);
- return (cod);
- }
- static void
- cod_free(struct cryptop_data *cod)
- {
- free(cod->aad, M_XDATA);
- free(cod->obuf, M_XDATA);
- free(cod->buf, M_XDATA);
- free(cod, M_XDATA);
- }
- static int
- cryptodev_cb(struct cryptop *crp)
- {
- struct cryptop_data *cod = crp->crp_opaque;
- /*
- * Lock to ensure the wakeup() is not missed by the loops
- * waiting on cod->done in cryptodev_op() and
- * cryptodev_aead().
- */
- mtx_lock(&cod->cse->lock);
- cod->done = true;
- mtx_unlock(&cod->cse->lock);
- wakeup(cod);
- return (0);
- }
- static int
- cryptodev_op(struct csession *cse, const struct crypt_op *cop)
- {
- struct cryptop_data *cod = NULL;
- struct cryptop *crp = NULL;
- char *dst;
- int error;
- if (cop->len > 256*1024-4) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (E2BIG);
- }
- if (cse->txform) {
- if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- }
- if (cop->mac && cse->hashsize == 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- /*
- * The COP_F_CIPHER_FIRST flag predates explicit session
- * modes, but the only way it was used was for EtA so allow it
- * as long as it is consistent with EtA.
- */
- if (cop->flags & COP_F_CIPHER_FIRST) {
- if (cop->op != COP_ENCRYPT) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- }
- cod = cod_alloc(cse, 0, cop->len + cse->hashsize);
- dst = cop->dst;
- crp = crypto_getreq(cse->cses, M_WAITOK);
- error = copyin(cop->src, cod->buf, cop->len);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- crp->crp_payload_start = 0;
- crp->crp_payload_length = cop->len;
- if (cse->hashsize)
- crp->crp_digest_start = cop->len;
- switch (cse->mode) {
- case CSP_MODE_COMPRESS:
- switch (cop->op) {
- case COP_ENCRYPT:
- crp->crp_op = CRYPTO_OP_COMPRESS;
- break;
- case COP_DECRYPT:
- crp->crp_op = CRYPTO_OP_DECOMPRESS;
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- break;
- case CSP_MODE_CIPHER:
- switch (cop->op) {
- case COP_ENCRYPT:
- crp->crp_op = CRYPTO_OP_ENCRYPT;
- break;
- case COP_DECRYPT:
- crp->crp_op = CRYPTO_OP_DECRYPT;
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- break;
- case CSP_MODE_DIGEST:
- switch (cop->op) {
- case 0:
- case COP_ENCRYPT:
- case COP_DECRYPT:
- crp->crp_op = CRYPTO_OP_COMPUTE_DIGEST;
- if (cod->obuf != NULL)
- crp->crp_digest_start = 0;
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- break;
- case CSP_MODE_ETA:
- switch (cop->op) {
- case COP_ENCRYPT:
- crp->crp_op = CRYPTO_OP_ENCRYPT |
- CRYPTO_OP_COMPUTE_DIGEST;
- break;
- case COP_DECRYPT:
- crp->crp_op = CRYPTO_OP_DECRYPT |
- CRYPTO_OP_VERIFY_DIGEST;
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- crp->crp_flags = CRYPTO_F_CBIMM | (cop->flags & COP_F_BATCH);
- crypto_use_buf(crp, cod->buf, cop->len + cse->hashsize);
- if (cod->obuf)
- crypto_use_output_buf(crp, cod->obuf, cop->len + cse->hashsize);
- crp->crp_callback = cryptodev_cb;
- crp->crp_opaque = cod;
- if (cop->iv) {
- if (cse->ivsize == 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- error = copyin(cop->iv, crp->crp_iv, cse->ivsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- crp->crp_flags |= CRYPTO_F_IV_SEPARATE;
- } else if (cse->ivsize != 0) {
- crp->crp_iv_start = 0;
- crp->crp_payload_start += cse->ivsize;
- crp->crp_payload_length -= cse->ivsize;
- dst += cse->ivsize;
- }
- if (cop->mac != NULL && crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
- error = copyin(cop->mac, cod->buf + crp->crp_digest_start,
- cse->hashsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- again:
- /*
- * Let the dispatch run unlocked, then, interlock against the
- * callback before checking if the operation completed and going
- * to sleep. This insures drivers don't inherit our lock which
- * results in a lock order reversal between crypto_dispatch forced
- * entry and the crypto_done callback into us.
- */
- error = crypto_dispatch(crp);
- if (error != 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- mtx_lock(&cse->lock);
- while (!cod->done)
- mtx_sleep(cod, &cse->lock, PWAIT, "crydev", 0);
- mtx_unlock(&cse->lock);
- if (crp->crp_etype == EAGAIN) {
- crp->crp_etype = 0;
- crp->crp_flags &= ~CRYPTO_F_DONE;
- cod->done = false;
- goto again;
- }
- if (crp->crp_etype != 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = crp->crp_etype;
- goto bail;
- }
- if (cop->dst != NULL) {
- error = copyout(cod->obuf != NULL ? cod->obuf :
- cod->buf + crp->crp_payload_start, dst,
- crp->crp_payload_length);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- if (cop->mac != NULL && (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) == 0) {
- error = copyout((cod->obuf != NULL ? cod->obuf : cod->buf) +
- crp->crp_digest_start, cop->mac, cse->hashsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- bail:
- crypto_freereq(crp);
- cod_free(cod);
- return (error);
- }
- static int
- cryptodev_aead(struct csession *cse, struct crypt_aead *caead)
- {
- struct cryptop_data *cod = NULL;
- struct cryptop *crp = NULL;
- char *dst;
- int error;
- if (caead->len > 256*1024-4 || caead->aadlen > 256*1024-4) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (E2BIG);
- }
- if (cse->txform == NULL || cse->hashsize == 0 || caead->tag == NULL ||
- (caead->len % cse->txform->blocksize) != 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- /*
- * The COP_F_CIPHER_FIRST flag predates explicit session
- * modes, but the only way it was used was for EtA so allow it
- * as long as it is consistent with EtA.
- */
- if (caead->flags & COP_F_CIPHER_FIRST) {
- if (caead->op != COP_ENCRYPT) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- }
- cod = cod_alloc(cse, caead->aadlen, caead->len + cse->hashsize);
- dst = caead->dst;
- crp = crypto_getreq(cse->cses, M_WAITOK);
- if (cod->aad != NULL)
- error = copyin(caead->aad, cod->aad, caead->aadlen);
- else
- error = copyin(caead->aad, cod->buf, caead->aadlen);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- crp->crp_aad = cod->aad;
- crp->crp_aad_start = 0;
- crp->crp_aad_length = caead->aadlen;
- if (cod->aad != NULL)
- crp->crp_payload_start = 0;
- else
- crp->crp_payload_start = caead->aadlen;
- error = copyin(caead->src, cod->buf + crp->crp_payload_start,
- caead->len);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- crp->crp_payload_length = caead->len;
- if (caead->op == COP_ENCRYPT && cod->obuf != NULL)
- crp->crp_digest_start = crp->crp_payload_output_start +
- caead->len;
- else
- crp->crp_digest_start = crp->crp_payload_start + caead->len;
- switch (cse->mode) {
- case CSP_MODE_AEAD:
- case CSP_MODE_ETA:
- switch (caead->op) {
- case COP_ENCRYPT:
- crp->crp_op = CRYPTO_OP_ENCRYPT |
- CRYPTO_OP_COMPUTE_DIGEST;
- break;
- case COP_DECRYPT:
- crp->crp_op = CRYPTO_OP_DECRYPT |
- CRYPTO_OP_VERIFY_DIGEST;
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- break;
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- error = EINVAL;
- goto bail;
- }
- crp->crp_flags = CRYPTO_F_CBIMM | (caead->flags & COP_F_BATCH);
- crypto_use_buf(crp, cod->buf, crp->crp_payload_start + caead->len +
- cse->hashsize);
- if (cod->obuf != NULL)
- crypto_use_output_buf(crp, cod->obuf, caead->len +
- cse->hashsize);
- crp->crp_callback = cryptodev_cb;
- crp->crp_opaque = cod;
- if (caead->iv) {
- /*
- * Permit a 16-byte IV for AES-XTS, but only use the
- * first 8 bytes as a block number.
- */
- if (cse->mode == CSP_MODE_ETA &&
- caead->ivlen == AES_BLOCK_LEN &&
- cse->ivsize == AES_XTS_IV_LEN)
- caead->ivlen = AES_XTS_IV_LEN;
- if (caead->ivlen != cse->ivsize) {
- error = EINVAL;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- error = copyin(caead->iv, crp->crp_iv, cse->ivsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- crp->crp_flags |= CRYPTO_F_IV_SEPARATE;
- } else {
- crp->crp_iv_start = crp->crp_payload_start;
- crp->crp_payload_start += cse->ivsize;
- crp->crp_payload_length -= cse->ivsize;
- dst += cse->ivsize;
- }
- if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
- error = copyin(caead->tag, cod->buf + crp->crp_digest_start,
- cse->hashsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- again:
- /*
- * Let the dispatch run unlocked, then, interlock against the
- * callback before checking if the operation completed and going
- * to sleep. This insures drivers don't inherit our lock which
- * results in a lock order reversal between crypto_dispatch forced
- * entry and the crypto_done callback into us.
- */
- error = crypto_dispatch(crp);
- if (error != 0) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- mtx_lock(&cse->lock);
- while (!cod->done)
- mtx_sleep(cod, &cse->lock, PWAIT, "crydev", 0);
- mtx_unlock(&cse->lock);
- if (crp->crp_etype == EAGAIN) {
- crp->crp_etype = 0;
- crp->crp_flags &= ~CRYPTO_F_DONE;
- cod->done = false;
- goto again;
- }
- if (crp->crp_etype != 0) {
- error = crp->crp_etype;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- if (caead->dst != NULL) {
- error = copyout(cod->obuf != NULL ? cod->obuf :
- cod->buf + crp->crp_payload_start, dst,
- crp->crp_payload_length);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- if ((crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) == 0) {
- error = copyout((cod->obuf != NULL ? cod->obuf : cod->buf) +
- crp->crp_digest_start, caead->tag, cse->hashsize);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto bail;
- }
- }
- bail:
- crypto_freereq(crp);
- cod_free(cod);
- return (error);
- }
- static void
- cryptodevkey_cb(struct cryptkop *krp)
- {
- wakeup_one(krp);
- }
- static int
- cryptodev_key(struct crypt_kop *kop)
- {
- struct cryptkop *krp = NULL;
- int error = EINVAL;
- int in, out, size, i;
- if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EFBIG);
- }
- in = kop->crk_iparams;
- out = kop->crk_oparams;
- switch (kop->crk_op) {
- case CRK_MOD_EXP:
- if (in == 3 && out == 1)
- break;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- case CRK_MOD_EXP_CRT:
- if (in == 6 && out == 1)
- break;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- case CRK_DSA_SIGN:
- if (in == 5 && out == 2)
- break;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- case CRK_DSA_VERIFY:
- if (in == 7 && out == 0)
- break;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- case CRK_DH_COMPUTE_KEY:
- if (in == 3 && out == 1)
- break;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- default:
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- krp = malloc(sizeof(*krp), M_XDATA, M_WAITOK | M_ZERO);
- krp->krp_op = kop->crk_op;
- krp->krp_status = kop->crk_status;
- krp->krp_iparams = kop->crk_iparams;
- krp->krp_oparams = kop->crk_oparams;
- krp->krp_crid = kop->crk_crid;
- krp->krp_status = 0;
- krp->krp_callback = cryptodevkey_cb;
- for (i = 0; i < CRK_MAXPARAM; i++) {
- if (kop->crk_param[i].crp_nbits > 65536) {
- /* Limit is the same as in OpenBSD */
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
- krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
- }
- for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
- size = (krp->krp_param[i].crp_nbits + 7) / 8;
- if (size == 0)
- continue;
- krp->krp_param[i].crp_p = malloc(size, M_XDATA, M_WAITOK);
- if (i >= krp->krp_iparams)
- continue;
- error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
- }
- error = crypto_kdispatch(krp);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
- error = tsleep(krp, PSOCK, "crydev", 0);
- if (error) {
- /* XXX can this happen? if so, how do we recover? */
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
-
- kop->crk_crid = krp->krp_hid; /* device that did the work */
- if (krp->krp_status != 0) {
- error = krp->krp_status;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
- for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
- size = (krp->krp_param[i].crp_nbits + 7) / 8;
- if (size == 0)
- continue;
- error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size);
- if (error) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- goto fail;
- }
- }
- fail:
- if (krp) {
- kop->crk_status = krp->krp_status;
- for (i = 0; i < CRK_MAXPARAM; i++) {
- if (krp->krp_param[i].crp_p)
- free(krp->krp_param[i].crp_p, M_XDATA);
- }
- free(krp, M_XDATA);
- }
- return (error);
- }
- static int
- cryptodev_find(struct crypt_find_op *find)
- {
- device_t dev;
- size_t fnlen = sizeof find->name;
- if (find->crid != -1) {
- dev = crypto_find_device_byhid(find->crid);
- if (dev == NULL)
- return (ENOENT);
- strncpy(find->name, device_get_nameunit(dev), fnlen);
- find->name[fnlen - 1] = '\x0';
- } else {
- find->name[fnlen - 1] = '\x0';
- find->crid = crypto_find_driver(find->name);
- if (find->crid == -1)
- return (ENOENT);
- }
- return (0);
- }
- static void
- fcrypt_dtor(void *data)
- {
- struct fcrypt *fcr = data;
- struct csession *cse;
- while ((cse = TAILQ_FIRST(&fcr->csessions))) {
- TAILQ_REMOVE(&fcr->csessions, cse, next);
- KASSERT(refcount_load(&cse->refs) == 1,
- ("%s: crypto session %p with %d refs", __func__, cse,
- refcount_load(&cse->refs)));
- cse_free(cse);
- }
- mtx_destroy(&fcr->lock);
- free(fcr, M_XDATA);
- }
- static int
- crypto_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
- {
- struct fcrypt *fcr;
- int error;
- fcr = malloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK | M_ZERO);
- TAILQ_INIT(&fcr->csessions);
- mtx_init(&fcr->lock, "fcrypt", NULL, MTX_DEF);
- error = devfs_set_cdevpriv(fcr, fcrypt_dtor);
- if (error)
- fcrypt_dtor(fcr);
- return (error);
- }
- static int
- crypto_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag,
- struct thread *td)
- {
- static struct timeval keywarn, featwarn;
- struct fcrypt *fcr;
- struct csession *cse;
- struct session2_op *sop;
- struct crypt_op *cop;
- struct crypt_aead *caead;
- struct crypt_kop *kop;
- uint32_t ses;
- int error = 0;
- union {
- struct session2_op sopc;
- #ifdef COMPAT_FREEBSD32
- struct crypt_op copc;
- struct crypt_aead aeadc;
- struct crypt_kop kopc;
- #endif
- } thunk;
- #ifdef COMPAT_FREEBSD32
- u_long cmd32;
- void *data32;
- cmd32 = 0;
- data32 = NULL;
- switch (cmd) {
- case CIOCGSESSION32:
- cmd32 = cmd;
- data32 = data;
- cmd = CIOCGSESSION;
- data = (void *)&thunk.sopc;
- session_op_from_32((struct session_op32 *)data32, &thunk.sopc);
- break;
- case CIOCGSESSION232:
- cmd32 = cmd;
- data32 = data;
- cmd = CIOCGSESSION2;
- data = (void *)&thunk.sopc;
- session2_op_from_32((struct session2_op32 *)data32,
- &thunk.sopc);
- break;
- case CIOCCRYPT32:
- cmd32 = cmd;
- data32 = data;
- cmd = CIOCCRYPT;
- data = (void *)&thunk.copc;
- crypt_op_from_32((struct crypt_op32 *)data32, &thunk.copc);
- break;
- case CIOCCRYPTAEAD32:
- cmd32 = cmd;
- data32 = data;
- cmd = CIOCCRYPTAEAD;
- data = (void *)&thunk.aeadc;
- crypt_aead_from_32((struct crypt_aead32 *)data32, &thunk.aeadc);
- break;
- case CIOCKEY32:
- case CIOCKEY232:
- cmd32 = cmd;
- data32 = data;
- if (cmd == CIOCKEY32)
- cmd = CIOCKEY;
- else
- cmd = CIOCKEY2;
- data = (void *)&thunk.kopc;
- crypt_kop_from_32((struct crypt_kop32 *)data32, &thunk.kopc);
- break;
- }
- #endif
- devfs_get_cdevpriv((void **)&fcr);
- switch (cmd) {
- #ifdef COMPAT_FREEBSD12
- case CRIOGET:
- /*
- * NB: This may fail in cases that the old
- * implementation did not if the current process has
- * restricted filesystem access (e.g. running in a
- * jail that does not expose /dev/crypto or in
- * capability mode).
- */
- error = kern_openat(td, AT_FDCWD, "/dev/crypto", UIO_SYSSPACE,
- O_RDWR, 0);
- if (error == 0)
- *(uint32_t *)data = td->td_retval[0];
- break;
- #endif
- case CIOCGSESSION:
- case CIOCGSESSION2:
- if (cmd == CIOCGSESSION) {
- session2_op_from_op((void *)data, &thunk.sopc);
- sop = &thunk.sopc;
- } else
- sop = (struct session2_op *)data;
- error = cse_create(fcr, sop);
- if (cmd == CIOCGSESSION && error == 0)
- session2_op_to_op(sop, (void *)data);
- break;
- case CIOCFSESSION:
- ses = *(uint32_t *)data;
- if (!cse_delete(fcr, ses)) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- break;
- case CIOCCRYPT:
- cop = (struct crypt_op *)data;
- cse = cse_find(fcr, cop->ses);
- if (cse == NULL) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- error = cryptodev_op(cse, cop);
- cse_free(cse);
- break;
- case CIOCKEY:
- case CIOCKEY2:
- if (ratecheck(&keywarn, &warninterval))
- gone_in(14,
- "Asymmetric crypto operations via /dev/crypto");
- if (!crypto_userasymcrypto) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EPERM); /* XXX compat? */
- }
- kop = (struct crypt_kop *)data;
- if (cmd == CIOCKEY) {
- /* NB: crypto core enforces s/w driver use */
- kop->crk_crid =
- CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
- }
- mtx_lock(&Giant);
- error = cryptodev_key(kop);
- mtx_unlock(&Giant);
- break;
- case CIOCASYMFEAT:
- if (ratecheck(&featwarn, &warninterval))
- gone_in(14,
- "Asymmetric crypto features via /dev/crypto");
- if (!crypto_userasymcrypto) {
- /*
- * NB: if user asym crypto operations are
- * not permitted return "no algorithms"
- * so well-behaved applications will just
- * fallback to doing them in software.
- */
- *(int *)data = 0;
- } else {
- error = crypto_getfeat((int *)data);
- if (error)
- SDT_PROBE1(opencrypto, dev, ioctl, error,
- __LINE__);
- }
- break;
- case CIOCFINDDEV:
- error = cryptodev_find((struct crypt_find_op *)data);
- break;
- case CIOCCRYPTAEAD:
- caead = (struct crypt_aead *)data;
- cse = cse_find(fcr, caead->ses);
- if (cse == NULL) {
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- return (EINVAL);
- }
- error = cryptodev_aead(cse, caead);
- cse_free(cse);
- break;
- default:
- error = EINVAL;
- SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__);
- break;
- }
- #ifdef COMPAT_FREEBSD32
- switch (cmd32) {
- case CIOCGSESSION32:
- if (error == 0)
- session_op_to_32((void *)data, data32);
- break;
- case CIOCGSESSION232:
- if (error == 0)
- session2_op_to_32((void *)data, data32);
- break;
- case CIOCCRYPT32:
- if (error == 0)
- crypt_op_to_32((void *)data, data32);
- break;
- case CIOCCRYPTAEAD32:
- if (error == 0)
- crypt_aead_to_32((void *)data, data32);
- break;
- case CIOCKEY32:
- case CIOCKEY232:
- crypt_kop_to_32((void *)data, data32);
- break;
- }
- #endif
- return (error);
- }
- static struct cdevsw crypto_cdevsw = {
- .d_version = D_VERSION,
- .d_open = crypto_open,
- .d_ioctl = crypto_ioctl,
- .d_name = "crypto",
- };
- static struct cdev *crypto_dev;
- /*
- * Initialization code, both for static and dynamic loading.
- */
- static int
- cryptodev_modevent(module_t mod, int type, void *unused)
- {
- switch (type) {
- case MOD_LOAD:
- if (bootverbose)
- printf("crypto: <crypto device>\n");
- crypto_dev = make_dev(&crypto_cdevsw, 0,
- UID_ROOT, GID_WHEEL, 0666,
- "crypto");
- return 0;
- case MOD_UNLOAD:
- /*XXX disallow if active sessions */
- destroy_dev(crypto_dev);
- return 0;
- }
- return EINVAL;
- }
- static moduledata_t cryptodev_mod = {
- "cryptodev",
- cryptodev_modevent,
- 0
- };
- MODULE_VERSION(cryptodev, 1);
- DECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
- MODULE_DEPEND(cryptodev, crypto, 1, 1, 1);
- MODULE_DEPEND(cryptodev, zlib, 1, 1, 1);
|