The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/cavium/cryptocteon/cryptocteon.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Octeon Crypto for OCF
    3  *
    4  * Written by David McCullough <david_mccullough@securecomputing.com>
    5  * Copyright (C) 2009 David McCullough
    6  *
    7  * LICENSE TERMS
    8  *
    9  * The free distribution and use of this software in both source and binary
   10  * form is allowed (with or without changes) provided that:
   11  *
   12  *   1. distributions of this source code include the above copyright
   13  *      notice, this list of conditions and the following disclaimer;
   14  *
   15  *   2. distributions in binary form include the above copyright
   16  *      notice, this list of conditions and the following disclaimer
   17  *      in the documentation and/or other associated materials;
   18  *
   19  *   3. the copyright holder's name is not used to endorse products
   20  *      built using this software without specific written permission.
   21  *
   22  * DISCLAIMER
   23  *
   24  * This software is provided 'as is' with no explicit or implied warranties
   25  * in respect of its properties, including, but not limited to, correctness
   26  * and/or fitness for purpose.
   27  * ---------------------------------------------------------------------------
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/uio.h>
   41 
   42 #include <opencrypto/cryptodev.h>
   43 
   44 #include <contrib/octeon-sdk/cvmx.h>
   45 
   46 #include <mips/cavium/cryptocteon/cryptocteonvar.h>
   47 
   48 #include "cryptodev_if.h"
   49 
   50 struct cryptocteon_softc {
   51         int32_t                 sc_cid;         /* opencrypto id */
   52 };
   53 
   54 int cryptocteon_debug = 0;
   55 TUNABLE_INT("hw.cryptocteon.debug", &cryptocteon_debug);
   56 
   57 static void cryptocteon_identify(driver_t *, device_t);
   58 static int cryptocteon_probe(device_t);
   59 static int cryptocteon_attach(device_t);
   60 
   61 static int cryptocteon_process(device_t, struct cryptop *, int);
   62 static int cryptocteon_newsession(device_t, crypto_session_t, struct cryptoini *);
   63 
   64 static void
   65 cryptocteon_identify(driver_t *drv, device_t parent)
   66 {
   67         if (octeon_has_feature(OCTEON_FEATURE_CRYPTO))
   68                 BUS_ADD_CHILD(parent, 0, "cryptocteon", 0);
   69 }
   70 
   71 static int
   72 cryptocteon_probe(device_t dev)
   73 {
   74         device_set_desc(dev, "Octeon Secure Coprocessor");
   75         return (0);
   76 }
   77 
   78 static int
   79 cryptocteon_attach(device_t dev)
   80 {
   81         struct cryptocteon_softc *sc;
   82 
   83         sc = device_get_softc(dev);
   84 
   85         sc->sc_cid = crypto_get_driverid(dev, sizeof(struct octo_sess),
   86             CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC);
   87         if (sc->sc_cid < 0) {
   88                 device_printf(dev, "crypto_get_driverid ret %d\n", sc->sc_cid);
   89                 return (ENXIO);
   90         }
   91 
   92         crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
   93         crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
   94         crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
   95         crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
   96         crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
   97 
   98         return (0);
   99 }
  100 
  101 /*
  102  * Generate a new octo session.  We artifically limit it to a single
  103  * hash/cipher or hash-cipher combo just to make it easier, most callers
  104  * do not expect more than this anyway.
  105  */
  106 static int
  107 cryptocteon_newsession(device_t dev, crypto_session_t cses,
  108     struct cryptoini *cri)
  109 {
  110         struct cryptoini *c, *encini = NULL, *macini = NULL;
  111         struct cryptocteon_softc *sc;
  112         struct octo_sess *ocd;
  113         int i;
  114 
  115         sc = device_get_softc(dev);
  116 
  117         if (cri == NULL || sc == NULL)
  118                 return (EINVAL);
  119 
  120         /*
  121          * To keep it simple, we only handle hash, cipher or hash/cipher in a
  122          * session,  you cannot currently do multiple ciphers/hashes in one
  123          * session even though it would be possibel to code this driver to
  124          * handle it.
  125          */
  126         for (i = 0, c = cri; c && i < 2; i++) {
  127                 if (c->cri_alg == CRYPTO_MD5_HMAC ||
  128                     c->cri_alg == CRYPTO_SHA1_HMAC ||
  129                     c->cri_alg == CRYPTO_NULL_HMAC) {
  130                         if (macini) {
  131                                 break;
  132                         }
  133                         macini = c;
  134                 }
  135                 if (c->cri_alg == CRYPTO_DES_CBC ||
  136                     c->cri_alg == CRYPTO_3DES_CBC ||
  137                     c->cri_alg == CRYPTO_AES_CBC ||
  138                     c->cri_alg == CRYPTO_NULL_CBC) {
  139                         if (encini) {
  140                                 break;
  141                         }
  142                         encini = c;
  143                 }
  144                 c = c->cri_next;
  145         }
  146         if (!macini && !encini) {
  147                 dprintf("%s,%d - EINVAL bad cipher/hash or combination\n",
  148                                 __FILE__, __LINE__);
  149                 return EINVAL;
  150         }
  151         if (c) {
  152                 dprintf("%s,%d - EINVAL cannot handle chained cipher/hash combos\n",
  153                                 __FILE__, __LINE__);
  154                 return EINVAL;
  155         }
  156 
  157         /*
  158          * So we have something we can do, lets setup the session
  159          */
  160         ocd = crypto_get_driver_session(cses);
  161 
  162         if (encini && encini->cri_key) {
  163                 ocd->octo_encklen = (encini->cri_klen + 7) / 8;
  164                 memcpy(ocd->octo_enckey, encini->cri_key, ocd->octo_encklen);
  165         }
  166 
  167         if (macini && macini->cri_key) {
  168                 ocd->octo_macklen = (macini->cri_klen + 7) / 8;
  169                 memcpy(ocd->octo_mackey, macini->cri_key, ocd->octo_macklen);
  170         }
  171 
  172         ocd->octo_mlen = 0;
  173         if (encini && encini->cri_mlen)
  174                 ocd->octo_mlen = encini->cri_mlen;
  175         else if (macini && macini->cri_mlen)
  176                 ocd->octo_mlen = macini->cri_mlen;
  177         else
  178                 ocd->octo_mlen = 12;
  179 
  180         /*
  181          * point c at the enc if it exists, otherwise the mac
  182          */
  183         c = encini ? encini : macini;
  184 
  185         switch (c->cri_alg) {
  186         case CRYPTO_DES_CBC:
  187         case CRYPTO_3DES_CBC:
  188                 ocd->octo_ivsize  = 8;
  189                 switch (macini ? macini->cri_alg : -1) {
  190                 case CRYPTO_MD5_HMAC:
  191                         ocd->octo_encrypt = octo_des_cbc_md5_encrypt;
  192                         ocd->octo_decrypt = octo_des_cbc_md5_decrypt;
  193                         octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
  194                                         ocd->octo_hmouter);
  195                         break;
  196                 case CRYPTO_SHA1_HMAC:
  197                         ocd->octo_encrypt = octo_des_cbc_sha1_encrypt;
  198                         ocd->octo_decrypt = octo_des_cbc_sha1_encrypt;
  199                         octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
  200                                         ocd->octo_hmouter);
  201                         break;
  202                 case -1:
  203                         ocd->octo_encrypt = octo_des_cbc_encrypt;
  204                         ocd->octo_decrypt = octo_des_cbc_decrypt;
  205                         break;
  206                 default:
  207                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  208                         return EINVAL;
  209                 }
  210                 break;
  211         case CRYPTO_AES_CBC:
  212                 ocd->octo_ivsize  = 16;
  213                 switch (macini ? macini->cri_alg : -1) {
  214                 case CRYPTO_MD5_HMAC:
  215                         ocd->octo_encrypt = octo_aes_cbc_md5_encrypt;
  216                         ocd->octo_decrypt = octo_aes_cbc_md5_decrypt;
  217                         octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
  218                                         ocd->octo_hmouter);
  219                         break;
  220                 case CRYPTO_SHA1_HMAC:
  221                         ocd->octo_encrypt = octo_aes_cbc_sha1_encrypt;
  222                         ocd->octo_decrypt = octo_aes_cbc_sha1_decrypt;
  223                         octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
  224                                         ocd->octo_hmouter);
  225                         break;
  226                 case -1:
  227                         ocd->octo_encrypt = octo_aes_cbc_encrypt;
  228                         ocd->octo_decrypt = octo_aes_cbc_decrypt;
  229                         break;
  230                 default:
  231                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  232                         return EINVAL;
  233                 }
  234                 break;
  235         case CRYPTO_MD5_HMAC:
  236                 ocd->octo_encrypt = octo_null_md5_encrypt;
  237                 ocd->octo_decrypt = octo_null_md5_encrypt;
  238                 octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
  239                                 ocd->octo_hmouter);
  240                 break;
  241         case CRYPTO_SHA1_HMAC:
  242                 ocd->octo_encrypt = octo_null_sha1_encrypt;
  243                 ocd->octo_decrypt = octo_null_sha1_encrypt;
  244                 octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
  245                                 ocd->octo_hmouter);
  246                 break;
  247         default:
  248                 dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
  249                 return EINVAL;
  250         }
  251 
  252         ocd->octo_encalg = encini ? encini->cri_alg : -1;
  253         ocd->octo_macalg = macini ? macini->cri_alg : -1;
  254 
  255         return (0);
  256 }
  257 
  258 /*
  259  * Process a request.
  260  */
  261 static int
  262 cryptocteon_process(device_t dev, struct cryptop *crp, int hint)
  263 {
  264         struct cryptodesc *crd;
  265         struct octo_sess *od;
  266         size_t iovcnt, iovlen;
  267         struct mbuf *m = NULL;
  268         struct uio *uiop = NULL;
  269         struct cryptodesc *enccrd = NULL, *maccrd = NULL;
  270         unsigned char *ivp = NULL;
  271         unsigned char iv_data[HASH_MAX_LEN];
  272         int auth_off = 0, auth_len = 0, crypt_off = 0, crypt_len = 0, icv_off = 0;
  273         struct cryptocteon_softc *sc;
  274 
  275         sc = device_get_softc(dev);
  276 
  277         if (sc == NULL || crp == NULL)
  278                 return EINVAL;
  279 
  280         crp->crp_etype = 0;
  281 
  282         if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
  283                 dprintf("%s,%d: EINVAL\n", __FILE__, __LINE__);
  284                 crp->crp_etype = EINVAL;
  285                 goto done;
  286         }
  287 
  288         od = crypto_get_driver_session(crp->crp_session);
  289 
  290         /*
  291          * do some error checking outside of the loop for m and IOV processing
  292          * this leaves us with valid m or uiop pointers for later
  293          */
  294         if (crp->crp_flags & CRYPTO_F_IMBUF) {
  295                 unsigned frags;
  296 
  297                 m = (struct mbuf *) crp->crp_buf;
  298                 for (frags = 0; m != NULL; frags++)
  299                         m = m->m_next;
  300 
  301                 if (frags >= UIO_MAXIOV) {
  302                         printf("%s,%d: %d frags > UIO_MAXIOV", __FILE__, __LINE__, frags);
  303                         goto done;
  304                 }
  305 
  306                 m = (struct mbuf *) crp->crp_buf;
  307         } else if (crp->crp_flags & CRYPTO_F_IOV) {
  308                 uiop = (struct uio *) crp->crp_buf;
  309                 if (uiop->uio_iovcnt > UIO_MAXIOV) {
  310                         printf("%s,%d: %d uio_iovcnt > UIO_MAXIOV", __FILE__, __LINE__,
  311                                uiop->uio_iovcnt);
  312                         goto done;
  313                 }
  314         }
  315 
  316         /* point our enccrd and maccrd appropriately */
  317         crd = crp->crp_desc;
  318         if (crd->crd_alg == od->octo_encalg)
  319                 enccrd = crd;
  320         if (crd->crd_alg == od->octo_macalg)
  321                 maccrd = crd;
  322         crd = crd->crd_next;
  323         if (crd) {
  324                 if (crd->crd_alg == od->octo_encalg)
  325                         enccrd = crd;
  326                 if (crd->crd_alg == od->octo_macalg)
  327                         maccrd = crd;
  328                 crd = crd->crd_next;
  329         }
  330         if (crd) {
  331                 crp->crp_etype = EINVAL;
  332                 dprintf("%s,%d: ENOENT - descriptors do not match session\n",
  333                                 __FILE__, __LINE__);
  334                 goto done;
  335         }
  336 
  337         if (enccrd) {
  338                 if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
  339                         ivp = enccrd->crd_iv;
  340                 } else {
  341                         ivp = iv_data;
  342                         crypto_copydata(crp->crp_flags, crp->crp_buf,
  343                                         enccrd->crd_inject, od->octo_ivsize, (caddr_t) ivp);
  344                 }
  345 
  346                 if (maccrd) {
  347                         auth_off = maccrd->crd_skip;
  348                         auth_len = maccrd->crd_len;
  349                         icv_off  = maccrd->crd_inject;
  350                 }
  351 
  352                 crypt_off = enccrd->crd_skip;
  353                 crypt_len = enccrd->crd_len;
  354         } else { /* if (maccrd) */
  355                 auth_off = maccrd->crd_skip;
  356                 auth_len = maccrd->crd_len;
  357                 icv_off  = maccrd->crd_inject;
  358         }
  359 
  360         /*
  361          * setup the I/O vector to cover the buffer
  362          */
  363         if (crp->crp_flags & CRYPTO_F_IMBUF) {
  364                 iovcnt = 0;
  365                 iovlen = 0;
  366 
  367                 while (m != NULL) {
  368                         od->octo_iov[iovcnt].iov_base = mtod(m, void *);
  369                         od->octo_iov[iovcnt].iov_len = m->m_len;
  370 
  371                         m = m->m_next;
  372                         iovlen += od->octo_iov[iovcnt++].iov_len;
  373                 }
  374         } else if (crp->crp_flags & CRYPTO_F_IOV) {
  375                 iovlen = 0;
  376                 for (iovcnt = 0; iovcnt < uiop->uio_iovcnt; iovcnt++) {
  377                         od->octo_iov[iovcnt].iov_base = uiop->uio_iov[iovcnt].iov_base;
  378                         od->octo_iov[iovcnt].iov_len = uiop->uio_iov[iovcnt].iov_len;
  379 
  380                         iovlen += od->octo_iov[iovcnt].iov_len;
  381                 }
  382         } else {
  383                 iovlen = crp->crp_ilen;
  384                 od->octo_iov[0].iov_base = crp->crp_buf;
  385                 od->octo_iov[0].iov_len = crp->crp_ilen;
  386                 iovcnt = 1;
  387         }
  388 
  389 
  390         /*
  391          * setup a new explicit key
  392          */
  393         if (enccrd) {
  394                 if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
  395                         od->octo_encklen = (enccrd->crd_klen + 7) / 8;
  396                         memcpy(od->octo_enckey, enccrd->crd_key, od->octo_encklen);
  397                 }
  398         }
  399         if (maccrd) {
  400                 if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
  401                         od->octo_macklen = (maccrd->crd_klen + 7) / 8;
  402                         memcpy(od->octo_mackey, maccrd->crd_key, od->octo_macklen);
  403                         od->octo_mackey_set = 0;
  404                 }
  405                 if (!od->octo_mackey_set) {
  406                         octo_calc_hash(maccrd->crd_alg == CRYPTO_MD5_HMAC ? 0 : 1,
  407                                 maccrd->crd_key, od->octo_hminner, od->octo_hmouter);
  408                         od->octo_mackey_set = 1;
  409                 }
  410         }
  411 
  412 
  413         if (!enccrd || (enccrd->crd_flags & CRD_F_ENCRYPT))
  414                 (*od->octo_encrypt)(od, od->octo_iov, iovcnt, iovlen,
  415                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
  416         else
  417                 (*od->octo_decrypt)(od, od->octo_iov, iovcnt, iovlen,
  418                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
  419 
  420 done:
  421         crypto_done(crp);
  422         return (0);
  423 }
  424 
  425 static device_method_t cryptocteon_methods[] = {
  426         /* device methods */
  427         DEVMETHOD(device_identify,      cryptocteon_identify),
  428         DEVMETHOD(device_probe,         cryptocteon_probe),
  429         DEVMETHOD(device_attach,        cryptocteon_attach),
  430 
  431         /* crypto device methods */
  432         DEVMETHOD(cryptodev_newsession, cryptocteon_newsession),
  433         DEVMETHOD(cryptodev_process,    cryptocteon_process),
  434 
  435         { 0, 0 }
  436 };
  437 
  438 static driver_t cryptocteon_driver = {
  439         "cryptocteon",
  440         cryptocteon_methods,
  441         sizeof (struct cryptocteon_softc),
  442 };
  443 static devclass_t cryptocteon_devclass;
  444 DRIVER_MODULE(cryptocteon, nexus, cryptocteon_driver, cryptocteon_devclass, 0, 0);

Cache object: 693a798d4b831e2c513619141ec90e52


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.