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/crypto/via/padlock.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  * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/6.4/sys/crypto/via/padlock.c 162001 2006-09-04 15:21:11Z pjd $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/malloc.h>
   37 #include <sys/libkern.h>
   38 #if defined(__i386__) && !defined(PC98)
   39 #include <machine/cpufunc.h>
   40 #include <machine/cputypes.h>
   41 #include <machine/md_var.h>
   42 #include <machine/specialreg.h>
   43 #endif
   44 
   45 #include <opencrypto/cryptodev.h>
   46 
   47 #include <crypto/via/padlock.h>
   48 
   49 /*
   50  * Technical documentation about the PadLock engine can be found here:
   51  *
   52  * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/programming_guide.pdf
   53  */
   54 
   55 struct padlock_softc {
   56         int32_t         sc_cid;
   57         uint32_t        sc_sid;
   58         TAILQ_HEAD(, padlock_session) sc_sessions;
   59         struct mtx      sc_sessions_mtx;
   60 };
   61 
   62 static struct padlock_softc *padlock_sc;
   63 
   64 static int padlock_newsession(void *arg __unused, uint32_t *sidp,
   65     struct cryptoini *cri);
   66 static int padlock_freesession(void *arg __unused, uint64_t tid);
   67 static int padlock_process(void *arg __unused, struct cryptop *crp,
   68     int hint __unused);
   69 
   70 MALLOC_DEFINE(M_PADLOCK, "padlock_data", "PadLock Data");
   71 
   72 static int
   73 padlock_init(void)
   74 {
   75         struct padlock_softc *sc;
   76         char capp[256];
   77 
   78 #if defined(__i386__) && !defined(PC98)
   79         /* If there is no AES support, we has nothing to do here. */
   80         if (!(via_feature_xcrypt & VIA_HAS_AES)) {
   81                 printf("PadLock: No ACE support.\n");
   82                 return (EINVAL);
   83         }
   84         strlcpy(capp, "AES-CBC", sizeof(capp));
   85 #if 0
   86         strlcat(capp, ",AES-EBC", sizeof(capp));
   87         strlcat(capp, ",AES-CFB", sizeof(capp));
   88         strlcat(capp, ",AES-OFB", sizeof(capp));
   89 #endif
   90         if (via_feature_xcrypt & VIA_HAS_SHA) {
   91                 strlcat(capp, ",SHA1", sizeof(capp));
   92                 strlcat(capp, ",SHA256", sizeof(capp));
   93         }
   94 #if 0
   95         if (via_feature_xcrypt & VIA_HAS_AESCTR)
   96                 strlcat(capp, ",AES-CTR", sizeof(capp));
   97         if (via_feature_xcrypt & VIA_HAS_MM)
   98                 strlcat(capp, ",RSA", sizeof(capp));
   99 #endif
  100         printf("PadLock: HW support loaded for %s.\n", capp);
  101 #else
  102         return (EINVAL);
  103 #endif
  104 
  105         padlock_sc = sc = malloc(sizeof(*padlock_sc), M_PADLOCK,
  106             M_WAITOK | M_ZERO);
  107         TAILQ_INIT(&sc->sc_sessions);
  108         sc->sc_sid = 1;
  109 
  110         sc->sc_cid = crypto_get_driverid(0);
  111         if (sc->sc_cid < 0) {
  112                 printf("PadLock: Could not get crypto driver id.\n");
  113                 free(padlock_sc, M_PADLOCK);
  114                 padlock_sc = NULL;
  115                 return (ENOMEM);
  116         }
  117 
  118         mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF);
  119         crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, padlock_newsession,
  120             padlock_freesession, padlock_process, NULL);
  121         crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, padlock_newsession,
  122             padlock_freesession, padlock_process, NULL);
  123         crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, padlock_newsession,
  124             padlock_freesession, padlock_process, NULL);
  125         crypto_register(sc->sc_cid, CRYPTO_RIPEMD160_HMAC, 0, 0,
  126             padlock_newsession, padlock_freesession, padlock_process, NULL);
  127         crypto_register(sc->sc_cid, CRYPTO_SHA2_256_HMAC, 0, 0,
  128             padlock_newsession, padlock_freesession, padlock_process, NULL);
  129         crypto_register(sc->sc_cid, CRYPTO_SHA2_384_HMAC, 0, 0,
  130             padlock_newsession, padlock_freesession, padlock_process, NULL);
  131         crypto_register(sc->sc_cid, CRYPTO_SHA2_512_HMAC, 0, 0,
  132             padlock_newsession, padlock_freesession, padlock_process, NULL);
  133         return (0);
  134 }
  135 
  136 static int
  137 padlock_destroy(void)
  138 {
  139         struct padlock_softc *sc = padlock_sc;
  140         struct padlock_session *ses;
  141         u_int active = 0;
  142 
  143         if (sc == NULL)
  144                 return (0);
  145         mtx_lock(&sc->sc_sessions_mtx);
  146         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  147                 if (ses->ses_used)
  148                         active++;
  149         }
  150         if (active > 0) {
  151                 mtx_unlock(&sc->sc_sessions_mtx);
  152                 printf("PadLock: Cannot destroy, %u sessions active.\n",
  153                     active);
  154                 return (EBUSY);
  155         }
  156         padlock_sc = NULL;
  157         for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL;
  158             ses = TAILQ_FIRST(&sc->sc_sessions)) {
  159                 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  160                 free(ses, M_PADLOCK);
  161         }
  162         mtx_destroy(&sc->sc_sessions_mtx);
  163         crypto_unregister_all(sc->sc_cid);
  164         free(sc, M_PADLOCK);
  165         return (0);
  166 }
  167 
  168 static int
  169 padlock_newsession(void *arg __unused, uint32_t *sidp, struct cryptoini *cri)
  170 {
  171         struct padlock_softc *sc = padlock_sc;
  172         struct padlock_session *ses = NULL;
  173         struct cryptoini *encini, *macini;
  174         int error;
  175 
  176         if (sc == NULL || sidp == NULL || cri == NULL)
  177                 return (EINVAL);
  178 
  179         encini = macini = NULL;
  180         for (; cri != NULL; cri = cri->cri_next) {
  181                 switch (cri->cri_alg) {
  182                 case CRYPTO_NULL_HMAC:
  183                 case CRYPTO_MD5_HMAC:
  184                 case CRYPTO_SHA1_HMAC:
  185                 case CRYPTO_RIPEMD160_HMAC:
  186                 case CRYPTO_SHA2_256_HMAC:
  187                 case CRYPTO_SHA2_384_HMAC:
  188                 case CRYPTO_SHA2_512_HMAC:
  189                         if (macini != NULL)
  190                                 return (EINVAL);
  191                         macini = cri;
  192                         break;
  193                 case CRYPTO_AES_CBC:
  194                         if (encini != NULL)
  195                                 return (EINVAL);
  196                         encini = cri;
  197                         break;
  198                 default:
  199                         return (EINVAL);
  200                 }
  201         }
  202 
  203         /*
  204          * We only support HMAC algorithms to be able to work with
  205          * fast_ipsec(4), so if we are asked only for authentication without
  206          * encryption, don't pretend we can accellerate it.
  207          */
  208         if (encini == NULL)
  209                 return (EINVAL);
  210 
  211         /*
  212          * Let's look for a free session structure.
  213          */
  214         mtx_lock(&sc->sc_sessions_mtx);
  215         /*
  216          * Free sessions goes first, so if first session is used, we need to
  217          * allocate one.
  218          */
  219         ses = TAILQ_FIRST(&sc->sc_sessions);
  220         if (ses == NULL || ses->ses_used)
  221                 ses = NULL;
  222         else {
  223                 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  224                 ses->ses_used = 1;
  225                 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  226         }
  227         mtx_unlock(&sc->sc_sessions_mtx);
  228         if (ses == NULL) {
  229                 ses = malloc(sizeof(*ses), M_PADLOCK, M_NOWAIT | M_ZERO);
  230                 if (ses == NULL)
  231                         return (ENOMEM);
  232                 ses->ses_used = 1;
  233                 mtx_lock(&sc->sc_sessions_mtx);
  234                 ses->ses_id = sc->sc_sid++;
  235                 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  236                 mtx_unlock(&sc->sc_sessions_mtx);
  237         }
  238 
  239         error = padlock_cipher_setup(ses, encini);
  240         if (error != 0) {
  241                 padlock_freesession(NULL, ses->ses_id);
  242                 return (error);
  243         }
  244 
  245         if (macini != NULL) {
  246                 error = padlock_hash_setup(ses, macini);
  247                 if (error != 0) {
  248                         padlock_freesession(NULL, ses->ses_id);
  249                         return (error);
  250                 }
  251         }
  252 
  253         *sidp = ses->ses_id;
  254         return (0);
  255 }
  256 
  257 static int
  258 padlock_freesession(void *arg __unused, uint64_t tid)
  259 {
  260         struct padlock_softc *sc = padlock_sc;
  261         struct padlock_session *ses;
  262         uint32_t sid = ((uint32_t)tid) & 0xffffffff;
  263 
  264         if (sc == NULL)
  265                 return (EINVAL);
  266         mtx_lock(&sc->sc_sessions_mtx);
  267         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  268                 if (ses->ses_id == sid)
  269                         break;
  270         }
  271         if (ses == NULL) {
  272                 mtx_unlock(&sc->sc_sessions_mtx);
  273                 return (EINVAL);
  274         }
  275         TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
  276         padlock_hash_free(ses);
  277         bzero(ses, sizeof(*ses));
  278         ses->ses_used = 0;
  279         TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
  280         mtx_unlock(&sc->sc_sessions_mtx);
  281         return (0);
  282 }
  283 
  284 static int
  285 padlock_process(void *arg __unused, struct cryptop *crp, int hint __unused)
  286 {
  287         struct padlock_softc *sc = padlock_sc;
  288         struct padlock_session *ses = NULL;
  289         struct cryptodesc *crd, *enccrd, *maccrd;
  290         int error = 0;
  291 
  292         enccrd = maccrd = NULL;
  293 
  294         if (crp == NULL || crp->crp_callback == NULL || crp->crp_desc == NULL) {
  295                 error = EINVAL;
  296                 goto out;
  297         }
  298 
  299         for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
  300                 switch (crd->crd_alg) {
  301                 case CRYPTO_NULL_HMAC:
  302                 case CRYPTO_MD5_HMAC:
  303                 case CRYPTO_SHA1_HMAC:
  304                 case CRYPTO_RIPEMD160_HMAC:
  305                 case CRYPTO_SHA2_256_HMAC:
  306                 case CRYPTO_SHA2_384_HMAC:
  307                 case CRYPTO_SHA2_512_HMAC:
  308                         if (maccrd != NULL) {
  309                                 error = EINVAL;
  310                                 goto out;
  311                         }
  312                         maccrd = crd;
  313                         break;
  314                 case CRYPTO_AES_CBC:
  315                         if (enccrd != NULL) {
  316                                 error = EINVAL;
  317                                 goto out;
  318                         }
  319                         enccrd = crd;
  320                         break;
  321                 default:
  322                         return (EINVAL);
  323                 }
  324         }
  325         if (enccrd == NULL || (enccrd->crd_len % AES_BLOCK_LEN) != 0) {
  326                 error = EINVAL;
  327                 goto out;
  328         }
  329 
  330         mtx_lock(&sc->sc_sessions_mtx);
  331         TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
  332                 if (ses->ses_id == (crp->crp_sid & 0xffffffff))
  333                         break;
  334         }
  335         mtx_unlock(&sc->sc_sessions_mtx);
  336         if (ses == NULL) {
  337                 error = EINVAL;
  338                 goto out;
  339         }
  340 
  341         /* Perform data authentication if requested before encryption. */
  342         if (maccrd != NULL && maccrd->crd_next == enccrd) {
  343                 error = padlock_hash_process(ses, maccrd, crp);
  344                 if (error != 0)
  345                         goto out;
  346         }
  347 
  348         error = padlock_cipher_process(ses, enccrd, crp);
  349         if (error != 0)
  350                 goto out;
  351 
  352         /* Perform data authentication if requested after encryption. */
  353         if (maccrd != NULL && enccrd->crd_next == maccrd) {
  354                 error = padlock_hash_process(ses, maccrd, crp);
  355                 if (error != 0)
  356                         goto out;
  357         }
  358 
  359 out:
  360 #if 0
  361         /*
  362          * This code is not necessary, because contexts will be freed on next
  363          * padlock_setup_mackey() call or at padlock_freesession() call.
  364          */
  365         if (ses != NULL && maccrd != NULL &&
  366             (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) {
  367                 padlock_free_ctx(ses->ses_axf, ses->ses_ictx);
  368                 padlock_free_ctx(ses->ses_axf, ses->ses_octx);
  369         }
  370 #endif
  371         crp->crp_etype = error;
  372         crypto_done(crp);
  373         return (error);
  374 }
  375 
  376 static int
  377 padlock_modevent(module_t mod, int type, void *unused __unused)
  378 {
  379         int error;
  380 
  381         error = EOPNOTSUPP;
  382         switch (type) {
  383         case MOD_LOAD:
  384                 error = padlock_init();
  385                 break;
  386         case MOD_UNLOAD:
  387                 error = padlock_destroy();
  388                 break;
  389         }
  390         return (error);
  391 }
  392 
  393 static moduledata_t padlock_mod = {
  394         "padlock",
  395         padlock_modevent,
  396         0
  397 };
  398 DECLARE_MODULE(padlock, padlock_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
  399 MODULE_VERSION(padlock, 1);
  400 MODULE_DEPEND(padlock, crypto, 1, 1, 1);

Cache object: 9373f8b7d929354c0b150ee243a38407


[ 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.