| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693 |
- From 37a5c14aad5051201e4bd18faf1a4b25a824cc30 Mon Sep 17 00:00:00 2001
- From: Eneas U de Queiroz <[email protected]>
- Date: Tue, 6 Nov 2018 10:57:03 -0200
- Subject: [PATCH 4/4] e_devcrypto: make the /dev/crypto engine dynamic
- Engine has been moved from crypto/engine/eng_devcrypto.c to
- engines/e_devcrypto.c.
- Signed-off-by: Eneas U de Queiroz <[email protected]>
- --- a/crypto/engine/build.info
- +++ b/crypto/engine/build.info
- @@ -6,6 +6,3 @@ SOURCE[../../libcrypto]=\
- tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c tb_eckey.c \
- eng_openssl.c eng_cnf.c eng_dyn.c \
- eng_rdrand.c
- -IF[{- !$disabled{devcryptoeng} -}]
- - SOURCE[../../libcrypto]=eng_devcrypto.c
- -ENDIF
- --- a/crypto/init.c
- +++ b/crypto/init.c
- @@ -330,18 +330,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_
- engine_load_openssl_int();
- return 1;
- }
- -# ifndef OPENSSL_NO_DEVCRYPTOENG
- -static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
- -DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
- -{
- -# ifdef OPENSSL_INIT_DEBUG
- - fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
- - "engine_load_devcrypto_int()\n");
- -# endif
- - engine_load_devcrypto_int();
- - return 1;
- -}
- -# endif
-
- # ifndef OPENSSL_NO_RDRAND
- static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
- @@ -366,6 +354,18 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_
- return 1;
- }
- # ifndef OPENSSL_NO_STATIC_ENGINE
- +# ifndef OPENSSL_NO_DEVCRYPTOENG
- +static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
- +DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
- +{
- +# ifdef OPENSSL_INIT_DEBUG
- + fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
- + "engine_load_devcrypto_int()\n");
- +# endif
- + engine_load_devcrypto_int();
- + return 1;
- +}
- +# endif
- # if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
- static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
- DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
- @@ -714,11 +714,6 @@ int OPENSSL_init_crypto(uint64_t opts, c
- if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
- && !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
- return 0;
- -# if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_DEVCRYPTOENG)
- - if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
- - && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
- - return 0;
- -# endif
- # ifndef OPENSSL_NO_RDRAND
- if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
- && !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
- @@ -728,6 +723,11 @@ int OPENSSL_init_crypto(uint64_t opts, c
- && !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
- return 0;
- # ifndef OPENSSL_NO_STATIC_ENGINE
- +# ifndef OPENSSL_NO_DEVCRYPTOENG
- + if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
- + && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
- + return 0;
- +# endif
- # if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
- if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
- && !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
- --- a/engines/build.info
- +++ b/engines/build.info
- @@ -10,6 +10,9 @@ IF[{- !$disabled{"engine"} -}]
- IF[{- !$disabled{afalgeng} -}]
- SOURCE[../libcrypto]=e_afalg.c
- ENDIF
- + IF[{- !$disabled{"devcryptoeng"} -}]
- + SOURCE[../libcrypto]=e_devcrypto.c
- + ENDIF
- ELSE
- ENGINES=padlock
- SOURCE[padlock]=e_padlock.c {- $target{padlock_asm_src} -}
- @@ -27,6 +30,12 @@ IF[{- !$disabled{"engine"} -}]
- DEPEND[afalg]=../libcrypto
- INCLUDE[afalg]= ../include
- ENDIF
- + IF[{- !$disabled{"devcryptoeng"} -}]
- + ENGINES=devcrypto
- + SOURCE[devcrypto]=e_devcrypto.c
- + DEPEND[devcrypto]=../libcrypto
- + INCLUDE[devcrypto]=../include
- + ENDIF
-
- ENGINES_NO_INST=ossltest dasync
- SOURCE[dasync]=e_dasync.c
- --- a/crypto/engine/eng_devcrypto.c
- +++ /dev/null
- @@ -1,1264 +0,0 @@
- -/*
- - * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
- - *
- - * Licensed under the OpenSSL license (the "License"). You may not use
- - * this file except in compliance with the License. You can obtain a copy
- - * in the file LICENSE in the source distribution or at
- - * https://www.openssl.org/source/license.html
- - */
- -
- -#include "e_os.h"
- -#include <string.h>
- -#include <sys/types.h>
- -#include <sys/stat.h>
- -#include <fcntl.h>
- -#include <sys/ioctl.h>
- -#include <unistd.h>
- -#include <assert.h>
- -
- -#include <openssl/conf.h>
- -#include <openssl/evp.h>
- -#include <openssl/err.h>
- -#include <openssl/engine.h>
- -#include <openssl/objects.h>
- -#include <crypto/cryptodev.h>
- -
- -#include "internal/engine.h"
- -
- -/* #define ENGINE_DEVCRYPTO_DEBUG */
- -
- -#ifdef CRYPTO_ALGORITHM_MIN
- -# define CHECK_BSD_STYLE_MACROS
- -#endif
- -
- -/*
- - * ONE global file descriptor for all sessions. This allows operations
- - * such as digest session data copying (see digest_copy()), but is also
- - * saner... why re-open /dev/crypto for every session?
- - */
- -static int cfd;
- -#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
- -#define DEVCRYPTO_USE_SOFTWARE 1 /* allow software drivers */
- -#define DEVCRYPTO_REJECT_SOFTWARE 2 /* only disallow confirmed software drivers */
- -
- -#define DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS DEVCRYPTO_REJECT_SOFTWARE
- -static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
- -
- -/*
- - * cipher/digest status & acceleration definitions
- - * Make sure the defaults are set to 0
- - */
- -struct driver_info_st {
- - enum devcrypto_status_t {
- - DEVCRYPTO_STATUS_FAILURE = -3, /* unusable for other reason */
- - DEVCRYPTO_STATUS_NO_CIOCCPHASH = -2, /* hash state copy not supported */
- - DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */
- - DEVCRYPTO_STATUS_UNKNOWN = 0, /* not tested yet */
- - DEVCRYPTO_STATUS_USABLE = 1 /* algo can be used */
- - } status;
- -
- - enum devcrypto_accelerated_t {
- - DEVCRYPTO_NOT_ACCELERATED = -1, /* software implemented */
- - DEVCRYPTO_ACCELERATION_UNKNOWN = 0, /* acceleration support unkown */
- - DEVCRYPTO_ACCELERATED = 1 /* hardware accelerated */
- - } accelerated;
- -
- - char *driver_name;
- -};
- -
- -static int clean_devcrypto_session(struct session_op *sess) {
- - if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- - memset(sess, 0, sizeof(struct session_op));
- - return 1;
- -}
- -
- -/******************************************************************************
- - *
- - * Ciphers
- - *
- - * Because they all do the same basic operation, we have only one set of
- - * method functions for them all to share, and a mapping table between
- - * NIDs and cryptodev IDs, with all the necessary size data.
- - *
- - *****/
- -
- -struct cipher_ctx {
- - struct session_op sess;
- - int op; /* COP_ENCRYPT or COP_DECRYPT */
- - unsigned long mode; /* EVP_CIPH_*_MODE */
- -
- - /* to handle ctr mode being a stream cipher */
- - unsigned char partial[EVP_MAX_BLOCK_LENGTH];
- - unsigned int blocksize, num;
- -};
- -
- -static const struct cipher_data_st {
- - int nid;
- - int blocksize;
- - int keylen;
- - int ivlen;
- - int flags;
- - int devcryptoid;
- -} cipher_data[] = {
- -#ifndef OPENSSL_NO_DES
- - { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },
- - { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },
- -#endif
- -#ifndef OPENSSL_NO_BF
- - { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },
- -#endif
- -#ifndef OPENSSL_NO_CAST
- - { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },
- -#endif
- - { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- - { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- - { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- -#ifndef OPENSSL_NO_RC4
- - { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)
- - { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- - { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- - { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- -#endif
- -#if 0 /* Not yet supported */
- - { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
- - { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)
- - { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- - { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- - { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- -#endif
- -#if 0 /* Not yet supported */
- - { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- - { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- - { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- -#endif
- -#ifndef OPENSSL_NO_CAMELLIA
- - { NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,
- - CRYPTO_CAMELLIA_CBC },
- - { NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,
- - CRYPTO_CAMELLIA_CBC },
- - { NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,
- - CRYPTO_CAMELLIA_CBC },
- -#endif
- -};
- -
- -static size_t find_cipher_data_index(int nid)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(cipher_data); i++)
- - if (nid == cipher_data[i].nid)
- - return i;
- - return (size_t)-1;
- -}
- -
- -static size_t get_cipher_data_index(int nid)
- -{
- - size_t i = find_cipher_data_index(nid);
- -
- - if (i != (size_t)-1)
- - return i;
- -
- - /*
- - * Code further down must make sure that only NIDs in the table above
- - * are used. If any other NID reaches this function, there's a grave
- - * coding error further down.
- - */
- - assert("Code that never should be reached" == NULL);
- - return -1;
- -}
- -
- -static const struct cipher_data_st *get_cipher_data(int nid)
- -{
- - return &cipher_data[get_cipher_data_index(nid)];
- -}
- -
- -/*
- - * Following are the three necessary functions to map OpenSSL functionality
- - * with cryptodev.
- - */
- -
- -static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
- - const unsigned char *iv, int enc)
- -{
- - struct cipher_ctx *cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- - const struct cipher_data_st *cipher_d =
- - get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
- -
- - /* cleanup a previous session */
- - if (cipher_ctx->sess.ses != 0 &&
- - clean_devcrypto_session(&cipher_ctx->sess) == 0)
- - return 0;
- -
- - cipher_ctx->sess.cipher = cipher_d->devcryptoid;
- - cipher_ctx->sess.keylen = cipher_d->keylen;
- - cipher_ctx->sess.key = (void *)key;
- - cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;
- - cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;
- - cipher_ctx->blocksize = cipher_d->blocksize;
- - if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- -
- - return 1;
- -}
- -
- -static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
- - const unsigned char *in, size_t inl)
- -{
- - struct cipher_ctx *cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- - struct crypt_op cryp;
- - unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
- -#if !defined(COP_FLAG_WRITE_IV)
- - unsigned char saved_iv[EVP_MAX_IV_LENGTH];
- - const unsigned char *ivptr;
- - size_t nblocks, ivlen;
- -#endif
- -
- - memset(&cryp, 0, sizeof(cryp));
- - cryp.ses = cipher_ctx->sess.ses;
- - cryp.len = inl;
- - cryp.src = (void *)in;
- - cryp.dst = (void *)out;
- - cryp.iv = (void *)iv;
- - cryp.op = cipher_ctx->op;
- -#if !defined(COP_FLAG_WRITE_IV)
- - cryp.flags = 0;
- -
- - ivlen = EVP_CIPHER_CTX_iv_length(ctx);
- - if (ivlen > 0)
- - switch (cipher_ctx->mode) {
- - case EVP_CIPH_CBC_MODE:
- - assert(inl >= ivlen);
- - if (!EVP_CIPHER_CTX_encrypting(ctx)) {
- - ivptr = in + inl - ivlen;
- - memcpy(saved_iv, ivptr, ivlen);
- - }
- - break;
- -
- - case EVP_CIPH_CTR_MODE:
- - break;
- -
- - default: /* should not happen */
- - return 0;
- - }
- -#else
- - cryp.flags = COP_FLAG_WRITE_IV;
- -#endif
- -
- - if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- -
- -#if !defined(COP_FLAG_WRITE_IV)
- - if (ivlen > 0)
- - switch (cipher_ctx->mode) {
- - case EVP_CIPH_CBC_MODE:
- - assert(inl >= ivlen);
- - if (EVP_CIPHER_CTX_encrypting(ctx))
- - ivptr = out + inl - ivlen;
- - else
- - ivptr = saved_iv;
- -
- - memcpy(iv, ivptr, ivlen);
- - break;
- -
- - case EVP_CIPH_CTR_MODE:
- - nblocks = (inl + cipher_ctx->blocksize - 1)
- - / cipher_ctx->blocksize;
- - do {
- - ivlen--;
- - nblocks += iv[ivlen];
- - iv[ivlen] = (uint8_t) nblocks;
- - nblocks >>= 8;
- - } while (ivlen);
- - break;
- -
- - default: /* should not happen */
- - return 0;
- - }
- -#endif
- -
- - return 1;
- -}
- -
- -static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
- - const unsigned char *in, size_t inl)
- -{
- - struct cipher_ctx *cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- - size_t nblocks, len;
- -
- - /* initial partial block */
- - while (cipher_ctx->num && inl) {
- - (*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];
- - --inl;
- - cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;
- - }
- -
- - /* full blocks */
- - if (inl > (unsigned int) cipher_ctx->blocksize) {
- - nblocks = inl/cipher_ctx->blocksize;
- - len = nblocks * cipher_ctx->blocksize;
- - if (cipher_do_cipher(ctx, out, in, len) < 1)
- - return 0;
- - inl -= len;
- - out += len;
- - in += len;
- - }
- -
- - /* final partial block */
- - if (inl) {
- - memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);
- - if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,
- - cipher_ctx->blocksize) < 1)
- - return 0;
- - while (inl--) {
- - out[cipher_ctx->num] = in[cipher_ctx->num]
- - ^ cipher_ctx->partial[cipher_ctx->num];
- - cipher_ctx->num++;
- - }
- - }
- -
- - return 1;
- -}
- -
- -static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2)
- -{
- - struct cipher_ctx *cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- - EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;
- - struct cipher_ctx *to_cipher_ctx;
- -
- - switch (type) {
- - case EVP_CTRL_COPY:
- - if (cipher_ctx == NULL)
- - return 1;
- - /* when copying the context, a new session needs to be initialized */
- - to_cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);
- - memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));
- - return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),
- - (cipher_ctx->op == COP_ENCRYPT));
- -
- - case EVP_CTRL_INIT:
- - memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));
- - return 1;
- -
- - default:
- - break;
- - }
- -
- - return -1;
- -}
- -
- -static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
- -{
- - struct cipher_ctx *cipher_ctx =
- - (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- -
- - return clean_devcrypto_session(&cipher_ctx->sess);
- -}
- -
- -/*
- - * Keep tables of known nids, associated methods, selected ciphers, and driver
- - * info.
- - * Note that known_cipher_nids[] isn't necessarily indexed the same way as
- - * cipher_data[] above, which the other tables are.
- - */
- -static int known_cipher_nids[OSSL_NELEM(cipher_data)];
- -static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
- -static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
- -static int selected_ciphers[OSSL_NELEM(cipher_data)];
- -static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];
- -
- -
- -static int devcrypto_test_cipher(size_t cipher_data_index)
- -{
- - return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE
- - && selected_ciphers[cipher_data_index] == 1
- - && (cipher_driver_info[cipher_data_index].accelerated
- - == DEVCRYPTO_ACCELERATED
- - || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
- - || (cipher_driver_info[cipher_data_index].accelerated
- - != DEVCRYPTO_NOT_ACCELERATED
- - && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
- -}
- -
- -static void prepare_cipher_methods(void)
- -{
- - size_t i;
- - struct session_op sess;
- - unsigned long cipher_mode;
- -#ifdef CIOCGSESSINFO
- - struct session_info_op siop;
- -#endif
- -
- - memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));
- -
- - memset(&sess, 0, sizeof(sess));
- - sess.key = (void *)"01234567890123456789012345678901234567890123456789";
- -
- - for (i = 0, known_cipher_nids_amount = 0;
- - i < OSSL_NELEM(cipher_data); i++) {
- -
- - selected_ciphers[i] = 1;
- - /*
- - * Check that the cipher is usable
- - */
- - sess.cipher = cipher_data[i].devcryptoid;
- - sess.keylen = cipher_data[i].keylen;
- - if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
- - cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
- - continue;
- - }
- -
- - cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
- -
- - if ((known_cipher_methods[i] =
- - EVP_CIPHER_meth_new(cipher_data[i].nid,
- - cipher_mode == EVP_CIPH_CTR_MODE ? 1 :
- - cipher_data[i].blocksize,
- - cipher_data[i].keylen)) == NULL
- - || !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],
- - cipher_data[i].ivlen)
- - || !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],
- - cipher_data[i].flags
- - | EVP_CIPH_CUSTOM_COPY
- - | EVP_CIPH_CTRL_INIT
- - | EVP_CIPH_FLAG_DEFAULT_ASN1)
- - || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)
- - || !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],
- - cipher_mode == EVP_CIPH_CTR_MODE ?
- - ctr_do_cipher :
- - cipher_do_cipher)
- - || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)
- - || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],
- - cipher_cleanup)
- - || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
- - sizeof(struct cipher_ctx))) {
- - cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- - EVP_CIPHER_meth_free(known_cipher_methods[i]);
- - known_cipher_methods[i] = NULL;
- - } else {
- - cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
- -#ifdef CIOCGSESSINFO
- - siop.ses = sess.ses;
- - if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
- - cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
- - } else {
- - cipher_driver_info[i].driver_name =
- - OPENSSL_strndup(siop.cipher_info.cra_driver_name,
- - CRYPTODEV_MAX_ALG_NAME);
- - if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
- - cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
- - else
- - cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
- - }
- -#endif /* CIOCGSESSINFO */
- - }
- - ioctl(cfd, CIOCFSESSION, &sess.ses);
- - if (devcrypto_test_cipher(i)) {
- - known_cipher_nids[known_cipher_nids_amount++] =
- - cipher_data[i].nid;
- - }
- - }
- -}
- -
- -static void rebuild_known_cipher_nids(ENGINE *e)
- -{
- - size_t i;
- -
- - for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {
- - if (devcrypto_test_cipher(i))
- - known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;
- - }
- - ENGINE_unregister_ciphers(e);
- - ENGINE_register_ciphers(e);
- -}
- -
- -static const EVP_CIPHER *get_cipher_method(int nid)
- -{
- - size_t i = get_cipher_data_index(nid);
- -
- - if (i == (size_t)-1)
- - return NULL;
- - return known_cipher_methods[i];
- -}
- -
- -static int get_cipher_nids(const int **nids)
- -{
- - *nids = known_cipher_nids;
- - return known_cipher_nids_amount;
- -}
- -
- -static void destroy_cipher_method(int nid)
- -{
- - size_t i = get_cipher_data_index(nid);
- -
- - EVP_CIPHER_meth_free(known_cipher_methods[i]);
- - known_cipher_methods[i] = NULL;
- -}
- -
- -static void destroy_all_cipher_methods(void)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
- - destroy_cipher_method(cipher_data[i].nid);
- - OPENSSL_free(cipher_driver_info[i].driver_name);
- - cipher_driver_info[i].driver_name = NULL;
- - }
- -}
- -
- -static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
- - const int **nids, int nid)
- -{
- - if (cipher == NULL)
- - return get_cipher_nids(nids);
- -
- - *cipher = get_cipher_method(nid);
- -
- - return *cipher != NULL;
- -}
- -
- -static void devcrypto_select_all_ciphers(int *cipher_list)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(cipher_data); i++)
- - cipher_list[i] = 1;
- -}
- -
- -static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
- -{
- - int *cipher_list = (int *)usr;
- - char *name;
- - const EVP_CIPHER *EVP;
- - size_t i;
- -
- - if (len == 0)
- - return 1;
- - if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
- - return 0;
- - EVP = EVP_get_cipherbyname(name);
- - if (EVP == NULL)
- - fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
- - else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
- - cipher_list[i] = 1;
- - else
- - fprintf(stderr, "devcrypto: cipher %s not available\n", name);
- - OPENSSL_free(name);
- - return 1;
- -}
- -
- -static void dump_cipher_info(void)
- -{
- - size_t i;
- - const char *name;
- -
- - fprintf (stderr, "Information about ciphers supported by the /dev/crypto"
- - " engine:\n");
- -#ifndef CIOCGSESSINFO
- - fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
- -#endif
- - for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
- - name = OBJ_nid2sn(cipher_data[i].nid);
- - fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
- - name ? name : "unknown", cipher_data[i].nid,
- - cipher_data[i].devcryptoid);
- - if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
- - fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
- - continue;
- - }
- - fprintf (stderr, "driver=%s ", cipher_driver_info[i].driver_name ?
- - cipher_driver_info[i].driver_name : "unknown");
- - if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
- - fprintf(stderr, "(hw accelerated)");
- - else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
- - fprintf(stderr, "(software)");
- - else
- - fprintf(stderr, "(acceleration status unknown)");
- - if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
- - fprintf (stderr, ". Cipher setup failed");
- - fprintf(stderr, "\n");
- - }
- - fprintf(stderr, "\n");
- -}
- -
- -/*
- - * We only support digests if the cryptodev implementation supports multiple
- - * data updates and session copying. Otherwise, we would be forced to maintain
- - * a cache, which is perilous if there's a lot of data coming in (if someone
- - * wants to checksum an OpenSSL tarball, for example).
- - */
- -#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)
- -#define IMPLEMENT_DIGEST
- -
- -/******************************************************************************
- - *
- - * Digests
- - *
- - * Because they all do the same basic operation, we have only one set of
- - * method functions for them all to share, and a mapping table between
- - * NIDs and cryptodev IDs, with all the necessary size data.
- - *
- - *****/
- -
- -struct digest_ctx {
- - struct session_op sess;
- - /* This signals that the init function was called, not that it succeeded. */
- - int init_called;
- - unsigned char digest_res[HASH_MAX_LEN];
- -};
- -
- -static const struct digest_data_st {
- - int nid;
- - int blocksize;
- - int digestlen;
- - int devcryptoid;
- -} digest_data[] = {
- -#ifndef OPENSSL_NO_MD5
- - { NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },
- -#endif
- - { NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },
- -#ifndef OPENSSL_NO_RMD160
- -# if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)
- - { NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },
- -# endif
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)
- - { NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)
- - { NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)
- - { NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },
- -#endif
- -#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)
- - { NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },
- -#endif
- -};
- -
- -static size_t find_digest_data_index(int nid)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(digest_data); i++)
- - if (nid == digest_data[i].nid)
- - return i;
- - return (size_t)-1;
- -}
- -
- -static size_t get_digest_data_index(int nid)
- -{
- - size_t i = find_digest_data_index(nid);
- -
- - if (i != (size_t)-1)
- - return i;
- -
- - /*
- - * Code further down must make sure that only NIDs in the table above
- - * are used. If any other NID reaches this function, there's a grave
- - * coding error further down.
- - */
- - assert("Code that never should be reached" == NULL);
- - return -1;
- -}
- -
- -static const struct digest_data_st *get_digest_data(int nid)
- -{
- - return &digest_data[get_digest_data_index(nid)];
- -}
- -
- -/*
- - * Following are the five necessary functions to map OpenSSL functionality
- - * with cryptodev: init, update, final, cleanup, and copy.
- - */
- -
- -static int digest_init(EVP_MD_CTX *ctx)
- -{
- - struct digest_ctx *digest_ctx =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- - const struct digest_data_st *digest_d =
- - get_digest_data(EVP_MD_CTX_type(ctx));
- -
- - digest_ctx->init_called = 1;
- -
- - memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));
- - digest_ctx->sess.mac = digest_d->devcryptoid;
- - if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- -
- - return 1;
- -}
- -
- -static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,
- - void *res, unsigned int flags)
- -{
- - struct crypt_op cryp;
- -
- - memset(&cryp, 0, sizeof(cryp));
- - cryp.ses = ctx->sess.ses;
- - cryp.len = srclen;
- - cryp.src = (void *)src;
- - cryp.dst = NULL;
- - cryp.mac = res;
- - cryp.flags = flags;
- - return ioctl(cfd, CIOCCRYPT, &cryp);
- -}
- -
- -static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
- -{
- - struct digest_ctx *digest_ctx =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- -
- - if (count == 0)
- - return 1;
- -
- - if (digest_ctx == NULL)
- - return 0;
- -
- - if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
- - if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)
- - return 1;
- - } else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {
- - return 1;
- - }
- -
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- -}
- -
- -static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
- -{
- - struct digest_ctx *digest_ctx =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- -
- - if (md == NULL || digest_ctx == NULL)
- - return 0;
- -
- - if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
- - memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
- - } else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- -
- - return 1;
- -}
- -
- -static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
- -{
- - struct digest_ctx *digest_from =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(from);
- - struct digest_ctx *digest_to =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(to);
- - struct cphash_op cphash;
- -
- - if (digest_from == NULL || digest_from->init_called != 1)
- - return 1;
- -
- - if (!digest_init(to)) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- -
- - cphash.src_ses = digest_from->sess.ses;
- - cphash.dst_ses = digest_to->sess.ses;
- - if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
- - SYSerr(SYS_F_IOCTL, errno);
- - return 0;
- - }
- - return 1;
- -}
- -
- -static int digest_cleanup(EVP_MD_CTX *ctx)
- -{
- - struct digest_ctx *digest_ctx =
- - (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- -
- - if (digest_ctx == NULL)
- - return 1;
- -
- - return clean_devcrypto_session(&digest_ctx->sess);
- -}
- -
- -/*
- - * Keep tables of known nids, associated methods, selected digests, and
- - * driver info.
- - * Note that known_digest_nids[] isn't necessarily indexed the same way as
- - * digest_data[] above, which the other tables are.
- - */
- -static int known_digest_nids[OSSL_NELEM(digest_data)];
- -static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
- -static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
- -static int selected_digests[OSSL_NELEM(digest_data)];
- -static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];
- -
- -static int devcrypto_test_digest(size_t digest_data_index)
- -{
- - return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE
- - && selected_digests[digest_data_index] == 1
- - && (digest_driver_info[digest_data_index].accelerated
- - == DEVCRYPTO_ACCELERATED
- - || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
- - || (digest_driver_info[digest_data_index].accelerated
- - != DEVCRYPTO_NOT_ACCELERATED
- - && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
- -}
- -
- -static void rebuild_known_digest_nids(ENGINE *e)
- -{
- - size_t i;
- -
- - for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {
- - if (devcrypto_test_digest(i))
- - known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
- - }
- - ENGINE_unregister_digests(e);
- - ENGINE_register_digests(e);
- -}
- -
- -static void prepare_digest_methods(void)
- -{
- - size_t i;
- - struct session_op sess1, sess2;
- -#ifdef CIOCGSESSINFO
- - struct session_info_op siop;
- -#endif
- - struct cphash_op cphash;
- -
- - memset(&digest_driver_info, 0, sizeof(digest_driver_info));
- -
- - memset(&sess1, 0, sizeof(sess1));
- - memset(&sess2, 0, sizeof(sess2));
- -
- - for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
- - i++) {
- -
- - selected_digests[i] = 1;
- -
- - /*
- - * Check that the digest is usable
- - */
- - sess1.mac = digest_data[i].devcryptoid;
- - sess2.ses = 0;
- - if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
- - digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
- - goto finish;
- - }
- -
- -#ifdef CIOCGSESSINFO
- - /* gather hardware acceleration info from the driver */
- - siop.ses = sess1.ses;
- - if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
- - digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
- - } else {
- - digest_driver_info[i].driver_name =
- - OPENSSL_strndup(siop.hash_info.cra_driver_name,
- - CRYPTODEV_MAX_ALG_NAME);
- - if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
- - digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
- - else
- - digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
- - }
- -#endif
- -
- - /* digest must be capable of hash state copy */
- - sess2.mac = sess1.mac;
- - if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
- - digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- - goto finish;
- - }
- - cphash.src_ses = sess1.ses;
- - cphash.dst_ses = sess2.ses;
- - if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
- - digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;
- - goto finish;
- - }
- - if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
- - NID_undef)) == NULL
- - || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
- - digest_data[i].blocksize)
- - || !EVP_MD_meth_set_result_size(known_digest_methods[i],
- - digest_data[i].digestlen)
- - || !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)
- - || !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)
- - || !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)
- - || !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)
- - || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
- - || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
- - sizeof(struct digest_ctx))) {
- - digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- - EVP_MD_meth_free(known_digest_methods[i]);
- - known_digest_methods[i] = NULL;
- - goto finish;
- - }
- - digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
- -finish:
- - ioctl(cfd, CIOCFSESSION, &sess1.ses);
- - if (sess2.ses != 0)
- - ioctl(cfd, CIOCFSESSION, &sess2.ses);
- - if (devcrypto_test_digest(i))
- - known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
- - }
- -}
- -
- -static const EVP_MD *get_digest_method(int nid)
- -{
- - size_t i = get_digest_data_index(nid);
- -
- - if (i == (size_t)-1)
- - return NULL;
- - return known_digest_methods[i];
- -}
- -
- -static int get_digest_nids(const int **nids)
- -{
- - *nids = known_digest_nids;
- - return known_digest_nids_amount;
- -}
- -
- -static void destroy_digest_method(int nid)
- -{
- - size_t i = get_digest_data_index(nid);
- -
- - EVP_MD_meth_free(known_digest_methods[i]);
- - known_digest_methods[i] = NULL;
- -}
- -
- -static void destroy_all_digest_methods(void)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(digest_data); i++) {
- - destroy_digest_method(digest_data[i].nid);
- - OPENSSL_free(digest_driver_info[i].driver_name);
- - digest_driver_info[i].driver_name = NULL;
- - }
- -}
- -
- -static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
- - const int **nids, int nid)
- -{
- - if (digest == NULL)
- - return get_digest_nids(nids);
- -
- - *digest = get_digest_method(nid);
- -
- - return *digest != NULL;
- -}
- -
- -static void devcrypto_select_all_digests(int *digest_list)
- -{
- - size_t i;
- -
- - for (i = 0; i < OSSL_NELEM(digest_data); i++)
- - digest_list[i] = 1;
- -}
- -
- -static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
- -{
- - int *digest_list = (int *)usr;
- - char *name;
- - const EVP_MD *EVP;
- - size_t i;
- -
- - if (len == 0)
- - return 1;
- - if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
- - return 0;
- - EVP = EVP_get_digestbyname(name);
- - if (EVP == NULL)
- - fprintf(stderr, "devcrypto: unknown digest %s\n", name);
- - else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
- - digest_list[i] = 1;
- - else
- - fprintf(stderr, "devcrypto: digest %s not available\n", name);
- - OPENSSL_free(name);
- - return 1;
- -}
- -
- -static void dump_digest_info(void)
- -{
- - size_t i;
- - const char *name;
- -
- - fprintf (stderr, "Information about digests supported by the /dev/crypto"
- - " engine:\n");
- -#ifndef CIOCGSESSINFO
- - fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
- -#endif
- -
- - for (i = 0; i < OSSL_NELEM(digest_data); i++) {
- - name = OBJ_nid2sn(digest_data[i].nid);
- - fprintf (stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",
- - name ? name : "unknown", digest_data[i].nid,
- - digest_data[i].devcryptoid,
- - digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");
- - if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
- - fprintf (stderr, ". CIOCGSESSION (session open) failed\n");
- - continue;
- - }
- - if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
- - fprintf(stderr, " (hw accelerated)");
- - else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
- - fprintf(stderr, " (software)");
- - else
- - fprintf(stderr, " (acceleration status unknown)");
- - if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
- - fprintf (stderr, ". Cipher setup failed\n");
- - else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)
- - fprintf(stderr, ", CIOCCPHASH failed\n");
- - else
- - fprintf(stderr, ", CIOCCPHASH capable\n");
- - }
- - fprintf(stderr, "\n");
- -}
- -
- -#endif
- -
- -/******************************************************************************
- - *
- - * CONTROL COMMANDS
- - *
- - *****/
- -
- -#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE
- -#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)
- -#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)
- -#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
- -
- -/* Helper macros for CPP string composition */
- -#ifndef OPENSSL_MSTR
- -# define OPENSSL_MSTR_HELPER(x) #x
- -# define OPENSSL_MSTR(x) OPENSSL_MSTR_HELPER(x)
- -#endif
- -
- -static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
- -#ifdef CIOCGSESSINFO
- - {DEVCRYPTO_CMD_USE_SOFTDRIVERS,
- - "USE_SOFTDRIVERS",
- - "specifies whether to use software (not accelerated) drivers ("
- - OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, "
- - OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
- - OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
- - "=use if acceleration can't be determined) [default="
- - OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS) "]",
- - ENGINE_CMD_FLAG_NUMERIC},
- -#endif
- -
- - {DEVCRYPTO_CMD_CIPHERS,
- - "CIPHERS",
- - "either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",
- - ENGINE_CMD_FLAG_STRING},
- -
- -#ifdef IMPLEMENT_DIGEST
- - {DEVCRYPTO_CMD_DIGESTS,
- - "DIGESTS",
- - "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
- - ENGINE_CMD_FLAG_STRING},
- -#endif
- -
- - {DEVCRYPTO_CMD_DUMP_INFO,
- - "DUMP_INFO",
- - "dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",
- - ENGINE_CMD_FLAG_NO_INPUT},
- -
- - {0, NULL, NULL, 0}
- -};
- -
- -static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
- -{
- - int *new_list;
- - switch (cmd) {
- -#ifdef CIOCGSESSINFO
- - case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
- - switch (i) {
- - case DEVCRYPTO_REQUIRE_ACCELERATED:
- - case DEVCRYPTO_USE_SOFTWARE:
- - case DEVCRYPTO_REJECT_SOFTWARE:
- - break;
- - default:
- - fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);
- - return 0;
- - }
- - if (use_softdrivers == i)
- - return 1;
- - use_softdrivers = i;
- -#ifdef IMPLEMENT_DIGEST
- - rebuild_known_digest_nids(e);
- -#endif
- - rebuild_known_cipher_nids(e);
- - return 1;
- -#endif /* CIOCGSESSINFO */
- -
- - case DEVCRYPTO_CMD_CIPHERS:
- - if (p == NULL)
- - return 1;
- - if (strcasecmp((const char *)p, "ALL") == 0) {
- - devcrypto_select_all_ciphers(selected_ciphers);
- - } else if (strcasecmp((const char*)p, "NONE") == 0) {
- - memset(selected_ciphers, 0, sizeof(selected_ciphers));
- - } else {
- - new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
- - if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {
- - OPENSSL_free(new_list);
- - return 0;
- - }
- - memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));
- - OPENSSL_free(new_list);
- - }
- - rebuild_known_cipher_nids(e);
- - return 1;
- -
- -#ifdef IMPLEMENT_DIGEST
- - case DEVCRYPTO_CMD_DIGESTS:
- - if (p == NULL)
- - return 1;
- - if (strcasecmp((const char *)p, "ALL") == 0) {
- - devcrypto_select_all_digests(selected_digests);
- - } else if (strcasecmp((const char*)p, "NONE") == 0) {
- - memset(selected_digests, 0, sizeof(selected_digests));
- - } else {
- - new_list=OPENSSL_zalloc(sizeof(selected_digests));
- - if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {
- - OPENSSL_free(new_list);
- - return 0;
- - }
- - memcpy(selected_digests, new_list, sizeof(selected_digests));
- - OPENSSL_free(new_list);
- - }
- - rebuild_known_digest_nids(e);
- - return 1;
- -#endif /* IMPLEMENT_DIGEST */
- -
- - case DEVCRYPTO_CMD_DUMP_INFO:
- - dump_cipher_info();
- -#ifdef IMPLEMENT_DIGEST
- - dump_digest_info();
- -#endif
- - return 1;
- -
- - default:
- - break;
- - }
- - return 0;
- -}
- -
- -/******************************************************************************
- - *
- - * LOAD / UNLOAD
- - *
- - *****/
- -
- -static int devcrypto_unload(ENGINE *e)
- -{
- - destroy_all_cipher_methods();
- -#ifdef IMPLEMENT_DIGEST
- - destroy_all_digest_methods();
- -#endif
- -
- - close(cfd);
- -
- - return 1;
- -}
- -/*
- - * This engine is always built into libcrypto, so it doesn't offer any
- - * ability to be dynamically loadable.
- - */
- -void engine_load_devcrypto_int()
- -{
- - ENGINE *e = NULL;
- -
- - if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
- -#ifndef ENGINE_DEVCRYPTO_DEBUG
- - if (errno != ENOENT)
- -#endif
- - fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
- - return;
- - }
- -
- - if ((e = ENGINE_new()) == NULL
- - || !ENGINE_set_destroy_function(e, devcrypto_unload)) {
- - ENGINE_free(e);
- - /*
- - * We know that devcrypto_unload() won't be called when one of the
- - * above two calls have failed, so we close cfd explicitly here to
- - * avoid leaking resources.
- - */
- - close(cfd);
- - return;
- - }
- -
- - prepare_cipher_methods();
- -#ifdef IMPLEMENT_DIGEST
- - prepare_digest_methods();
- -#endif
- -
- - if (!ENGINE_set_id(e, "devcrypto")
- - || !ENGINE_set_name(e, "/dev/crypto engine")
- - || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
- - || !ENGINE_set_ctrl_function(e, devcrypto_ctrl)
- -
- -/*
- - * Asymmetric ciphers aren't well supported with /dev/crypto. Among the BSD
- - * implementations, it seems to only exist in FreeBSD, and regarding the
- - * parameters in its crypt_kop, the manual crypto(4) has this to say:
- - *
- - * The semantics of these arguments are currently undocumented.
- - *
- - * Reading through the FreeBSD source code doesn't give much more than
- - * their CRK_MOD_EXP implementation for ubsec.
- - *
- - * It doesn't look much better with cryptodev-linux. They have the crypt_kop
- - * structure as well as the command (CRK_*) in cryptodev.h, but no support
- - * seems to be implemented at all for the moment.
- - *
- - * At the time of writing, it seems impossible to write proper support for
- - * FreeBSD's asym features without some very deep knowledge and access to
- - * specific kernel modules.
- - *
- - * /Richard Levitte, 2017-05-11
- - */
- -#if 0
- -# ifndef OPENSSL_NO_RSA
- - || !ENGINE_set_RSA(e, devcrypto_rsa)
- -# endif
- -# ifndef OPENSSL_NO_DSA
- - || !ENGINE_set_DSA(e, devcrypto_dsa)
- -# endif
- -# ifndef OPENSSL_NO_DH
- - || !ENGINE_set_DH(e, devcrypto_dh)
- -# endif
- -# ifndef OPENSSL_NO_EC
- - || !ENGINE_set_EC(e, devcrypto_ec)
- -# endif
- -#endif
- - || !ENGINE_set_ciphers(e, devcrypto_ciphers)
- -#ifdef IMPLEMENT_DIGEST
- - || !ENGINE_set_digests(e, devcrypto_digests)
- -#endif
- - ) {
- - ENGINE_free(e);
- - return;
- - }
- -
- - ENGINE_add(e);
- - ENGINE_free(e); /* Loose our local reference */
- - ERR_clear_error();
- -}
- --- /dev/null
- +++ b/engines/e_devcrypto.c
- @@ -0,0 +1,1315 @@
- +/*
- + * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
- + *
- + * Licensed under the OpenSSL license (the "License"). You may not use
- + * this file except in compliance with the License. You can obtain a copy
- + * in the file LICENSE in the source distribution or at
- + * https://www.openssl.org/source/license.html
- + */
- +
- +#include "../e_os.h"
- +#include <string.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <fcntl.h>
- +#include <sys/ioctl.h>
- +#include <unistd.h>
- +#include <assert.h>
- +
- +#include <openssl/conf.h>
- +#include <openssl/evp.h>
- +#include <openssl/err.h>
- +#include <openssl/engine.h>
- +#include <openssl/objects.h>
- +#include <crypto/cryptodev.h>
- +
- +/* #define ENGINE_DEVCRYPTO_DEBUG */
- +
- +#ifdef CRYPTO_ALGORITHM_MIN
- +# define CHECK_BSD_STYLE_MACROS
- +#endif
- +
- +#define engine_devcrypto_id "devcrypto"
- +
- +/*
- + * ONE global file descriptor for all sessions. This allows operations
- + * such as digest session data copying (see digest_copy()), but is also
- + * saner... why re-open /dev/crypto for every session?
- + */
- +static int cfd = -1;
- +#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
- +#define DEVCRYPTO_USE_SOFTWARE 1 /* allow software drivers */
- +#define DEVCRYPTO_REJECT_SOFTWARE 2 /* only disallow confirmed software drivers */
- +
- +#define DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS DEVCRYPTO_REJECT_SOFTWARE
- +static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS;
- +
- +/*
- + * cipher/digest status & acceleration definitions
- + * Make sure the defaults are set to 0
- + */
- +struct driver_info_st {
- + enum devcrypto_status_t {
- + DEVCRYPTO_STATUS_FAILURE = -3, /* unusable for other reason */
- + DEVCRYPTO_STATUS_NO_CIOCCPHASH = -2, /* hash state copy not supported */
- + DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */
- + DEVCRYPTO_STATUS_UNKNOWN = 0, /* not tested yet */
- + DEVCRYPTO_STATUS_USABLE = 1 /* algo can be used */
- + } status;
- +
- + enum devcrypto_accelerated_t {
- + DEVCRYPTO_NOT_ACCELERATED = -1, /* software implemented */
- + DEVCRYPTO_ACCELERATION_UNKNOWN = 0, /* acceleration support unkown */
- + DEVCRYPTO_ACCELERATED = 1 /* hardware accelerated */
- + } accelerated;
- +
- + char *driver_name;
- +};
- +
- +#ifdef OPENSSL_NO_DYNAMIC_ENGINE
- +void engine_load_devcrypto_int(void);
- +#endif
- +
- +static int clean_devcrypto_session(struct session_op *sess) {
- + if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- + memset(sess, 0, sizeof(struct session_op));
- + return 1;
- +}
- +
- +/******************************************************************************
- + *
- + * Ciphers
- + *
- + * Because they all do the same basic operation, we have only one set of
- + * method functions for them all to share, and a mapping table between
- + * NIDs and cryptodev IDs, with all the necessary size data.
- + *
- + *****/
- +
- +struct cipher_ctx {
- + struct session_op sess;
- + int op; /* COP_ENCRYPT or COP_DECRYPT */
- + unsigned long mode; /* EVP_CIPH_*_MODE */
- +
- + /* to handle ctr mode being a stream cipher */
- + unsigned char partial[EVP_MAX_BLOCK_LENGTH];
- + unsigned int blocksize, num;
- +};
- +
- +static const struct cipher_data_st {
- + int nid;
- + int blocksize;
- + int keylen;
- + int ivlen;
- + int flags;
- + int devcryptoid;
- +} cipher_data[] = {
- +#ifndef OPENSSL_NO_DES
- + { NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },
- + { NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },
- +#endif
- +#ifndef OPENSSL_NO_BF
- + { NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },
- +#endif
- +#ifndef OPENSSL_NO_CAST
- + { NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },
- +#endif
- + { NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- + { NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- + { NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },
- +#ifndef OPENSSL_NO_RC4
- + { NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)
- + { NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- + { NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- + { NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },
- +#endif
- +#if 0 /* Not yet supported */
- + { NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
- + { NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)
- + { NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- + { NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- + { NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },
- +#endif
- +#if 0 /* Not yet supported */
- + { NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- + { NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- + { NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },
- +#endif
- +#ifndef OPENSSL_NO_CAMELLIA
- + { NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,
- + CRYPTO_CAMELLIA_CBC },
- + { NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,
- + CRYPTO_CAMELLIA_CBC },
- + { NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,
- + CRYPTO_CAMELLIA_CBC },
- +#endif
- +};
- +
- +static size_t find_cipher_data_index(int nid)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(cipher_data); i++)
- + if (nid == cipher_data[i].nid)
- + return i;
- + return (size_t)-1;
- +}
- +
- +static size_t get_cipher_data_index(int nid)
- +{
- + size_t i = find_cipher_data_index(nid);
- +
- + if (i != (size_t)-1)
- + return i;
- +
- + /*
- + * Code further down must make sure that only NIDs in the table above
- + * are used. If any other NID reaches this function, there's a grave
- + * coding error further down.
- + */
- + assert("Code that never should be reached" == NULL);
- + return -1;
- +}
- +
- +static const struct cipher_data_st *get_cipher_data(int nid)
- +{
- + return &cipher_data[get_cipher_data_index(nid)];
- +}
- +
- +/*
- + * Following are the three necessary functions to map OpenSSL functionality
- + * with cryptodev.
- + */
- +
- +static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
- + const unsigned char *iv, int enc)
- +{
- + struct cipher_ctx *cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- + const struct cipher_data_st *cipher_d =
- + get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
- +
- + /* cleanup a previous session */
- + if (cipher_ctx->sess.ses != 0 &&
- + clean_devcrypto_session(&cipher_ctx->sess) == 0)
- + return 0;
- +
- + cipher_ctx->sess.cipher = cipher_d->devcryptoid;
- + cipher_ctx->sess.keylen = cipher_d->keylen;
- + cipher_ctx->sess.key = (void *)key;
- + cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;
- + cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;
- + cipher_ctx->blocksize = cipher_d->blocksize;
- + if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- +static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
- + const unsigned char *in, size_t inl)
- +{
- + struct cipher_ctx *cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- + struct crypt_op cryp;
- + unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);
- +#if !defined(COP_FLAG_WRITE_IV)
- + unsigned char saved_iv[EVP_MAX_IV_LENGTH];
- + const unsigned char *ivptr;
- + size_t nblocks, ivlen;
- +#endif
- +
- + memset(&cryp, 0, sizeof(cryp));
- + cryp.ses = cipher_ctx->sess.ses;
- + cryp.len = inl;
- + cryp.src = (void *)in;
- + cryp.dst = (void *)out;
- + cryp.iv = (void *)iv;
- + cryp.op = cipher_ctx->op;
- +#if !defined(COP_FLAG_WRITE_IV)
- + cryp.flags = 0;
- +
- + ivlen = EVP_CIPHER_CTX_iv_length(ctx);
- + if (ivlen > 0)
- + switch (cipher_ctx->mode) {
- + case EVP_CIPH_CBC_MODE:
- + assert(inl >= ivlen);
- + if (!EVP_CIPHER_CTX_encrypting(ctx)) {
- + ivptr = in + inl - ivlen;
- + memcpy(saved_iv, ivptr, ivlen);
- + }
- + break;
- +
- + case EVP_CIPH_CTR_MODE:
- + break;
- +
- + default: /* should not happen */
- + return 0;
- + }
- +#else
- + cryp.flags = COP_FLAG_WRITE_IV;
- +#endif
- +
- + if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- +
- +#if !defined(COP_FLAG_WRITE_IV)
- + if (ivlen > 0)
- + switch (cipher_ctx->mode) {
- + case EVP_CIPH_CBC_MODE:
- + assert(inl >= ivlen);
- + if (EVP_CIPHER_CTX_encrypting(ctx))
- + ivptr = out + inl - ivlen;
- + else
- + ivptr = saved_iv;
- +
- + memcpy(iv, ivptr, ivlen);
- + break;
- +
- + case EVP_CIPH_CTR_MODE:
- + nblocks = (inl + cipher_ctx->blocksize - 1)
- + / cipher_ctx->blocksize;
- + do {
- + ivlen--;
- + nblocks += iv[ivlen];
- + iv[ivlen] = (uint8_t) nblocks;
- + nblocks >>= 8;
- + } while (ivlen);
- + break;
- +
- + default: /* should not happen */
- + return 0;
- + }
- +#endif
- +
- + return 1;
- +}
- +
- +static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
- + const unsigned char *in, size_t inl)
- +{
- + struct cipher_ctx *cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- + size_t nblocks, len;
- +
- + /* initial partial block */
- + while (cipher_ctx->num && inl) {
- + (*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];
- + --inl;
- + cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;
- + }
- +
- + /* full blocks */
- + if (inl > (unsigned int) cipher_ctx->blocksize) {
- + nblocks = inl/cipher_ctx->blocksize;
- + len = nblocks * cipher_ctx->blocksize;
- + if (cipher_do_cipher(ctx, out, in, len) < 1)
- + return 0;
- + inl -= len;
- + out += len;
- + in += len;
- + }
- +
- + /* final partial block */
- + if (inl) {
- + memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);
- + if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,
- + cipher_ctx->blocksize) < 1)
- + return 0;
- + while (inl--) {
- + out[cipher_ctx->num] = in[cipher_ctx->num]
- + ^ cipher_ctx->partial[cipher_ctx->num];
- + cipher_ctx->num++;
- + }
- + }
- +
- + return 1;
- +}
- +
- +static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void* p2)
- +{
- + struct cipher_ctx *cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- + EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;
- + struct cipher_ctx *to_cipher_ctx;
- +
- + switch (type) {
- +
- + case EVP_CTRL_COPY:
- + if (cipher_ctx == NULL)
- + return 1;
- + /* when copying the context, a new session needs to be initialized */
- + to_cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);
- + memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));
- + return cipher_init(to_ctx, cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),
- + (cipher_ctx->op == COP_ENCRYPT));
- +
- + case EVP_CTRL_INIT:
- + memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));
- + return 1;
- +
- + default:
- + break;
- + }
- +
- + return -1;
- +}
- +
- +static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
- +{
- + struct cipher_ctx *cipher_ctx =
- + (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
- +
- + return clean_devcrypto_session(&cipher_ctx->sess);
- +}
- +
- +/*
- + * Keep tables of known nids, associated methods, selected ciphers, and driver
- + * info.
- + * Note that known_cipher_nids[] isn't necessarily indexed the same way as
- + * cipher_data[] above, which the other tables are.
- + */
- +static int known_cipher_nids[OSSL_NELEM(cipher_data)];
- +static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
- +static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
- +static int selected_ciphers[OSSL_NELEM(cipher_data)];
- +static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];
- +
- +
- +static int devcrypto_test_cipher(size_t cipher_data_index)
- +{
- + return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE
- + && selected_ciphers[cipher_data_index] == 1
- + && (cipher_driver_info[cipher_data_index].accelerated
- + == DEVCRYPTO_ACCELERATED
- + || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
- + || (cipher_driver_info[cipher_data_index].accelerated
- + != DEVCRYPTO_NOT_ACCELERATED
- + && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
- +}
- +
- +static void prepare_cipher_methods(void)
- +{
- + size_t i;
- + struct session_op sess;
- + unsigned long cipher_mode;
- +#ifdef CIOCGSESSINFO
- + struct session_info_op siop;
- +#endif
- +
- + memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));
- +
- + memset(&sess, 0, sizeof(sess));
- + sess.key = (void *)"01234567890123456789012345678901234567890123456789";
- +
- + for (i = 0, known_cipher_nids_amount = 0;
- + i < OSSL_NELEM(cipher_data); i++) {
- +
- + selected_ciphers[i] = 1;
- + /*
- + * Check that the cipher is usable
- + */
- + sess.cipher = cipher_data[i].devcryptoid;
- + sess.keylen = cipher_data[i].keylen;
- + if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
- + cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
- + continue;
- + }
- +
- + cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
- +
- + if ((known_cipher_methods[i] =
- + EVP_CIPHER_meth_new(cipher_data[i].nid,
- + cipher_mode == EVP_CIPH_CTR_MODE ? 1 :
- + cipher_data[i].blocksize,
- + cipher_data[i].keylen)) == NULL
- + || !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],
- + cipher_data[i].ivlen)
- + || !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],
- + cipher_data[i].flags
- + | EVP_CIPH_CUSTOM_COPY
- + | EVP_CIPH_CTRL_INIT
- + | EVP_CIPH_FLAG_DEFAULT_ASN1)
- + || !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)
- + || !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],
- + cipher_mode == EVP_CIPH_CTR_MODE ?
- + ctr_do_cipher :
- + cipher_do_cipher)
- + || !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)
- + || !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],
- + cipher_cleanup)
- + || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
- + sizeof(struct cipher_ctx))) {
- + cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- + EVP_CIPHER_meth_free(known_cipher_methods[i]);
- + known_cipher_methods[i] = NULL;
- + } else {
- + cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
- +#ifdef CIOCGSESSINFO
- + siop.ses = sess.ses;
- + if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
- + cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
- + } else {
- + cipher_driver_info[i].driver_name =
- + OPENSSL_strndup(siop.cipher_info.cra_driver_name,
- + CRYPTODEV_MAX_ALG_NAME);
- + if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
- + cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
- + else
- + cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
- + }
- +#endif /* CIOCGSESSINFO */
- + }
- + ioctl(cfd, CIOCFSESSION, &sess.ses);
- + if (devcrypto_test_cipher(i)) {
- + known_cipher_nids[known_cipher_nids_amount++] =
- + cipher_data[i].nid;
- + }
- + }
- +}
- +
- +static void rebuild_known_cipher_nids(ENGINE *e)
- +{
- + size_t i;
- +
- + for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {
- + if (devcrypto_test_cipher(i))
- + known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;
- + }
- + ENGINE_unregister_ciphers(e);
- + ENGINE_register_ciphers(e);
- +}
- +
- +static const EVP_CIPHER *get_cipher_method(int nid)
- +{
- + size_t i = get_cipher_data_index(nid);
- +
- + if (i == (size_t)-1)
- + return NULL;
- + return known_cipher_methods[i];
- +}
- +
- +static int get_cipher_nids(const int **nids)
- +{
- + *nids = known_cipher_nids;
- + return known_cipher_nids_amount;
- +}
- +
- +static void destroy_cipher_method(int nid)
- +{
- + size_t i = get_cipher_data_index(nid);
- +
- + EVP_CIPHER_meth_free(known_cipher_methods[i]);
- + known_cipher_methods[i] = NULL;
- +}
- +
- +static void destroy_all_cipher_methods(void)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
- + destroy_cipher_method(cipher_data[i].nid);
- + OPENSSL_free(cipher_driver_info[i].driver_name);
- + cipher_driver_info[i].driver_name = NULL;
- + }
- +}
- +
- +static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
- + const int **nids, int nid)
- +{
- + if (cipher == NULL)
- + return get_cipher_nids(nids);
- +
- + *cipher = get_cipher_method(nid);
- +
- + return *cipher != NULL;
- +}
- +
- +static void devcrypto_select_all_ciphers(int *cipher_list)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(cipher_data); i++)
- + cipher_list[i] = 1;
- +}
- +
- +static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
- +{
- + int *cipher_list = (int *)usr;
- + char *name;
- + const EVP_CIPHER *EVP;
- + size_t i;
- +
- + if (len == 0)
- + return 1;
- + if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
- + return 0;
- + EVP = EVP_get_cipherbyname(name);
- + if (EVP == NULL)
- + fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
- + else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
- + cipher_list[i] = 1;
- + else
- + fprintf(stderr, "devcrypto: cipher %s not available\n", name);
- + OPENSSL_free(name);
- + return 1;
- +}
- +
- +static void dump_cipher_info(void)
- +{
- + size_t i;
- + const char *name;
- +
- + fprintf (stderr, "Information about ciphers supported by the /dev/crypto"
- + " engine:\n");
- +#ifndef CIOCGSESSINFO
- + fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
- +#endif
- + for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
- + name = OBJ_nid2sn(cipher_data[i].nid);
- + fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
- + name ? name : "unknown", cipher_data[i].nid,
- + cipher_data[i].devcryptoid);
- + if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
- + fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
- + continue;
- + }
- + fprintf (stderr, "driver=%s ", cipher_driver_info[i].driver_name ?
- + cipher_driver_info[i].driver_name : "unknown");
- + if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
- + fprintf(stderr, "(hw accelerated)");
- + else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
- + fprintf(stderr, "(software)");
- + else
- + fprintf(stderr, "(acceleration status unknown)");
- + if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
- + fprintf (stderr, ". Cipher setup failed");
- + fprintf(stderr, "\n");
- + }
- + fprintf(stderr, "\n");
- +}
- +
- +/*
- + * We only support digests if the cryptodev implementation supports multiple
- + * data updates and session copying. Otherwise, we would be forced to maintain
- + * a cache, which is perilous if there's a lot of data coming in (if someone
- + * wants to checksum an OpenSSL tarball, for example).
- + */
- +#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)
- +#define IMPLEMENT_DIGEST
- +
- +/******************************************************************************
- + *
- + * Digests
- + *
- + * Because they all do the same basic operation, we have only one set of
- + * method functions for them all to share, and a mapping table between
- + * NIDs and cryptodev IDs, with all the necessary size data.
- + *
- + *****/
- +
- +struct digest_ctx {
- + struct session_op sess;
- + /* This signals that the init function was called, not that it succeeded. */
- + int init_called;
- + unsigned char digest_res[HASH_MAX_LEN];
- +};
- +
- +static const struct digest_data_st {
- + int nid;
- + int blocksize;
- + int digestlen;
- + int devcryptoid;
- +} digest_data[] = {
- +#ifndef OPENSSL_NO_MD5
- + { NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },
- +#endif
- + { NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },
- +#ifndef OPENSSL_NO_RMD160
- +# if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)
- + { NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },
- +# endif
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)
- + { NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)
- + { NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)
- + { NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },
- +#endif
- +#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)
- + { NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },
- +#endif
- +};
- +
- +static size_t find_digest_data_index(int nid)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(digest_data); i++)
- + if (nid == digest_data[i].nid)
- + return i;
- + return (size_t)-1;
- +}
- +
- +static size_t get_digest_data_index(int nid)
- +{
- + size_t i = find_digest_data_index(nid);
- +
- + if (i != (size_t)-1)
- + return i;
- +
- + /*
- + * Code further down must make sure that only NIDs in the table above
- + * are used. If any other NID reaches this function, there's a grave
- + * coding error further down.
- + */
- + assert("Code that never should be reached" == NULL);
- + return -1;
- +}
- +
- +static const struct digest_data_st *get_digest_data(int nid)
- +{
- + return &digest_data[get_digest_data_index(nid)];
- +}
- +
- +/*
- + * Following are the five necessary functions to map OpenSSL functionality
- + * with cryptodev: init, update, final, cleanup, and copy.
- + */
- +
- +static int digest_init(EVP_MD_CTX *ctx)
- +{
- + struct digest_ctx *digest_ctx =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- + const struct digest_data_st *digest_d =
- + get_digest_data(EVP_MD_CTX_type(ctx));
- +
- + digest_ctx->init_called = 1;
- +
- + memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));
- + digest_ctx->sess.mac = digest_d->devcryptoid;
- + if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- + return 1;
- +}
- +
- +static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,
- + void *res, unsigned int flags)
- +{
- + struct crypt_op cryp;
- +
- + memset(&cryp, 0, sizeof(cryp));
- + cryp.ses = ctx->sess.ses;
- + cryp.len = srclen;
- + cryp.src = (void *)src;
- + cryp.dst = NULL;
- + cryp.mac = res;
- + cryp.flags = flags;
- + return ioctl(cfd, CIOCCRYPT, &cryp);
- +}
- +
- +static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
- +{
- + struct digest_ctx *digest_ctx =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- +
- + if (count == 0)
- + return 1;
- +
- + if (digest_ctx == NULL)
- + return 0;
- +
- + if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
- + if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)
- + return 1;
- + } else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {
- + return 1;
- + }
- +
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- +}
- +
- +static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
- +{
- + struct digest_ctx *digest_ctx =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- +
- + if (md == NULL || digest_ctx == NULL)
- + return 0;
- +
- + if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
- + memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
- + } else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- +static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
- +{
- + struct digest_ctx *digest_from =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(from);
- + struct digest_ctx *digest_to =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(to);
- + struct cphash_op cphash;
- +
- + if (digest_from == NULL || digest_from->init_called != 1)
- + return 1;
- +
- + if (!digest_init(to)) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- +
- + cphash.src_ses = digest_from->sess.ses;
- + cphash.dst_ses = digest_to->sess.ses;
- + if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
- + SYSerr(SYS_F_IOCTL, errno);
- + return 0;
- + }
- + return 1;
- +}
- +
- +static int digest_cleanup(EVP_MD_CTX *ctx)
- +{
- + struct digest_ctx *digest_ctx =
- + (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
- +
- + if (digest_ctx == NULL)
- + return 1;
- +
- + return clean_devcrypto_session(&digest_ctx->sess);
- +}
- +
- +/*
- + * Keep tables of known nids, associated methods, selected digests, and
- + * driver info.
- + * Note that known_digest_nids[] isn't necessarily indexed the same way as
- + * digest_data[] above, which the other tables are.
- + */
- +static int known_digest_nids[OSSL_NELEM(digest_data)];
- +static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
- +static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
- +static int selected_digests[OSSL_NELEM(digest_data)];
- +static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];
- +
- +static int devcrypto_test_digest(size_t digest_data_index)
- +{
- + return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE
- + && selected_digests[digest_data_index] == 1
- + && (digest_driver_info[digest_data_index].accelerated
- + == DEVCRYPTO_ACCELERATED
- + || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
- + || (digest_driver_info[digest_data_index].accelerated
- + != DEVCRYPTO_NOT_ACCELERATED
- + && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
- +}
- +
- +static void rebuild_known_digest_nids(ENGINE *e)
- +{
- + size_t i;
- +
- + for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {
- + if (devcrypto_test_digest(i))
- + known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
- + }
- + ENGINE_unregister_digests(e);
- + ENGINE_register_digests(e);
- +}
- +
- +static void prepare_digest_methods(void)
- +{
- + size_t i;
- + struct session_op sess1, sess2;
- +#ifdef CIOCGSESSINFO
- + struct session_info_op siop;
- +#endif
- + struct cphash_op cphash;
- +
- + memset(&digest_driver_info, 0, sizeof(digest_driver_info));
- +
- + memset(&sess1, 0, sizeof(sess1));
- + memset(&sess2, 0, sizeof(sess2));
- +
- + for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
- + i++) {
- +
- + selected_digests[i] = 1;
- +
- + /*
- + * Check that the digest is usable
- + */
- + sess1.mac = digest_data[i].devcryptoid;
- + sess2.ses = 0;
- + if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
- + digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
- + goto finish;
- + }
- +
- +#ifdef CIOCGSESSINFO
- + /* gather hardware acceleration info from the driver */
- + siop.ses = sess1.ses;
- + if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
- + digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
- + } else {
- + digest_driver_info[i].driver_name =
- + OPENSSL_strndup(siop.hash_info.cra_driver_name,
- + CRYPTODEV_MAX_ALG_NAME);
- + if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
- + digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
- + else
- + digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
- + }
- +#endif
- +
- + /* digest must be capable of hash state copy */
- + sess2.mac = sess1.mac;
- + if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
- + digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- + goto finish;
- + }
- + cphash.src_ses = sess1.ses;
- + cphash.dst_ses = sess2.ses;
- + if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
- + digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;
- + goto finish;
- + }
- + if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
- + NID_undef)) == NULL
- + || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
- + digest_data[i].blocksize)
- + || !EVP_MD_meth_set_result_size(known_digest_methods[i],
- + digest_data[i].digestlen)
- + || !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)
- + || !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)
- + || !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)
- + || !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)
- + || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
- + || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
- + sizeof(struct digest_ctx))) {
- + digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
- + EVP_MD_meth_free(known_digest_methods[i]);
- + known_digest_methods[i] = NULL;
- + goto finish;
- + }
- + digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
- +finish:
- + ioctl(cfd, CIOCFSESSION, &sess1.ses);
- + if (sess2.ses != 0)
- + ioctl(cfd, CIOCFSESSION, &sess2.ses);
- + if (devcrypto_test_digest(i))
- + known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
- + }
- +}
- +
- +static const EVP_MD *get_digest_method(int nid)
- +{
- + size_t i = get_digest_data_index(nid);
- +
- + if (i == (size_t)-1)
- + return NULL;
- + return known_digest_methods[i];
- +}
- +
- +static int get_digest_nids(const int **nids)
- +{
- + *nids = known_digest_nids;
- + return known_digest_nids_amount;
- +}
- +
- +static void destroy_digest_method(int nid)
- +{
- + size_t i = get_digest_data_index(nid);
- +
- + EVP_MD_meth_free(known_digest_methods[i]);
- + known_digest_methods[i] = NULL;
- +}
- +
- +static void destroy_all_digest_methods(void)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(digest_data); i++) {
- + destroy_digest_method(digest_data[i].nid);
- + OPENSSL_free(digest_driver_info[i].driver_name);
- + digest_driver_info[i].driver_name = NULL;
- + }
- +}
- +
- +static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
- + const int **nids, int nid)
- +{
- + if (digest == NULL)
- + return get_digest_nids(nids);
- +
- + *digest = get_digest_method(nid);
- +
- + return *digest != NULL;
- +}
- +
- +static void devcrypto_select_all_digests(int *digest_list)
- +{
- + size_t i;
- +
- + for (i = 0; i < OSSL_NELEM(digest_data); i++)
- + digest_list[i] = 1;
- +}
- +
- +static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
- +{
- + int *digest_list = (int *)usr;
- + char *name;
- + const EVP_MD *EVP;
- + size_t i;
- +
- + if (len == 0)
- + return 1;
- + if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
- + return 0;
- + EVP = EVP_get_digestbyname(name);
- + if (EVP == NULL)
- + fprintf(stderr, "devcrypto: unknown digest %s\n", name);
- + else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
- + digest_list[i] = 1;
- + else
- + fprintf(stderr, "devcrypto: digest %s not available\n", name);
- + OPENSSL_free(name);
- + return 1;
- +}
- +
- +static void dump_digest_info(void)
- +{
- + size_t i;
- + const char *name;
- +
- + fprintf (stderr, "Information about digests supported by the /dev/crypto"
- + " engine:\n");
- +#ifndef CIOCGSESSINFO
- + fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
- +#endif
- +
- + for (i = 0; i < OSSL_NELEM(digest_data); i++) {
- + name = OBJ_nid2sn(digest_data[i].nid);
- + fprintf (stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",
- + name ? name : "unknown", digest_data[i].nid,
- + digest_data[i].devcryptoid,
- + digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");
- + if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
- + fprintf (stderr, ". CIOCGSESSION (session open) failed\n");
- + continue;
- + }
- + if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
- + fprintf(stderr, " (hw accelerated)");
- + else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
- + fprintf(stderr, " (software)");
- + else
- + fprintf(stderr, " (acceleration status unknown)");
- + if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
- + fprintf (stderr, ". Cipher setup failed\n");
- + else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)
- + fprintf(stderr, ", CIOCCPHASH failed\n");
- + else
- + fprintf(stderr, ", CIOCCPHASH capable\n");
- + }
- + fprintf(stderr, "\n");
- +}
- +
- +#endif
- +
- +/******************************************************************************
- + *
- + * CONTROL COMMANDS
- + *
- + *****/
- +
- +#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE
- +#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)
- +#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)
- +#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
- +
- +/* Helper macros for CPP string composition */
- +#ifndef OPENSSL_MSTR
- +# define OPENSSL_MSTR_HELPER(x) #x
- +# define OPENSSL_MSTR(x) OPENSSL_MSTR_HELPER(x)
- +#endif
- +
- +static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
- +#ifdef CIOCGSESSINFO
- + {DEVCRYPTO_CMD_USE_SOFTDRIVERS,
- + "USE_SOFTDRIVERS",
- + "specifies whether to use software (not accelerated) drivers ("
- + OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, "
- + OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
- + OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
- + "=use if acceleration can't be determined) [default="
- + OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS) "]",
- + ENGINE_CMD_FLAG_NUMERIC},
- +#endif
- +
- + {DEVCRYPTO_CMD_CIPHERS,
- + "CIPHERS",
- + "either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",
- + ENGINE_CMD_FLAG_STRING},
- +
- +#ifdef IMPLEMENT_DIGEST
- + {DEVCRYPTO_CMD_DIGESTS,
- + "DIGESTS",
- + "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
- + ENGINE_CMD_FLAG_STRING},
- +#endif
- +
- + {DEVCRYPTO_CMD_DUMP_INFO,
- + "DUMP_INFO",
- + "dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",
- + ENGINE_CMD_FLAG_NO_INPUT},
- +
- + {0, NULL, NULL, 0}
- +};
- +
- +static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
- +{
- + int *new_list;
- + switch (cmd) {
- +#ifdef CIOCGSESSINFO
- + case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
- + switch (i) {
- + case DEVCRYPTO_REQUIRE_ACCELERATED:
- + case DEVCRYPTO_USE_SOFTWARE:
- + case DEVCRYPTO_REJECT_SOFTWARE:
- + break;
- + default:
- + fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);
- + return 0;
- + }
- + if (use_softdrivers == i)
- + return 1;
- + use_softdrivers = i;
- +#ifdef IMPLEMENT_DIGEST
- + rebuild_known_digest_nids(e);
- +#endif
- + rebuild_known_cipher_nids(e);
- + return 1;
- +#endif /* CIOCGSESSINFO */
- +
- + case DEVCRYPTO_CMD_CIPHERS:
- + if (p == NULL)
- + return 1;
- + if (strcasecmp((const char *)p, "ALL") == 0) {
- + devcrypto_select_all_ciphers(selected_ciphers);
- + } else if (strcasecmp((const char*)p, "NONE") == 0) {
- + memset(selected_ciphers, 0, sizeof(selected_ciphers));
- + } else {
- + new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
- + if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {
- + OPENSSL_free(new_list);
- + return 0;
- + }
- + memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));
- + OPENSSL_free(new_list);
- + }
- + rebuild_known_cipher_nids(e);
- + return 1;
- +
- +#ifdef IMPLEMENT_DIGEST
- + case DEVCRYPTO_CMD_DIGESTS:
- + if (p == NULL)
- + return 1;
- + if (strcasecmp((const char *)p, "ALL") == 0) {
- + devcrypto_select_all_digests(selected_digests);
- + } else if (strcasecmp((const char*)p, "NONE") == 0) {
- + memset(selected_digests, 0, sizeof(selected_digests));
- + } else {
- + new_list=OPENSSL_zalloc(sizeof(selected_digests));
- + if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {
- + OPENSSL_free(new_list);
- + return 0;
- + }
- + memcpy(selected_digests, new_list, sizeof(selected_digests));
- + OPENSSL_free(new_list);
- + }
- + rebuild_known_digest_nids(e);
- + return 1;
- +#endif /* IMPLEMENT_DIGEST */
- +
- + case DEVCRYPTO_CMD_DUMP_INFO:
- + dump_cipher_info();
- +#ifdef IMPLEMENT_DIGEST
- + dump_digest_info();
- +#endif
- + return 1;
- +
- + default:
- + break;
- + }
- + return 0;
- +}
- +
- +/******************************************************************************
- + *
- + * LOAD / UNLOAD
- + *
- + *****/
- +
- +/*
- + * Opens /dev/crypto
- + */
- +static int open_devcrypto(void)
- +{
- + if (cfd >= 0)
- + return 1;
- +
- + if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
- +#ifndef ENGINE_DEVCRYPTO_DEBUG
- + if (errno != ENOENT)
- +#endif
- + fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
- + return 0;
- + }
- +
- + return 1;
- +}
- +
- +static int close_devcrypto(void)
- +{
- + int ret;
- +
- + if (cfd < 0)
- + return 1;
- + ret = close(cfd);
- + cfd = -1;
- + if (ret != 0) {
- + fprintf(stderr, "Error closing /dev/crypto: %s\n", strerror(errno));
- + return 0;
- + }
- + return 1;
- +}
- +
- +static int devcrypto_unload(ENGINE *e)
- +{
- + destroy_all_cipher_methods();
- +#ifdef IMPLEMENT_DIGEST
- + destroy_all_digest_methods();
- +#endif
- +
- + close_devcrypto();
- +
- + return 1;
- +}
- +
- +static int bind_devcrypto(ENGINE *e) {
- +
- + if (!ENGINE_set_id(e, engine_devcrypto_id)
- + || !ENGINE_set_name(e, "/dev/crypto engine")
- + || !ENGINE_set_destroy_function(e, devcrypto_unload)
- + || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
- + || !ENGINE_set_ctrl_function(e, devcrypto_ctrl))
- + return 0;
- +
- + prepare_cipher_methods();
- +#ifdef IMPLEMENT_DIGEST
- + prepare_digest_methods();
- +#endif
- +
- + return (ENGINE_set_ciphers(e, devcrypto_ciphers)
- +#ifdef IMPLEMENT_DIGEST
- + && ENGINE_set_digests(e, devcrypto_digests)
- +#endif
- +/*
- + * Asymmetric ciphers aren't well supported with /dev/crypto. Among the BSD
- + * implementations, it seems to only exist in FreeBSD, and regarding the
- + * parameters in its crypt_kop, the manual crypto(4) has this to say:
- + *
- + * The semantics of these arguments are currently undocumented.
- + *
- + * Reading through the FreeBSD source code doesn't give much more than
- + * their CRK_MOD_EXP implementation for ubsec.
- + *
- + * It doesn't look much better with cryptodev-linux. They have the crypt_kop
- + * structure as well as the command (CRK_*) in cryptodev.h, but no support
- + * seems to be implemented at all for the moment.
- + *
- + * At the time of writing, it seems impossible to write proper support for
- + * FreeBSD's asym features without some very deep knowledge and access to
- + * specific kernel modules.
- + *
- + * /Richard Levitte, 2017-05-11
- + */
- +#if 0
- +# ifndef OPENSSL_NO_RSA
- + && ENGINE_set_RSA(e, devcrypto_rsa)
- +# endif
- +# ifndef OPENSSL_NO_DSA
- + && ENGINE_set_DSA(e, devcrypto_dsa)
- +# endif
- +# ifndef OPENSSL_NO_DH
- + && ENGINE_set_DH(e, devcrypto_dh)
- +# endif
- +# ifndef OPENSSL_NO_EC
- + && ENGINE_set_EC(e, devcrypto_ec)
- +# endif
- +#endif
- + );
- +}
- +
- +#ifdef OPENSSL_NO_DYNAMIC_ENGINE
- +/*
- + * In case this engine is built into libcrypto, then it doesn't offer any
- + * ability to be dynamically loadable.
- + */
- +void engine_load_devcrypto_int(void)
- +{
- + ENGINE *e = NULL;
- +
- + if (!open_devcrypto())
- + return;
- +
- + if ((e = ENGINE_new()) == NULL
- + || !bind_devcrypto(e)) {
- + close_devcrypto();
- + ENGINE_free(e);
- + return;
- + }
- +
- + ENGINE_add(e);
- + ENGINE_free(e); /* Loose our local reference */
- + ERR_clear_error();
- +}
- +
- +#else
- +
- +static int bind_helper(ENGINE *e, const char *id)
- +{
- + if ((id && (strcmp(id, engine_devcrypto_id) != 0))
- + || !open_devcrypto())
- + return 0;
- + if (!bind_devcrypto(e)) {
- + close_devcrypto();
- + return 0;
- + }
- + return 1;
- +}
- +
- +IMPLEMENT_DYNAMIC_CHECK_FN()
- +IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
- +
- +#endif
|