1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213 |
- /* pubkey.c - pubkey dispatcher
- * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005,
- * 2007, 2008, 2011 Free Software Foundation, Inc.
- *
- * This file is part of Libgcrypt.
- *
- * Libgcrypt is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser general Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * Libgcrypt is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
- #include <config.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include "g10lib.h"
- #include "mpi.h"
- #include "cipher.h"
- #include "ath.h"
- static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result,
- gcry_mpi_t *data, gcry_mpi_t *skey,
- int flags);
- static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr,
- gcry_mpi_t hash, gcry_mpi_t *skey);
- static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash,
- gcry_mpi_t *data, gcry_mpi_t *pkey,
- int (*cmp) (void *, gcry_mpi_t),
- void *opaque);
- /* A dummy extraspec so that we do not need to tests the extraspec
- field from the module specification against NULL and instead
- directly test the respective fields of extraspecs. */
- static pk_extra_spec_t dummy_extra_spec;
- /* This is the list of the default public-key ciphers included in
- libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in
- FIPS mode. */
- static struct pubkey_table_entry
- {
- gcry_pk_spec_t *pubkey;
- pk_extra_spec_t *extraspec;
- unsigned int algorithm;
- int fips_allowed;
- } pubkey_table[] =
- {
- #if USE_RSA
- { &_gcry_pubkey_spec_rsa,
- &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1},
- #endif
- #if USE_ELGAMAL
- { &_gcry_pubkey_spec_elg,
- &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG },
- { &_gcry_pubkey_spec_elg,
- &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E },
- #endif
- #if USE_DSA
- { &_gcry_pubkey_spec_dsa,
- &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 },
- #endif
- #if USE_ECC
- { &_gcry_pubkey_spec_ecdsa,
- &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 },
- { &_gcry_pubkey_spec_ecdh,
- &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDH, 0 },
- #endif
- { NULL, 0 },
- };
- /* List of registered ciphers. */
- static gcry_module_t pubkeys_registered;
- /* This is the lock protecting PUBKEYS_REGISTERED. */
- static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;;
- /* Flag to check whether the default pubkeys have already been
- registered. */
- static int default_pubkeys_registered;
- /* Convenient macro for registering the default digests. */
- #define REGISTER_DEFAULT_PUBKEYS \
- do \
- { \
- ath_mutex_lock (&pubkeys_registered_lock); \
- if (! default_pubkeys_registered) \
- { \
- pk_register_default (); \
- default_pubkeys_registered = 1; \
- } \
- ath_mutex_unlock (&pubkeys_registered_lock); \
- } \
- while (0)
- /* These dummy functions are used in case a cipher implementation
- refuses to provide it's own functions. */
- static gcry_err_code_t
- dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy,
- gcry_mpi_t *skey, gcry_mpi_t **retfactors)
- {
- (void)algorithm;
- (void)nbits;
- (void)dummy;
- (void)skey;
- (void)retfactors;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static gcry_err_code_t
- dummy_check_secret_key (int algorithm, gcry_mpi_t *skey)
- {
- (void)algorithm;
- (void)skey;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static gcry_err_code_t
- dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
- gcry_mpi_t *pkey, int flags)
- {
- (void)algorithm;
- (void)resarr;
- (void)data;
- (void)pkey;
- (void)flags;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static gcry_err_code_t
- dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
- gcry_mpi_t *skey, int flags)
- {
- (void)algorithm;
- (void)result;
- (void)data;
- (void)skey;
- (void)flags;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static gcry_err_code_t
- dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
- gcry_mpi_t *skey)
- {
- (void)algorithm;
- (void)resarr;
- (void)data;
- (void)skey;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static gcry_err_code_t
- dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
- gcry_mpi_t *pkey,
- int (*cmp) (void *, gcry_mpi_t), void *opaquev)
- {
- (void)algorithm;
- (void)hash;
- (void)data;
- (void)pkey;
- (void)cmp;
- (void)opaquev;
- fips_signal_error ("using dummy public key function");
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- static unsigned
- dummy_get_nbits (int algorithm, gcry_mpi_t *pkey)
- {
- (void)algorithm;
- (void)pkey;
- fips_signal_error ("using dummy public key function");
- return 0;
- }
- /* Internal function. Register all the pubkeys included in
- PUBKEY_TABLE. Returns zero on success or an error code. */
- static void
- pk_register_default (void)
- {
- gcry_err_code_t err = 0;
- int i;
- for (i = 0; (! err) && pubkey_table[i].pubkey; i++)
- {
- #define pubkey_use_dummy(func) \
- if (! pubkey_table[i].pubkey->func) \
- pubkey_table[i].pubkey->func = dummy_##func;
- pubkey_use_dummy (generate);
- pubkey_use_dummy (check_secret_key);
- pubkey_use_dummy (encrypt);
- pubkey_use_dummy (decrypt);
- pubkey_use_dummy (sign);
- pubkey_use_dummy (verify);
- pubkey_use_dummy (get_nbits);
- #undef pubkey_use_dummy
- err = _gcry_module_add (&pubkeys_registered,
- pubkey_table[i].algorithm,
- (void *) pubkey_table[i].pubkey,
- (void *) pubkey_table[i].extraspec,
- NULL);
- }
- if (err)
- BUG ();
- }
- /* Internal callback function. Used via _gcry_module_lookup. */
- static int
- gcry_pk_lookup_func_name (void *spec, void *data)
- {
- gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec;
- char *name = (char *) data;
- const char **aliases = pubkey->aliases;
- int ret = stricmp (name, pubkey->name);
- while (ret && *aliases)
- ret = stricmp (name, *aliases++);
- return ! ret;
- }
- /* Internal function. Lookup a pubkey entry by it's name. */
- static gcry_module_t
- gcry_pk_lookup_name (const char *name)
- {
- gcry_module_t pubkey;
- pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name,
- gcry_pk_lookup_func_name);
- return pubkey;
- }
- /* Register a new pubkey module whose specification can be found in
- PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID
- and a pointer representhing this module is stored in MODULE. */
- gcry_error_t
- _gcry_pk_register (gcry_pk_spec_t *pubkey,
- pk_extra_spec_t *extraspec,
- unsigned int *algorithm_id,
- gcry_module_t *module)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- gcry_module_t mod;
- /* We do not support module loading in fips mode. */
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- ath_mutex_lock (&pubkeys_registered_lock);
- err = _gcry_module_add (&pubkeys_registered, 0,
- (void *) pubkey,
- (void *)(extraspec? extraspec : &dummy_extra_spec),
- &mod);
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (! err)
- {
- *module = mod;
- *algorithm_id = mod->mod_id;
- }
- return err;
- }
- /* Unregister the pubkey identified by ID, which must have been
- registered with gcry_pk_register. */
- void
- gcry_pk_unregister (gcry_module_t module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- static void
- release_mpi_array (gcry_mpi_t *array)
- {
- for (; *array; array++)
- {
- mpi_free(*array);
- *array = NULL;
- }
- }
- /****************
- * Map a string to the pubkey algo
- */
- int
- gcry_pk_map_name (const char *string)
- {
- gcry_module_t pubkey;
- int algorithm = 0;
- if (!string)
- return 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = gcry_pk_lookup_name (string);
- if (pubkey)
- {
- algorithm = pubkey->mod_id;
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return algorithm;
- }
- /* Map the public key algorithm whose ID is contained in ALGORITHM to
- a string representation of the algorithm name. For unknown
- algorithm IDs this functions returns "?". */
- const char *
- gcry_pk_algo_name (int algorithm)
- {
- gcry_module_t pubkey;
- const char *name;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- name = ((gcry_pk_spec_t *) pubkey->spec)->name;
- _gcry_module_release (pubkey);
- }
- else
- name = "?";
- ath_mutex_unlock (&pubkeys_registered_lock);
- return name;
- }
- /* A special version of gcry_pk_algo name to return the first aliased
- name of the algorithm. This is required to adhere to the spki
- specs where the algorithm names are lowercase. */
- const char *
- _gcry_pk_aliased_algo_name (int algorithm)
- {
- const char *name = NULL;
- gcry_module_t module;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec;
- name = pubkey->aliases? *pubkey->aliases : NULL;
- if (!name || !*name)
- name = pubkey->name;
- _gcry_module_release (module);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return name;
- }
- static void
- disable_pubkey_algo (int algorithm)
- {
- gcry_module_t pubkey;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- if (! (pubkey-> flags & FLAG_MODULE_DISABLED))
- pubkey->flags |= FLAG_MODULE_DISABLED;
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- /****************
- * A USE of 0 means: don't care.
- */
- static gcry_err_code_t
- check_pubkey_algo (int algorithm, unsigned use)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- gcry_pk_spec_t *pubkey;
- gcry_module_t module;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- if (((use & GCRY_PK_USAGE_SIGN)
- && (! (pubkey->use & GCRY_PK_USAGE_SIGN)))
- || ((use & GCRY_PK_USAGE_ENCR)
- && (! (pubkey->use & GCRY_PK_USAGE_ENCR))))
- err = GPG_ERR_WRONG_PUBKEY_ALGO;
- else if (module->flags & FLAG_MODULE_DISABLED)
- err = GPG_ERR_PUBKEY_ALGO;
- _gcry_module_release (module);
- }
- else
- err = GPG_ERR_PUBKEY_ALGO;
- ath_mutex_unlock (&pubkeys_registered_lock);
- return err;
- }
- /****************
- * Return the number of public key material numbers
- */
- static int
- pubkey_get_npkey (int algorithm)
- {
- gcry_module_t pubkey;
- int npkey = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey);
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return npkey;
- }
- /****************
- * Return the number of secret key material numbers
- */
- static int
- pubkey_get_nskey (int algorithm)
- {
- gcry_module_t pubkey;
- int nskey = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey);
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return nskey;
- }
- /****************
- * Return the number of signature material numbers
- */
- static int
- pubkey_get_nsig (int algorithm)
- {
- gcry_module_t pubkey;
- int nsig = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig);
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return nsig;
- }
- /****************
- * Return the number of encryption material numbers
- */
- static int
- pubkey_get_nenc (int algorithm)
- {
- gcry_module_t pubkey;
- int nenc = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc);
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return nenc;
- }
- /* Generate a new public key with algorithm ALGORITHM of size NBITS
- and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS
- is passed to the algorithm module if it features an extended
- generation function. RETFACTOR is used by some algorithms to
- return certain additional information which are in general not
- required.
- The function returns the error code number or 0 on success. */
- static gcry_err_code_t
- pubkey_generate (int algorithm,
- unsigned int nbits,
- unsigned long use_e,
- gcry_sexp_t genparms,
- gcry_mpi_t *skey, gcry_mpi_t **retfactors,
- gcry_sexp_t *r_extrainfo)
- {
- gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO;
- gcry_module_t pubkey;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- pk_extra_spec_t *extraspec = pubkey->extraspec;
- if (extraspec && extraspec->ext_generate)
- {
- /* Use the extended generate function. */
- ec = extraspec->ext_generate
- (algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo);
- }
- else
- {
- /* Use the standard generate function. */
- ec = ((gcry_pk_spec_t *) pubkey->spec)->generate
- (algorithm, nbits, use_e, skey, retfactors);
- }
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return ec;
- }
- static gcry_err_code_t
- pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey)
- {
- gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO;
- gcry_module_t pubkey;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key
- (algorithm, skey);
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- return err;
- }
- /****************
- * This is the interface to the public key encryption. Encrypt DATA
- * with PKEY and put it into RESARR which should be an array of MPIs
- * of size PUBKEY_MAX_NENC (or less if the algorithm allows this -
- * check with pubkey_get_nenc() )
- */
- static gcry_err_code_t
- pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
- gcry_mpi_t *pkey, int flags)
- {
- gcry_pk_spec_t *pubkey;
- gcry_module_t module;
- gcry_err_code_t rc;
- int i;
- /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as
- an extra failsafe protection we explicitly test for fips mode
- here. */
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("pubkey_encrypt: algo=%d\n", algorithm);
- for(i = 0; i < pubkey_get_npkey (algorithm); i++)
- log_mpidump (" pkey:", pkey[i]);
- log_mpidump (" data:", data);
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags);
- _gcry_module_release (module);
- goto ready;
- }
- rc = GPG_ERR_PUBKEY_ALGO;
- ready:
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!rc && DBG_CIPHER && !fips_mode ())
- {
- for(i = 0; i < pubkey_get_nenc (algorithm); i++)
- log_mpidump(" encr:", resarr[i] );
- }
- return rc;
- }
- /****************
- * This is the interface to the public key decryption.
- * ALGO gives the algorithm to use and this implicitly determines
- * the size of the arrays.
- * result is a pointer to a mpi variable which will receive a
- * newly allocated mpi or NULL in case of an error.
- */
- static gcry_err_code_t
- pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
- gcry_mpi_t *skey, int flags)
- {
- gcry_pk_spec_t *pubkey;
- gcry_module_t module;
- gcry_err_code_t rc;
- int i;
- *result = NULL; /* so the caller can always do a mpi_free */
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("pubkey_decrypt: algo=%d\n", algorithm);
- for(i = 0; i < pubkey_get_nskey (algorithm); i++)
- log_mpidump (" skey:", skey[i]);
- for(i = 0; i < pubkey_get_nenc (algorithm); i++)
- log_mpidump (" data:", data[i]);
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- rc = pubkey->decrypt (algorithm, result, data, skey, flags);
- _gcry_module_release (module);
- goto ready;
- }
- rc = GPG_ERR_PUBKEY_ALGO;
- ready:
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!rc && DBG_CIPHER && !fips_mode ())
- log_mpidump (" plain:", *result);
- return rc;
- }
- /****************
- * This is the interface to the public key signing.
- * Sign data with skey and put the result into resarr which
- * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
- * algorithm allows this - check with pubkey_get_nsig() )
- */
- static gcry_err_code_t
- pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
- gcry_mpi_t *skey)
- {
- gcry_pk_spec_t *pubkey;
- gcry_module_t module;
- gcry_err_code_t rc;
- int i;
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("pubkey_sign: algo=%d\n", algorithm);
- for(i = 0; i < pubkey_get_nskey (algorithm); i++)
- log_mpidump (" skey:", skey[i]);
- log_mpidump(" data:", data );
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- rc = pubkey->sign (algorithm, resarr, data, skey);
- _gcry_module_release (module);
- goto ready;
- }
- rc = GPG_ERR_PUBKEY_ALGO;
- ready:
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!rc && DBG_CIPHER && !fips_mode ())
- for (i = 0; i < pubkey_get_nsig (algorithm); i++)
- log_mpidump (" sig:", resarr[i]);
- return rc;
- }
- /****************
- * Verify a public key signature.
- * Return 0 if the signature is good
- */
- static gcry_err_code_t
- pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
- gcry_mpi_t *pkey,
- int (*cmp)(void *, gcry_mpi_t), void *opaquev)
- {
- gcry_pk_spec_t *pubkey;
- gcry_module_t module;
- gcry_err_code_t rc;
- int i;
- if (DBG_CIPHER && !fips_mode ())
- {
- log_debug ("pubkey_verify: algo=%d\n", algorithm);
- for (i = 0; i < pubkey_get_npkey (algorithm); i++)
- log_mpidump (" pkey", pkey[i]);
- for (i = 0; i < pubkey_get_nsig (algorithm); i++)
- log_mpidump (" sig", data[i]);
- log_mpidump (" hash", hash);
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (module)
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev);
- _gcry_module_release (module);
- goto ready;
- }
- rc = GPG_ERR_PUBKEY_ALGO;
- ready:
- ath_mutex_unlock (&pubkeys_registered_lock);
- return rc;
- }
- /* Turn VALUE into an octet string and store it in an allocated buffer
- at R_FRAME or - if R_RAME is NULL - copy it into the caller
- provided buffer SPACE; either SPACE or R_FRAME may be used. If
- SPACE if not NULL, the caller must provide a buffer of at least
- NBYTES. If the resulting octet string is shorter than NBYTES pad
- it to the left with zeroes. If VALUE does not fit into NBYTES
- return an error code. */
- static gpg_err_code_t
- octet_string_from_mpi (unsigned char **r_frame, void *space,
- gcry_mpi_t value, size_t nbytes)
- {
- gpg_err_code_t rc;
- size_t nframe, noff, n;
- unsigned char *frame;
- if (!r_frame == !space)
- return GPG_ERR_INV_ARG; /* Only one may be used. */
- if (r_frame)
- *r_frame = NULL;
- rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
- NULL, 0, &nframe, value));
- if (rc)
- return rc;
- if (nframe > nbytes)
- return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */
- noff = (nframe < nbytes)? nbytes - nframe : 0;
- n = nframe + noff;
- if (space)
- frame = space;
- else
- {
- frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n);
- if (!frame)
- {
- rc = gpg_err_code_from_syserror ();
- return rc;
- }
- }
- if (noff)
- memset (frame, 0, noff);
- nframe += noff;
- rc = gcry_err_code (gcry_mpi_print (GCRYMPI_FMT_USG,
- frame+noff, nframe-noff, NULL, value));
- if (rc)
- {
- gcry_free (frame);
- return rc;
- }
- if (r_frame)
- *r_frame = frame;
- return 0;
- }
- /* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
- type 2 padding. On sucess the result is stored as a new MPI at
- R_RESULT. On error the value at R_RESULT is undefined.
- If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
- the seed instead of using a random string for it. This feature is
- only useful for regression tests. Note that this value may not
- contain zero bytes.
- We encode the value in this way:
- 0 2 RND(n bytes) 0 VALUE
- 0 is a marker we unfortunately can't encode because we return an
- MPI which strips all leading zeroes.
- 2 is the block type.
- RND are non-zero random bytes.
- (Note that OpenPGP includes the cipher algorithm and a checksum in
- VALUE; the caller needs to prepare the value accordingly.)
- */
- static gcry_err_code_t
- pkcs1_encode_for_encryption (gcry_mpi_t *r_result, unsigned int nbits,
- const unsigned char *value, size_t valuelen,
- const unsigned char *random_override,
- size_t random_override_len)
- {
- gcry_err_code_t rc = 0;
- gcry_error_t err;
- unsigned char *frame = NULL;
- size_t nframe = (nbits+7) / 8;
- int i;
- size_t n;
- unsigned char *p;
- if (valuelen + 7 > nframe || !nframe)
- {
- /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
- return GPG_ERR_TOO_SHORT; /* The key is too short. */
- }
- if ( !(frame = gcry_malloc_secure (nframe)))
- return gpg_err_code_from_syserror ();
- n = 0;
- frame[n++] = 0;
- frame[n++] = 2; /* block type */
- i = nframe - 3 - valuelen;
- gcry_assert (i > 0);
- if (random_override)
- {
- int j;
- if (random_override_len != i)
- {
- gcry_free (frame);
- return GPG_ERR_INV_ARG;
- }
- /* Check that random does not include a zero byte. */
- for (j=0; j < random_override_len; j++)
- if (!random_override[j])
- {
- gcry_free (frame);
- return GPG_ERR_INV_ARG;
- }
- memcpy (frame + n, random_override, random_override_len);
- n += random_override_len;
- }
- else
- {
- p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
- /* Replace zero bytes by new values. */
- for (;;)
- {
- int j, k;
- unsigned char *pp;
- /* Count the zero bytes. */
- for (j=k=0; j < i; j++)
- {
- if (!p[j])
- k++;
- }
- if (!k)
- break; /* Okay: no (more) zero bytes. */
- k += k/128 + 3; /* Better get some more. */
- pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
- for (j=0; j < i && k; )
- {
- if (!p[j])
- p[j] = pp[--k];
- if (p[j])
- j++;
- }
- gcry_free (pp);
- }
- memcpy (frame+n, p, i);
- n += i;
- gcry_free (p);
- }
- frame[n++] = 0;
- memcpy (frame+n, value, valuelen);
- n += valuelen;
- gcry_assert (n == nframe);
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
- if (err)
- rc = gcry_err_code (err);
- else if (DBG_CIPHER)
- log_mpidump ("PKCS#1 block type 2 encoded data", *r_result);
- gcry_free (frame);
- return rc;
- }
- /* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
- NBITS is the size of the secret key. On success the result is
- stored as a newly allocated buffer at R_RESULT and its valid length at
- R_RESULTLEN. On error NULL is stored at R_RESULT. */
- static gcry_err_code_t
- pkcs1_decode_for_encryption (unsigned char **r_result, size_t *r_resultlen,
- unsigned int nbits, gcry_mpi_t value)
- {
- gcry_error_t err;
- unsigned char *frame = NULL;
- size_t nframe = (nbits+7) / 8;
- size_t n;
- *r_result = NULL;
- if ( !(frame = gcry_malloc_secure (nframe)))
- return gpg_err_code_from_syserror ();
- err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
- if (err)
- {
- gcry_free (frame);
- return gcry_err_code (err);
- }
- nframe = n; /* Set NFRAME to the actual length. */
- /* FRAME = 0x00 || 0x02 || PS || 0x00 || M
- pkcs#1 requires that the first byte is zero. Our MPIs usually
- strip leading zero bytes; thus we are not able to detect them.
- However due to the way gcry_mpi_print is implemented we may see
- leading zero bytes nevertheless. We handle this by making the
- first zero byte optional. */
- if (nframe < 4)
- {
- gcry_free (frame);
- return GPG_ERR_ENCODING_PROBLEM; /* Too short. */
- }
- n = 0;
- if (!frame[0])
- n++;
- if (frame[n++] != 0x02)
- {
- gcry_free (frame);
- return GPG_ERR_ENCODING_PROBLEM; /* Wrong block type. */
- }
- /* Skip the non-zero random bytes and the terminating zero byte. */
- for (; n < nframe && frame[n] != 0x00; n++)
- ;
- if (n+1 >= nframe)
- {
- gcry_free (frame);
- return GPG_ERR_ENCODING_PROBLEM; /* No zero byte. */
- }
- n++; /* Skip the zero byte. */
- /* To avoid an extra allocation we reuse the frame buffer. The only
- caller of this function will anyway free the result soon. */
- memmove (frame, frame + n, nframe - n);
- *r_result = frame;
- *r_resultlen = nframe - n;
- if (DBG_CIPHER)
- log_printhex ("value extracted from PKCS#1 block type 2 encoded data:",
- *r_result, *r_resultlen);
- return 0;
- }
- /* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
- using the pkcs#1 block type 1 padding. On success the result is
- stored as a new MPI at R_RESULT. On error the value at R_RESULT is
- undefined.
- We encode the value in this way:
- 0 1 PAD(n bytes) 0 ASN(asnlen bytes) VALUE(valuelen bytes)
- 0 is a marker we unfortunately can't encode because we return an
- MPI which strips all leading zeroes.
- 1 is the block type.
- PAD consists of 0xff bytes.
- 0 marks the end of the padding.
- ASN is the DER encoding of the hash algorithm; along with the VALUE
- it yields a valid DER encoding.
- (Note that PGP prior to version 2.3 encoded the message digest as:
- 0 1 MD(16 bytes) 0 PAD(n bytes) 1
- The MD is always 16 bytes here because it's always MD5. GnuPG
- does not not support pre-v2.3 signatures, but I'm including this
- comment so the information is easily found if needed.)
- */
- static gcry_err_code_t
- pkcs1_encode_for_signature (gcry_mpi_t *r_result, unsigned int nbits,
- const unsigned char *value, size_t valuelen,
- int algo)
- {
- gcry_err_code_t rc = 0;
- gcry_error_t err;
- byte asn[100];
- byte *frame = NULL;
- size_t nframe = (nbits+7) / 8;
- int i;
- size_t n;
- size_t asnlen, dlen;
- asnlen = DIM(asn);
- dlen = gcry_md_get_algo_dlen (algo);
- if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
- {
- /* We don't have yet all of the above algorithms. */
- return GPG_ERR_NOT_IMPLEMENTED;
- }
- if ( valuelen != dlen )
- {
- /* Hash value does not match the length of digest for
- the given algorithm. */
- return GPG_ERR_CONFLICT;
- }
- if ( !dlen || dlen + asnlen + 4 > nframe)
- {
- /* Can't encode an DLEN byte digest MD into an NFRAME byte
- frame. */
- return GPG_ERR_TOO_SHORT;
- }
- if ( !(frame = gcry_malloc (nframe)) )
- return gpg_err_code_from_syserror ();
- /* Assemble the pkcs#1 block type 1. */
- n = 0;
- frame[n++] = 0;
- frame[n++] = 1; /* block type */
- i = nframe - valuelen - asnlen - 3 ;
- gcry_assert (i > 1);
- memset (frame+n, 0xff, i );
- n += i;
- frame[n++] = 0;
- memcpy (frame+n, asn, asnlen);
- n += asnlen;
- memcpy (frame+n, value, valuelen );
- n += valuelen;
- gcry_assert (n == nframe);
- /* Convert it into an MPI. */
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
- if (err)
- rc = gcry_err_code (err);
- else if (DBG_CIPHER)
- log_mpidump ("PKCS#1 block type 1 encoded data", *r_result);
- gcry_free (frame);
- return rc;
- }
- /* Mask generation function for OAEP. See RFC-3447 B.2.1. */
- static gcry_err_code_t
- mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
- int algo)
- {
- size_t dlen, nbytes, n;
- int idx;
- gcry_md_hd_t hd;
- gcry_error_t err;
- err = gcry_md_open (&hd, algo, 0);
- if (err)
- return gpg_err_code (err);
- dlen = gcry_md_get_algo_dlen (algo);
- /* We skip step 1 which would be assert(OUTLEN <= 2^32). The loop
- in step 3 is merged with step 4 by concatenating no more octets
- than what would fit into OUTPUT. The ceiling for the counter IDX
- is implemented indirectly. */
- nbytes = 0; /* Step 2. */
- idx = 0;
- while ( nbytes < outlen )
- {
- unsigned char c[4], *digest;
- if (idx)
- gcry_md_reset (hd);
- c[0] = (idx >> 24) & 0xFF;
- c[1] = (idx >> 16) & 0xFF;
- c[2] = (idx >> 8) & 0xFF;
- c[3] = idx & 0xFF;
- idx++;
- gcry_md_write (hd, seed, seedlen);
- gcry_md_write (hd, c, 4);
- digest = gcry_md_read (hd, 0);
- n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen;
- memcpy (output+nbytes, digest, n);
- nbytes += n;
- }
- gcry_md_close (hd);
- return GPG_ERR_NO_ERROR;
- }
- /* RFC-3447 (pkcs#1 v2.1) OAEP encoding. NBITS is the length of the
- key measured in bits. ALGO is the hash function; it must be a
- valid and usable algorithm. {VALUE,VALUELEN} is the message to
- encrypt. {LABEL,LABELLEN} is the optional label to be associated
- with the message, if LABEL is NULL the default is to use the empty
- string as label. On success the encoded ciphertext is returned at
- R_RESULT.
- If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
- the seed instead of using a random string for it. This feature is
- only useful for regression tests.
- Here is figure 1 from the RFC depicting the process:
- +----------+---------+-------+
- DB = | lHash | PS | M |
- +----------+---------+-------+
- |
- +----------+ V
- | seed |--> MGF ---> xor
- +----------+ |
- | |
- +--+ V |
- |00| xor <----- MGF <-----|
- +--+ | |
- | | |
- V V V
- +--+----------+----------------------------+
- EM = |00|maskedSeed| maskedDB |
- +--+----------+----------------------------+
- */
- static gcry_err_code_t
- oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
- const unsigned char *value, size_t valuelen,
- const unsigned char *label, size_t labellen,
- const void *random_override, size_t random_override_len)
- {
- gcry_err_code_t rc = 0;
- gcry_error_t err;
- unsigned char *frame = NULL;
- size_t nframe = (nbits+7) / 8;
- unsigned char *p;
- size_t hlen;
- size_t n;
- *r_result = NULL;
- /* Set defaults for LABEL. */
- if (!label || !labellen)
- {
- label = (const unsigned char*)"";
- labellen = 0;
- }
- hlen = gcry_md_get_algo_dlen (algo);
- /* We skip step 1a which would be to check that LABELLEN is not
- greater than 2^61-1. See rfc-3447 7.1.1. */
- /* Step 1b. Note that the obsolete rfc-2437 uses the check:
- valuelen > nframe - 2 * hlen - 1 . */
- if (valuelen > nframe - 2 * hlen - 2 || !nframe)
- {
- /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
- return GPG_ERR_TOO_SHORT; /* The key is too short. */
- }
- /* Allocate the frame. */
- frame = gcry_calloc_secure (1, nframe);
- if (!frame)
- return gpg_err_code_from_syserror ();
- /* Step 2a: Compute the hash of the label. We store it in the frame
- where later the maskedDB will commence. */
- gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen);
- /* Step 2b: Set octet string to zero. */
- /* This has already been done while allocating FRAME. */
- /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M. */
- n = nframe - valuelen - 1;
- frame[n] = 0x01;
- memcpy (frame + n + 1, value, valuelen);
- /* Step 3d: Generate seed. We store it where the maskedSeed will go
- later. */
- if (random_override)
- {
- if (random_override_len != hlen)
- {
- gcry_free (frame);
- return GPG_ERR_INV_ARG;
- }
- memcpy (frame + 1, random_override, hlen);
- }
- else
- gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM);
- /* Step 2e and 2f: Create maskedDB. */
- {
- unsigned char *dmask;
- dmask = gcry_malloc_secure (nframe - hlen - 1);
- if (!dmask)
- {
- rc = gpg_err_code_from_syserror ();
- gcry_free (frame);
- return rc;
- }
- rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo);
- if (rc)
- {
- gcry_free (dmask);
- gcry_free (frame);
- return rc;
- }
- for (n = 1 + hlen, p = dmask; n < nframe; n++)
- frame[n] ^= *p++;
- gcry_free (dmask);
- }
- /* Step 2g and 2h: Create maskedSeed. */
- {
- unsigned char *smask;
- smask = gcry_malloc_secure (hlen);
- if (!smask)
- {
- rc = gpg_err_code_from_syserror ();
- gcry_free (frame);
- return rc;
- }
- rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo);
- if (rc)
- {
- gcry_free (smask);
- gcry_free (frame);
- return rc;
- }
- for (n = 1, p = smask; n < 1 + hlen; n++)
- frame[n] ^= *p++;
- gcry_free (smask);
- }
- /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB. */
- /* This has already been done by using in-place operations. */
- /* Convert the stuff into an MPI as expected by the caller. */
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
- if (err)
- rc = gcry_err_code (err);
- else if (DBG_CIPHER)
- log_mpidump ("OAEP encoded data", *r_result);
- gcry_free (frame);
- return rc;
- }
- /* RFC-3447 (pkcs#1 v2.1) OAEP decoding. NBITS is the length of the
- key measured in bits. ALGO is the hash function; it must be a
- valid and usable algorithm. VALUE is the raw decrypted message
- {LABEL,LABELLEN} is the optional label to be associated with the
- message, if LABEL is NULL the default is to use the empty string as
- label. On success the plaintext is returned as a newly allocated
- buffer at R_RESULT; its valid length is stored at R_RESULTLEN. On
- error NULL is stored at R_RESULT. */
- static gcry_err_code_t
- oaep_decode (unsigned char **r_result, size_t *r_resultlen,
- unsigned int nbits, int algo,
- gcry_mpi_t value, const unsigned char *label, size_t labellen)
- {
- gcry_err_code_t rc;
- unsigned char *frame = NULL; /* Encoded messages (EM). */
- unsigned char *masked_seed; /* Points into FRAME. */
- unsigned char *masked_db; /* Points into FRAME. */
- unsigned char *seed = NULL; /* Allocated space for the seed and DB. */
- unsigned char *db; /* Points into SEED. */
- unsigned char *lhash = NULL; /* Hash of the label. */
- size_t nframe; /* Length of the ciphertext (EM). */
- size_t hlen; /* Length of the hash digest. */
- size_t db_len; /* Length of DB and masked_db. */
- size_t nkey = (nbits+7)/8; /* Length of the key in bytes. */
- int failed = 0; /* Error indicator. */
- size_t n;
- *r_result = NULL;
- /* This code is implemented as described by rfc-3447 7.1.2. */
- /* Set defaults for LABEL. */
- if (!label || !labellen)
- {
- label = (const unsigned char*)"";
- labellen = 0;
- }
- /* Get the length of the digest. */
- hlen = gcry_md_get_algo_dlen (algo);
- /* Hash the label right away. */
- lhash = gcry_malloc (hlen);
- if (!lhash)
- return gpg_err_code_from_syserror ();
- gcry_md_hash_buffer (algo, lhash, label, labellen);
- /* Turn the MPI into an octet string. If the octet string is
- shorter than the key we pad it to the left with zeroes. This may
- happen due to the leading zero in OAEP frames and due to the
- following random octets (seed^mask) which may have leading zero
- bytes. This all is needed to cope with our leading zeroes
- suppressing MPI implementation. The code implictly implements
- Step 1b (bail out if NFRAME != N). */
- rc = octet_string_from_mpi (&frame, NULL, value, nkey);
- if (rc)
- {
- gcry_free (lhash);
- return GPG_ERR_ENCODING_PROBLEM;
- }
- nframe = nkey;
- /* Step 1c: Check that the key is long enough. */
- if ( nframe < 2 * hlen + 2 )
- {
- gcry_free (frame);
- gcry_free (lhash);
- return GPG_ERR_ENCODING_PROBLEM;
- }
- /* Step 2 has already been done by the caller and the
- gcry_mpi_aprint above. */
- /* Allocate space for SEED and DB. */
- seed = gcry_malloc_secure (nframe - 1);
- if (!seed)
- {
- rc = gpg_err_code_from_syserror ();
- gcry_free (frame);
- gcry_free (lhash);
- return rc;
- }
- db = seed + hlen;
- /* To avoid choosen ciphertext attacks from now on we make sure to
- run all code even in the error case; this avoids possible timing
- attacks as described by Manger. */
- /* Step 3a: Hash the label. */
- /* This has already been done. */
- /* Step 3b: Separate the encoded message. */
- masked_seed = frame + 1;
- masked_db = frame + 1 + hlen;
- db_len = nframe - 1 - hlen;
- /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen). */
- if (mgf1 (seed, hlen, masked_db, db_len, algo))
- failed = 1;
- for (n = 0; n < hlen; n++)
- seed[n] ^= masked_seed[n];
- /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len). */
- if (mgf1 (db, db_len, seed, hlen, algo))
- failed = 1;
- for (n = 0; n < db_len; n++)
- db[n] ^= masked_db[n];
- /* Step 3g: Check lhash, an possible empty padding string terminated
- by 0x01 and the first byte of EM being 0. */
- if (memcmp (lhash, db, hlen))
- failed = 1;
- for (n = hlen; n < db_len; n++)
- if (db[n] == 0x01)
- break;
- if (n == db_len)
- failed = 1;
- if (frame[0])
- failed = 1;
- gcry_free (lhash);
- gcry_free (frame);
- if (failed)
- {
- gcry_free (seed);
- return GPG_ERR_ENCODING_PROBLEM;
- }
- /* Step 4: Output M. */
- /* To avoid an extra allocation we reuse the seed buffer. The only
- caller of this function will anyway free the result soon. */
- n++;
- memmove (seed, db + n, db_len - n);
- *r_result = seed;
- *r_resultlen = db_len - n;
- seed = NULL;
- if (DBG_CIPHER)
- log_printhex ("value extracted from OAEP encoded data:",
- *r_result, *r_resultlen);
- return 0;
- }
- /* RFC-3447 (pkcs#1 v2.1) PSS encoding. Encode {VALUE,VALUELEN} for
- an NBITS key. Note that VALUE is already the mHash from the
- picture below. ALGO is a valid hash algorithm and SALTLEN is the
- length of salt to be used. On success the result is stored as a
- new MPI at R_RESULT. On error the value at R_RESULT is undefined.
- If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
- the salt instead of using a random string for the salt. This
- feature is only useful for regression tests.
- Here is figure 2 from the RFC (errata 595 applied) depicting the
- process:
- +-----------+
- | M |
- +-----------+
- |
- V
- Hash
- |
- V
- +--------+----------+----------+
- M' = |Padding1| mHash | salt |
- +--------+----------+----------+
- |
- +--------+----------+ V
- DB = |Padding2| salt | Hash
- +--------+----------+ |
- | |
- V | +----+
- xor <--- MGF <---| |0xbc|
- | | +----+
- | | |
- V V V
- +-------------------+----------+----+
- EM = | maskedDB | H |0xbc|
- +-------------------+----------+----+
- */
- static gcry_err_code_t
- pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
- const unsigned char *value, size_t valuelen, int saltlen,
- const void *random_override, size_t random_override_len)
- {
- gcry_err_code_t rc = 0;
- gcry_error_t err;
- size_t hlen; /* Length of the hash digest. */
- unsigned char *em = NULL; /* Encoded message. */
- size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */
- unsigned char *h; /* Points into EM. */
- unsigned char *buf = NULL; /* Help buffer. */
- size_t buflen; /* Length of BUF. */
- unsigned char *mhash; /* Points into BUF. */
- unsigned char *salt; /* Points into BUF. */
- unsigned char *dbmask; /* Points into BUF. */
- unsigned char *p;
- size_t n;
- /* This code is implemented as described by rfc-3447 9.1.1. */
- /* Get the length of the digest. */
- hlen = gcry_md_get_algo_dlen (algo);
- gcry_assert (hlen); /* We expect a valid ALGO here. */
- /* Allocate a help buffer and setup some pointers. */
- buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
- buf = gcry_malloc (buflen);
- if (!buf)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- mhash = buf + 8;
- salt = mhash + hlen;
- dbmask= salt + saltlen;
- /* Step 2: That would be: mHash = Hash(M) but our input is already
- mHash thus we do only a consistency check and copy to MHASH. */
- if (valuelen != hlen)
- {
- rc = GPG_ERR_INV_LENGTH;
- goto leave;
- }
- memcpy (mhash, value, hlen);
- /* Step 3: Check length constraints. */
- if (emlen < hlen + saltlen + 2)
- {
- rc = GPG_ERR_TOO_SHORT;
- goto leave;
- }
- /* Allocate space for EM. */
- em = gcry_malloc (emlen);
- if (!em)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- h = em + emlen - 1 - hlen;
- /* Step 4: Create a salt. */
- if (saltlen)
- {
- if (random_override)
- {
- if (random_override_len != saltlen)
- {
- rc = GPG_ERR_INV_ARG;
- goto leave;
- }
- memcpy (salt, random_override, saltlen);
- }
- else
- gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
- }
- /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt). */
- memset (buf, 0, 8); /* Padding. */
- gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
- /* Step 7 and 8: DB = PS || 0x01 || salt. */
- /* Note that we use EM to store DB and later Xor in-place. */
- p = em + emlen - 1 - hlen - saltlen - 1;
- memset (em, 0, p - em);
- *p++ = 0x01;
- memcpy (p, salt, saltlen);
- /* Step 9: dbmask = MGF(H, emlen - hlen - 1). */
- mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
- /* Step 10: maskedDB = DB ^ dbMask */
- for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
- em[n] ^= *p;
- /* Step 11: Set the leftmost bits to zero. */
- em[0] &= 0xFF >> (8 * emlen - nbits);
- /* Step 12: EM = maskedDB || H || 0xbc. */
- em[emlen-1] = 0xbc;
- /* Convert EM into an MPI. */
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL);
- if (err)
- rc = gcry_err_code (err);
- else if (DBG_CIPHER)
- log_mpidump ("PSS encoded data", *r_result);
- leave:
- if (em)
- {
- wipememory (em, emlen);
- gcry_free (em);
- }
- if (buf)
- {
- wipememory (buf, buflen);
- gcry_free (buf);
- }
- return rc;
- }
- /* Verify a signature assuming PSS padding. VALUE is the hash of the
- message (mHash) encoded as an MPI; its length must match the digest
- length of ALGO. ENCODED is the output of the RSA public key
- function (EM). NBITS is the size of the public key. ALGO is the
- hash algorithm and SALTLEN is the length of the used salt. The
- function returns 0 on success or on error code. */
- static gcry_err_code_t
- pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo,
- size_t saltlen)
- {
- gcry_err_code_t rc = 0;
- size_t hlen; /* Length of the hash digest. */
- unsigned char *em = NULL; /* Encoded message. */
- size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */
- unsigned char *salt; /* Points into EM. */
- unsigned char *h; /* Points into EM. */
- unsigned char *buf = NULL; /* Help buffer. */
- size_t buflen; /* Length of BUF. */
- unsigned char *dbmask; /* Points into BUF. */
- unsigned char *mhash; /* Points into BUF. */
- unsigned char *p;
- size_t n;
- /* This code is implemented as described by rfc-3447 9.1.2. */
- /* Get the length of the digest. */
- hlen = gcry_md_get_algo_dlen (algo);
- gcry_assert (hlen); /* We expect a valid ALGO here. */
- /* Allocate a help buffer and setup some pointers.
- This buffer is used for two purposes:
- +------------------------------+-------+
- 1. | dbmask | mHash |
- +------------------------------+-------+
- emlen - hlen - 1 hlen
- +----------+-------+---------+-+-------+
- 2. | padding1 | mHash | salt | | mHash |
- +----------+-------+---------+-+-------+
- 8 hlen saltlen hlen
- */
- buflen = 8 + hlen + saltlen;
- if (buflen < emlen - hlen - 1)
- buflen = emlen - hlen - 1;
- buflen += hlen;
- buf = gcry_malloc (buflen);
- if (!buf)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- dbmask = buf;
- mhash = buf + buflen - hlen;
- /* Step 2: That would be: mHash = Hash(M) but our input is already
- mHash thus we only need to convert VALUE into MHASH. */
- rc = octet_string_from_mpi (NULL, mhash, value, hlen);
- if (rc)
- goto leave;
- /* Convert the signature into an octet string. */
- rc = octet_string_from_mpi (&em, NULL, encoded, emlen);
- if (rc)
- goto leave;
- /* Step 3: Check length of EM. Because we internally use MPI
- functions we can't do this properly; EMLEN is always the length
- of the key because octet_string_from_mpi needs to left pad the
- result with zero to cope with the fact that our MPIs suppress all
- leading zeroes. Thus what we test here are merely the digest and
- salt lengths to the key. */
- if (emlen < hlen + saltlen + 2)
- {
- rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen. */
- goto leave;
- }
- /* Step 4: Check last octet. */
- if (em[emlen - 1] != 0xbc)
- {
- rc = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- /* Step 5: Split EM. */
- h = em + emlen - 1 - hlen;
- /* Step 6: Check the leftmost bits. */
- if ((em[0] & ~(0xFF >> (8 * emlen - nbits))))
- {
- rc = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- /* Step 7: dbmask = MGF(H, emlen - hlen - 1). */
- mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
- /* Step 8: maskedDB = DB ^ dbMask. */
- for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
- em[n] ^= *p;
- /* Step 9: Set leftmost bits in DB to zero. */
- em[0] &= 0xFF >> (8 * emlen - nbits);
- /* Step 10: Check the padding of DB. */
- for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++)
- ;
- if (n != emlen - hlen - saltlen - 2 || em[n++] != 1)
- {
- rc = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- /* Step 11: Extract salt from DB. */
- salt = em + n;
- /* Step 12: M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
- memset (buf, 0, 8);
- memcpy (buf+8, mhash, hlen);
- memcpy (buf+8+hlen, salt, saltlen);
- /* Step 13: H' = Hash(M'). */
- gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen);
- /* Step 14: Check H == H'. */
- rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
- leave:
- if (em)
- {
- wipememory (em, emlen);
- gcry_free (em);
- }
- if (buf)
- {
- wipememory (buf, buflen);
- gcry_free (buf);
- }
- return rc;
- }
- /* Callback for the pubkey algorithm code to verify PSS signatures.
- OPAQUE is the data provided by the actual caller. The meaning of
- TMP depends on the actual algorithm (but there is only RSA); now
- for RSA it is the output of running the public key function on the
- input. */
- static int
- pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
- {
- struct pk_encoding_ctx *ctx = opaque;
- gcry_mpi_t hash = ctx->verify_arg;
- return pss_verify (hash, tmp, ctx->nbits - 1, ctx->hash_algo, ctx->saltlen);
- }
- /* Internal function. */
- static gcry_err_code_t
- sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
- gcry_mpi_t *elements, const char *algo_name)
- {
- gcry_err_code_t err = 0;
- int i, idx;
- const char *name;
- gcry_sexp_t list;
- for (name = element_names, idx = 0; *name && !err; name++, idx++)
- {
- list = gcry_sexp_find_token (key_sexp, name, 1);
- if (!list)
- elements[idx] = NULL;
- else
- {
- elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (list);
- if (!elements[idx])
- err = GPG_ERR_INV_OBJ;
- }
- }
- if (!err)
- {
- /* Check that all elements are available. */
- for (name = element_names, idx = 0; *name; name++, idx++)
- if (!elements[idx])
- break;
- if (*name)
- {
- err = GPG_ERR_NO_OBJ;
- /* Some are missing. Before bailing out we test for
- optional parameters. */
- if (algo_name && !strcmp (algo_name, "RSA")
- && !strcmp (element_names, "nedpqu") )
- {
- /* This is RSA. Test whether we got N, E and D and that
- the optional P, Q and U are all missing. */
- if (elements[0] && elements[1] && elements[2]
- && !elements[3] && !elements[4] && !elements[5])
- err = 0;
- }
- }
- }
- if (err)
- {
- for (i = 0; i < idx; i++)
- if (elements[i])
- gcry_free (elements[i]);
- }
- return err;
- }
- /* Internal function used for ecc. Note, that this function makes use
- of its intimate knowledge about the ECC parameters from ecc.c. */
- static gcry_err_code_t
- sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
- gcry_mpi_t *elements, pk_extra_spec_t *extraspec)
- {
- gcry_err_code_t err = 0;
- int idx;
- const char *name;
- gcry_sexp_t list;
- /* Clear the array for easier error cleanup. */
- for (name = element_names, idx = 0; *name; name++, idx++)
- elements[idx] = NULL;
- gcry_assert (idx >= 5); /* We know that ECC has at least 5 elements
- (params only) or 6 (full public key). */
- if (idx == 5)
- elements[5] = NULL; /* Extra clear for the params only case. */
- /* Init the array with the available curve parameters. */
- for (name = element_names, idx = 0; *name && !err; name++, idx++)
- {
- list = gcry_sexp_find_token (key_sexp, name, 1);
- if (!list)
- elements[idx] = NULL;
- else
- {
- elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (list);
- if (!elements[idx])
- {
- err = GPG_ERR_INV_OBJ;
- goto leave;
- }
- }
- }
- /* Check whether a curve parameter has been given and then fill any
- missing elements. */
- list = gcry_sexp_find_token (key_sexp, "curve", 5);
- if (list)
- {
- if (extraspec->get_param)
- {
- char *curve;
- gcry_mpi_t params[6];
- for (idx = 0; idx < DIM(params); idx++)
- params[idx] = NULL;
- curve = _gcry_sexp_nth_string (list, 1);
- gcry_sexp_release (list);
- if (!curve)
- {
- /* No curve name given (or out of core). */
- err = GPG_ERR_INV_OBJ;
- goto leave;
- }
- err = extraspec->get_param (curve, params);
- gcry_free (curve);
- if (err)
- goto leave;
- for (idx = 0; idx < DIM(params); idx++)
- {
- if (!elements[idx])
- elements[idx] = params[idx];
- else
- mpi_free (params[idx]);
- }
- }
- else
- {
- gcry_sexp_release (list);
- err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */
- goto leave;
- }
- }
- /* Check that all parameters are known. */
- for (name = element_names, idx = 0; *name; name++, idx++)
- if (!elements[idx])
- {
- err = GPG_ERR_NO_OBJ;
- goto leave;
- }
- leave:
- if (err)
- {
- for (name = element_names, idx = 0; *name; name++, idx++)
- if (elements[idx])
- gcry_free (elements[idx]);
- }
- return err;
- }
- /****************
- * Convert a S-Exp with either a private or a public key to our
- * internal format. Currently we do only support the following
- * algorithms:
- * dsa
- * rsa
- * openpgp-dsa
- * openpgp-rsa
- * openpgp-elg
- * openpgp-elg-sig
- * ecdsa
- * ecdh
- * Provide a SE with the first element be either "private-key" or
- * or "public-key". It is followed by a list with its first element
- * be one of the above algorithm identifiers and the remaning
- * elements are pairs with parameter-id and value.
- * NOTE: we look through the list to find a list beginning with
- * "private-key" or "public-key" - the first one found is used.
- *
- * If OVERRIDE_ELEMS is not NULL those elems override the parameter
- * specification taken from the module. This ise used by
- * gcry_pk_get_curve.
- *
- * Returns: A pointer to an allocated array of MPIs if the return value is
- * zero; the caller has to release this array.
- *
- * Example of a DSA public key:
- * (private-key
- * (dsa
- * (p <mpi>)
- * (g <mpi>)
- * (y <mpi>)
- * (x <mpi>)
- * )
- * )
- * The <mpi> are expected to be in GCRYMPI_FMT_USG
- */
- static gcry_err_code_t
- sexp_to_key (gcry_sexp_t sexp, int want_private, const char *override_elems,
- gcry_mpi_t **retarray, gcry_module_t *retalgo)
- {
- gcry_err_code_t err = 0;
- gcry_sexp_t list, l2;
- char *name;
- const char *elems;
- gcry_mpi_t *array;
- gcry_module_t module;
- gcry_pk_spec_t *pubkey;
- pk_extra_spec_t *extraspec;
- int is_ecc;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token (sexp,
- want_private? "private-key":"public-key", 0);
- if (!list)
- return GPG_ERR_INV_OBJ; /* Does not contain a key object. */
- l2 = gcry_sexp_cadr( list );
- gcry_sexp_release ( list );
- list = l2;
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- {
- gcry_sexp_release ( list );
- return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name (name);
- ath_mutex_unlock (&pubkeys_registered_lock);
- /* Fixme: We should make sure that an ECC key is always named "ecc"
- and not "ecdsa". "ecdsa" should be used for the signature
- itself. We need a function to test whether an algorithm given
- with a key is compatible with an application of the key (signing,
- encryption). For RSA this is easy, but ECC is the first
- algorithm which has many flavours. */
- is_ecc = ( !strcmp (name, "ecdsa")
- || !strcmp (name, "ecdh")
- || !strcmp (name, "ecc") );
- gcry_free (name);
- if (!module)
- {
- gcry_sexp_release (list);
- return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- }
- else
- {
- pubkey = (gcry_pk_spec_t *) module->spec;
- extraspec = module->extraspec;
- }
- if (override_elems)
- elems = override_elems;
- else if (want_private)
- elems = pubkey->elements_skey;
- else
- elems = pubkey->elements_pkey;
- array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
- if (!array)
- err = gpg_err_code_from_syserror ();
- if (!err)
- {
- if (is_ecc)
- err = sexp_elements_extract_ecc (list, elems, array, extraspec);
- else
- err = sexp_elements_extract (list, elems, array, pubkey->name);
- }
- gcry_sexp_release (list);
- if (err)
- {
- gcry_free (array);
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- else
- {
- *retarray = array;
- *retalgo = module;
- }
- return err;
- }
- static gcry_err_code_t
- sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
- gcry_module_t *retalgo)
- {
- gcry_err_code_t err = 0;
- gcry_sexp_t list, l2;
- char *name;
- const char *elems;
- gcry_mpi_t *array;
- gcry_module_t module;
- gcry_pk_spec_t *pubkey;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
- if (!list)
- return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */
- l2 = gcry_sexp_nth (list, 1);
- if (!l2)
- {
- gcry_sexp_release (list);
- return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */
- }
- name = _gcry_sexp_nth_string (l2, 0);
- if (!name)
- {
- gcry_sexp_release (list);
- gcry_sexp_release (l2);
- return GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- }
- else if (!strcmp (name, "flags"))
- {
- /* Skip flags, since they are not used but here just for the
- sake of consistent S-expressions. */
- gcry_free (name);
- gcry_sexp_release (l2);
- l2 = gcry_sexp_nth (list, 2);
- if (!l2)
- {
- gcry_sexp_release (list);
- return GPG_ERR_INV_OBJ;
- }
- name = _gcry_sexp_nth_string (l2, 0);
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name (name);
- ath_mutex_unlock (&pubkeys_registered_lock);
- gcry_free (name);
- name = NULL;
- if (!module)
- {
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
- return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- }
- else
- pubkey = (gcry_pk_spec_t *) module->spec;
- elems = pubkey->elements_sig;
- array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
- if (!array)
- err = gpg_err_code_from_syserror ();
- if (!err)
- err = sexp_elements_extract (list, elems, array, NULL);
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
- if (err)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- gcry_free (array);
- }
- else
- {
- *retarray = array;
- *retalgo = module;
- }
- return err;
- }
- static inline int
- get_hash_algo (const char *s, size_t n)
- {
- static const struct { const char *name; int algo; } hashnames[] = {
- { "sha1", GCRY_MD_SHA1 },
- { "md5", GCRY_MD_MD5 },
- { "sha256", GCRY_MD_SHA256 },
- { "ripemd160", GCRY_MD_RMD160 },
- { "rmd160", GCRY_MD_RMD160 },
- { "sha384", GCRY_MD_SHA384 },
- { "sha512", GCRY_MD_SHA512 },
- { "sha224", GCRY_MD_SHA224 },
- { "md2", GCRY_MD_MD2 },
- { "md4", GCRY_MD_MD4 },
- { "tiger", GCRY_MD_TIGER },
- { "haval", GCRY_MD_HAVAL },
- { NULL, 0 }
- };
- int algo;
- int i;
- for (i=0; hashnames[i].name; i++)
- {
- if ( strlen (hashnames[i].name) == n
- && !memcmp (hashnames[i].name, s, n))
- break;
- }
- if (hashnames[i].name)
- algo = hashnames[i].algo;
- else
- {
- /* In case of not listed or dynamically allocated hash
- algorithm we fall back to this somewhat slower
- method. Further, it also allows to use OIDs as
- algorithm names. */
- char *tmpname;
- tmpname = gcry_malloc (n+1);
- if (!tmpname)
- algo = 0; /* Out of core - silently give up. */
- else
- {
- memcpy (tmpname, s, n);
- tmpname[n] = 0;
- algo = gcry_md_map_name (tmpname);
- gcry_free (tmpname);
- }
- }
- return algo;
- }
- /****************
- * Take sexp and return an array of MPI as used for our internal decrypt
- * function.
- * s_data = (enc-val
- * [(flags [raw, pkcs1, oaep, no-blinding])]
- * [(hash-algo <algo>)]
- * [(label <label>)]
- * (<algo>
- * (<param_name1> <mpi>)
- * ...
- * (<param_namen> <mpi>)
- * ))
- * HASH-ALGO and LABEL are specific to OAEP.
- * RET_MODERN is set to true when at least an empty flags list has been found.
- * CTX is used to return encoding information; it may be NULL in which
- * case raw encoding is used.
- */
- static gcry_err_code_t
- sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
- int *ret_modern, int *flags, struct pk_encoding_ctx *ctx)
- {
- gcry_err_code_t err = 0;
- gcry_sexp_t list = NULL, l2 = NULL;
- gcry_pk_spec_t *pubkey = NULL;
- gcry_module_t module = NULL;
- char *name = NULL;
- size_t n;
- int parsed_flags = 0;
- const char *elems;
- gcry_mpi_t *array = NULL;
- *ret_modern = 0;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token (sexp, "enc-val" , 0);
- if (!list)
- {
- err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */
- goto leave;
- }
- l2 = gcry_sexp_nth (list, 1);
- if (!l2)
- {
- err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
- goto leave;
- }
- /* Extract identifier of sublist. */
- name = _gcry_sexp_nth_string (l2, 0);
- if (!name)
- {
- err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- goto leave;
- }
- if (!strcmp (name, "flags"))
- {
- /* There is a flags element - process it. */
- const char *s;
- int i;
- *ret_modern = 1;
- for (i = gcry_sexp_length (l2) - 1; i > 0; i--)
- {
- s = gcry_sexp_nth_data (l2, i, &n);
- if (! s)
- ; /* Not a data element - ignore. */
- else if (n == 3 && !memcmp (s, "raw", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_RAW;
- else if (n == 5 && !memcmp (s, "pkcs1", 5)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_PKCS1;
- else if (n == 4 && !memcmp (s, "oaep", 4)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_OAEP;
- else if (n == 3 && !memcmp (s, "pss", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- {
- err = GPG_ERR_CONFLICT;
- goto leave;
- }
- else if (n == 11 && ! memcmp (s, "no-blinding", 11))
- parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
- else
- {
- err = GPG_ERR_INV_FLAG;
- goto leave;
- }
- }
- gcry_sexp_release (l2);
- /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
- if (ctx->encoding == PUBKEY_ENC_OAEP)
- {
- /* Get HASH-ALGO. */
- l2 = gcry_sexp_find_token (list, "hash-algo", 0);
- if (l2)
- {
- s = gcry_sexp_nth_data (l2, 1, &n);
- if (!s)
- err = GPG_ERR_NO_OBJ;
- else
- {
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- err = GPG_ERR_DIGEST_ALGO;
- }
- gcry_sexp_release (l2);
- if (err)
- goto leave;
- }
- /* Get LABEL. */
- l2 = gcry_sexp_find_token (list, "label", 0);
- if (l2)
- {
- s = gcry_sexp_nth_data (l2, 1, &n);
- if (!s)
- err = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- ctx->label = gcry_malloc (n);
- if (!ctx->label)
- err = gpg_err_code_from_syserror ();
- else
- {
- memcpy (ctx->label, s, n);
- ctx->labellen = n;
- }
- }
- gcry_sexp_release (l2);
- if (err)
- goto leave;
- }
- }
- /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
- for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++)
- {
- s = gcry_sexp_nth_data (l2, 0, &n);
- if (!(n == 9 && !memcmp (s, "hash-algo", 9))
- && !(n == 5 && !memcmp (s, "label", 5))
- && !(n == 15 && !memcmp (s, "random-override", 15)))
- break;
- gcry_sexp_release (l2);
- }
- if (!l2)
- {
- err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
- goto leave;
- }
- /* Extract sublist identifier. */
- gcry_free (name);
- name = _gcry_sexp_nth_string (l2, 0);
- if (!name)
- {
- err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
- goto leave;
- }
- gcry_sexp_release (list);
- list = l2;
- l2 = NULL;
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name (name);
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!module)
- {
- err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- goto leave;
- }
- pubkey = (gcry_pk_spec_t *) module->spec;
- elems = pubkey->elements_enc;
- array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
- if (!array)
- {
- err = gpg_err_code_from_syserror ();
- goto leave;
- }
- err = sexp_elements_extract (list, elems, array, NULL);
- leave:
- gcry_sexp_release (list);
- gcry_sexp_release (l2);
- gcry_free (name);
- if (err)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- gcry_free (array);
- gcry_free (ctx->label);
- ctx->label = NULL;
- }
- else
- {
- *retarray = array;
- *retalgo = module;
- *flags = parsed_flags;
- }
- return err;
- }
- /* Take the hash value and convert into an MPI, suitable for
- passing to the low level functions. We currently support the
- old style way of passing just a MPI and the modern interface which
- allows to pass flags so that we can choose between raw and pkcs1
- padding - may be more padding options later.
- (<mpi>)
- or
- (data
- [(flags [raw, pkcs1, oaep, pss, no-blinding])]
- [(hash <algo> <value>)]
- [(value <text>)]
- [(hash-algo <algo>)]
- [(label <label>)]
- [(salt-length <length>)]
- [(random-override <data>)]
- )
- Either the VALUE or the HASH element must be present for use
- with signatures. VALUE is used for encryption.
- HASH-ALGO and LABEL are specific to OAEP.
- SALT-LENGTH is for PSS.
- RANDOM-OVERRIDE is used to replace random nonces for regression
- testing. */
- static gcry_err_code_t
- sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
- struct pk_encoding_ctx *ctx)
- {
- gcry_err_code_t rc = 0;
- gcry_sexp_t ldata, lhash, lvalue;
- int i;
- size_t n;
- const char *s;
- int unknown_flag=0;
- int parsed_flags = 0;
- *ret_mpi = NULL;
- ldata = gcry_sexp_find_token (input, "data", 0);
- if (!ldata)
- { /* assume old style */
- *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0);
- return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ;
- }
- /* see whether there is a flags object */
- {
- gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0);
- if (lflags)
- { /* parse the flags list. */
- for (i=gcry_sexp_length (lflags)-1; i > 0; i--)
- {
- s = gcry_sexp_nth_data (lflags, i, &n);
- if (!s)
- ; /* not a data element*/
- else if ( n == 3 && !memcmp (s, "raw", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_RAW;
- else if ( n == 5 && !memcmp (s, "pkcs1", 5)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_PKCS1;
- else if ( n == 4 && !memcmp (s, "oaep", 4)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_OAEP;
- else if ( n == 3 && !memcmp (s, "pss", 3)
- && ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_PSS;
- else if (n == 11 && ! memcmp (s, "no-blinding", 11))
- parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
- else
- unknown_flag = 1;
- }
- gcry_sexp_release (lflags);
- }
- }
- if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
- ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
- /* Get HASH or MPI */
- lhash = gcry_sexp_find_token (ldata, "hash", 0);
- lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0);
- if (!(!lhash ^ !lvalue))
- rc = GPG_ERR_INV_OBJ; /* none or both given */
- else if (unknown_flag)
- rc = GPG_ERR_INV_FLAG;
- else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
- {
- *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
- if (!*ret_mpi)
- rc = GPG_ERR_INV_OBJ;
- }
- else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
- && ctx->op == PUBKEY_OP_ENCRYPT)
- {
- const void * value;
- size_t valuelen;
- gcry_sexp_t list;
- void *random_override = NULL;
- size_t random_override_len = 0;
- if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- rc = pkcs1_encode_for_encryption (ret_mpi, ctx->nbits,
- value, valuelen,
- random_override,
- random_override_len);
- gcry_free (random_override);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
- && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
- {
- if (gcry_sexp_length (lhash) != 3)
- rc = GPG_ERR_INV_OBJ;
- else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- const void * value;
- size_t valuelen;
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
- || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- rc = pkcs1_encode_for_signature (ret_mpi, ctx->nbits,
- value, valuelen,
- ctx->hash_algo);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
- && ctx->op == PUBKEY_OP_ENCRYPT)
- {
- const void * value;
- size_t valuelen;
- if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- gcry_sexp_t list;
- void *random_override = NULL;
- size_t random_override_len = 0;
- /* Get HASH-ALGO. */
- list = gcry_sexp_find_token (ldata, "hash-algo", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else
- {
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- /* Get LABEL. */
- list = gcry_sexp_find_token (ldata, "label", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- ctx->label = gcry_malloc (n);
- if (!ctx->label)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (ctx->label, s, n);
- ctx->labellen = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- rc = oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
- value, valuelen,
- ctx->label, ctx->labellen,
- random_override, random_override_len);
- gcry_free (random_override);
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
- && ctx->op == PUBKEY_OP_SIGN)
- {
- if (gcry_sexp_length (lhash) != 3)
- rc = GPG_ERR_INV_OBJ;
- else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- const void * value;
- size_t valuelen;
- void *random_override = NULL;
- size_t random_override_len = 0;
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen))
- || !valuelen )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- gcry_sexp_t list;
- /* Get SALT-LENGTH. */
- list = gcry_sexp_find_token (ldata, "salt-length", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- {
- rc = GPG_ERR_NO_OBJ;
- goto leave;
- }
- ctx->saltlen = (unsigned int)strtoul (s, NULL, 10);
- gcry_sexp_release (list);
- }
- /* Get optional RANDOM-OVERRIDE. */
- list = gcry_sexp_find_token (ldata, "random-override", 0);
- if (list)
- {
- s = gcry_sexp_nth_data (list, 1, &n);
- if (!s)
- rc = GPG_ERR_NO_OBJ;
- else if (n > 0)
- {
- random_override = gcry_malloc (n);
- if (!random_override)
- rc = gpg_err_code_from_syserror ();
- else
- {
- memcpy (random_override, s, n);
- random_override_len = n;
- }
- }
- gcry_sexp_release (list);
- if (rc)
- goto leave;
- }
- /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */
- rc = pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo,
- value, valuelen, ctx->saltlen,
- random_override, random_override_len);
- gcry_free (random_override);
- }
- }
- }
- else if (ctx->encoding == PUBKEY_ENC_PSS && lhash
- && ctx->op == PUBKEY_OP_VERIFY)
- {
- if (gcry_sexp_length (lhash) != 3)
- rc = GPG_ERR_INV_OBJ;
- else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
- rc = GPG_ERR_INV_OBJ;
- else
- {
- ctx->hash_algo = get_hash_algo (s, n);
- if (!ctx->hash_algo)
- rc = GPG_ERR_DIGEST_ALGO;
- else
- {
- *ret_mpi = gcry_sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG);
- if (!*ret_mpi)
- rc = GPG_ERR_INV_OBJ;
- ctx->verify_cmp = pss_verify_cmp;
- ctx->verify_arg = *ret_mpi;
- }
- }
- }
- else
- rc = GPG_ERR_CONFLICT;
- leave:
- gcry_sexp_release (ldata);
- gcry_sexp_release (lhash);
- gcry_sexp_release (lvalue);
- if (!rc)
- ctx->flags = parsed_flags;
- else
- {
- gcry_free (ctx->label);
- ctx->label = NULL;
- }
- return rc;
- }
- static void
- init_encoding_ctx (struct pk_encoding_ctx *ctx, enum pk_operation op,
- unsigned int nbits)
- {
- ctx->op = op;
- ctx->nbits = nbits;
- ctx->encoding = PUBKEY_ENC_UNKNOWN;
- ctx->flags = 0;
- ctx->hash_algo = GCRY_MD_SHA1;
- ctx->label = NULL;
- ctx->labellen = 0;
- ctx->saltlen = 20;
- ctx->verify_cmp = NULL;
- ctx->verify_arg = NULL;
- }
- /*
- Do a PK encrypt operation
- Caller has to provide a public key as the SEXP pkey and data as a
- SEXP with just one MPI in it. Alternatively S_DATA might be a
- complex S-Expression, similar to the one used for signature
- verification. This provides a flag which allows to handle PKCS#1
- block type 2 padding. The function returns a sexp which may be
- passed to to pk_decrypt.
- Returns: 0 or an errorcode.
- s_data = See comment for sexp_data_to_mpi
- s_pkey = <key-as-defined-in-sexp_to_key>
- r_ciph = (enc-val
- (<algo>
- (<param_name1> <mpi>)
- ...
- (<param_namen> <mpi>)
- ))
- */
- gcry_error_t
- gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
- {
- gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL;
- const char *algo_name, *algo_elems;
- struct pk_encoding_ctx ctx;
- gcry_err_code_t rc;
- gcry_pk_spec_t *pubkey = NULL;
- gcry_module_t module = NULL;
- *r_ciph = NULL;
- REGISTER_DEFAULT_PUBKEYS;
- /* Get the key. */
- rc = sexp_to_key (s_pkey, 0, NULL, &pkey, &module);
- if (rc)
- goto leave;
- gcry_assert (module);
- pubkey = (gcry_pk_spec_t *) module->spec;
- /* If aliases for the algorithm name exists, take the first one
- instead of the regular name to adhere to SPKI conventions. We
- assume that the first alias name is the lowercase version of the
- regular one. This change is required for compatibility with
- 1.1.12 generated S-expressions. */
- algo_name = pubkey->aliases? *pubkey->aliases : NULL;
- if (!algo_name || !*algo_name)
- algo_name = pubkey->name;
- algo_elems = pubkey->elements_enc;
- /* Get the stuff we want to encrypt. */
- init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
- rc = sexp_data_to_mpi (s_data, &data, &ctx);
- if (rc)
- goto leave;
- /* Now we can encrypt DATA to CIPH. */
- ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph));
- if (!ciph)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, ctx.flags);
- mpi_free (data);
- data = NULL;
- if (rc)
- goto leave;
- /* We did it. Now build the return list */
- if (ctx.encoding == PUBKEY_ENC_OAEP
- || ctx.encoding == PUBKEY_ENC_PKCS1)
- {
- /* We need to make sure to return the correct length to avoid
- problems with missing leading zeroes. We know that this
- encoding does only make sense with RSA thus we don't need to
- build the S-expression on the fly. */
- unsigned char *em;
- size_t emlen = (ctx.nbits+7)/8;
- rc = octet_string_from_mpi (&em, NULL, ciph[0], emlen);
- if (rc)
- goto leave;
- rc = gcry_err_code (gcry_sexp_build (r_ciph, NULL,
- "(enc-val(%s(a%b)))",
- algo_name, (int)emlen, em));
- gcry_free (em);
- if (rc)
- goto leave;
- }
- else
- {
- char *string, *p;
- int i;
- size_t nelem = strlen (algo_elems);
- size_t needed = 19 + strlen (algo_name) + (nelem * 5);
- void **arg_list;
- /* Build the string. */
- string = p = gcry_malloc (needed);
- if (!string)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- p = stpcpy ( p, "(enc-val(" );
- p = stpcpy ( p, algo_name );
- for (i=0; algo_elems[i]; i++ )
- {
- *p++ = '(';
- *p++ = algo_elems[i];
- p = stpcpy ( p, "%m)" );
- }
- strcpy ( p, "))" );
- /* And now the ugly part: We don't have a function to pass an
- * array to a format string, so we have to do it this way :-(. */
- /* FIXME: There is now such a format specifier, so we can
- change the code to be more clear. */
- arg_list = calloc (nelem, sizeof *arg_list);
- if (!arg_list)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- for (i = 0; i < nelem; i++)
- arg_list[i] = ciph + i;
- rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list);
- free (arg_list);
- if (rc)
- BUG ();
- gcry_free (string);
- }
- leave:
- if (pkey)
- {
- release_mpi_array (pkey);
- gcry_free (pkey);
- }
- if (ciph)
- {
- release_mpi_array (ciph);
- gcry_free (ciph);
- }
- if (module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- gcry_free (ctx.label);
- return gcry_error (rc);
- }
- /*
- Do a PK decrypt operation
- Caller has to provide a secret key as the SEXP skey and data in a
- format as created by gcry_pk_encrypt. For historic reasons the
- function returns simply an MPI as an S-expression part; this is
- deprecated and the new method should be used which returns a real
- S-expressionl this is selected by adding at least an empty flags
- list to S_DATA.
- Returns: 0 or an errorcode.
- s_data = (enc-val
- [(flags [raw, pkcs1, oaep])]
- (<algo>
- (<param_name1> <mpi>)
- ...
- (<param_namen> <mpi>)
- ))
- s_skey = <key-as-defined-in-sexp_to_key>
- r_plain= Either an incomplete S-expression without the parentheses
- or if the flags list is used (even if empty) a real S-expression:
- (value PLAIN). In raw mode (or no flags given) the returned value
- is to be interpreted as a signed MPI, thus it may have an extra
- leading zero octet even if not included in the original data.
- With pkcs1 or oaep decoding enabled the returned value is a
- verbatim octet string.
- */
- gcry_error_t
- gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
- {
- gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL;
- unsigned char *unpad = NULL;
- size_t unpadlen = 0;
- int modern, flags;
- struct pk_encoding_ctx ctx;
- gcry_err_code_t rc;
- gcry_module_t module_enc = NULL, module_key = NULL;
- *r_plain = NULL;
- ctx.label = NULL;
- REGISTER_DEFAULT_PUBKEYS;
- rc = sexp_to_key (s_skey, 1, NULL, &skey, &module_key);
- if (rc)
- goto leave;
- init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
- rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &flags, &ctx);
- if (rc)
- goto leave;
- if (module_key->mod_id != module_enc->mod_id)
- {
- rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */
- goto leave;
- }
- rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags);
- if (rc)
- goto leave;
- /* Do un-padding if necessary. */
- switch (ctx.encoding)
- {
- case PUBKEY_ENC_PKCS1:
- rc = pkcs1_decode_for_encryption (&unpad, &unpadlen,
- gcry_pk_get_nbits (s_skey), plain);
- mpi_free (plain);
- plain = NULL;
- if (!rc)
- rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
- (int)unpadlen, unpad));
- break;
- case PUBKEY_ENC_OAEP:
- rc = oaep_decode (&unpad, &unpadlen,
- gcry_pk_get_nbits (s_skey), ctx.hash_algo,
- plain, ctx.label, ctx.labellen);
- mpi_free (plain);
- plain = NULL;
- if (!rc)
- rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
- (int)unpadlen, unpad));
- break;
- default:
- /* Raw format. For backward compatibility we need to assume a
- signed mpi by using the sexp format string "%m". */
- rc = gcry_err_code (gcry_sexp_build
- (r_plain, NULL, modern? "(value %m)" : "%m", plain));
- break;
- }
- leave:
- gcry_free (unpad);
- if (skey)
- {
- release_mpi_array (skey);
- gcry_free (skey);
- }
- mpi_free (plain);
- if (data)
- {
- release_mpi_array (data);
- gcry_free (data);
- }
- if (module_key || module_enc)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- if (module_key)
- _gcry_module_release (module_key);
- if (module_enc)
- _gcry_module_release (module_enc);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- gcry_free (ctx.label);
- return gcry_error (rc);
- }
- /*
- Create a signature.
- Caller has to provide a secret key as the SEXP skey and data
- expressed as a SEXP list hash with only one element which should
- instantly be available as a MPI. Alternatively the structure given
- below may be used for S_HASH, it provides the abiliy to pass flags
- to the operation; the flags defined by now are "pkcs1" which does
- PKCS#1 block type 1 style padding and "pss" for PSS encoding.
- Returns: 0 or an errorcode.
- In case of 0 the function returns a new SEXP with the
- signature value; the structure of this signature depends on the
- other arguments but is always suitable to be passed to
- gcry_pk_verify
- s_hash = See comment for sexp_data_to_mpi
- s_skey = <key-as-defined-in-sexp_to_key>
- r_sig = (sig-val
- (<algo>
- (<param_name1> <mpi>)
- ...
- (<param_namen> <mpi>))
- [(hash algo)])
- Note that (hash algo) in R_SIG is not used.
- */
- gcry_error_t
- gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
- {
- gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL;
- gcry_pk_spec_t *pubkey = NULL;
- gcry_module_t module = NULL;
- const char *algo_name, *algo_elems;
- struct pk_encoding_ctx ctx;
- int i;
- gcry_err_code_t rc;
- *r_sig = NULL;
- REGISTER_DEFAULT_PUBKEYS;
- rc = sexp_to_key (s_skey, 1, NULL, &skey, &module);
- if (rc)
- goto leave;
- gcry_assert (module);
- pubkey = (gcry_pk_spec_t *) module->spec;
- algo_name = pubkey->aliases? *pubkey->aliases : NULL;
- if (!algo_name || !*algo_name)
- algo_name = pubkey->name;
- algo_elems = pubkey->elements_sig;
- /* Get the stuff we want to sign. Note that pk_get_nbits does also
- work on a private key. */
- init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, gcry_pk_get_nbits (s_skey));
- rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
- if (rc)
- goto leave;
- result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
- if (!result)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- rc = pubkey_sign (module->mod_id, result, hash, skey);
- if (rc)
- goto leave;
- if (ctx.encoding == PUBKEY_ENC_PSS
- || ctx.encoding == PUBKEY_ENC_PKCS1)
- {
- /* We need to make sure to return the correct length to avoid
- problems with missing leading zeroes. We know that this
- encoding does only make sense with RSA thus we don't need to
- build the S-expression on the fly. */
- unsigned char *em;
- size_t emlen = (ctx.nbits+7)/8;
- rc = octet_string_from_mpi (&em, NULL, result[0], emlen);
- if (rc)
- goto leave;
- rc = gcry_err_code (gcry_sexp_build (r_sig, NULL,
- "(sig-val(%s(s%b)))",
- algo_name, (int)emlen, em));
- gcry_free (em);
- if (rc)
- goto leave;
- }
- else
- {
- /* General purpose output encoding. Do it on the fly. */
- char *string, *p;
- size_t nelem, needed = strlen (algo_name) + 20;
- void **arg_list;
- nelem = strlen (algo_elems);
- /* Count elements, so that we can allocate enough space. */
- needed += 10 * nelem;
- /* Build the string. */
- string = p = gcry_malloc (needed);
- if (!string)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- p = stpcpy (p, "(sig-val(");
- p = stpcpy (p, algo_name);
- for (i = 0; algo_elems[i]; i++)
- {
- *p++ = '(';
- *p++ = algo_elems[i];
- p = stpcpy (p, "%M)");
- }
- strcpy (p, "))");
- arg_list = calloc (nelem, sizeof *arg_list);
- if (!arg_list)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- for (i = 0; i < nelem; i++)
- arg_list[i] = result + i;
- rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list);
- free (arg_list);
- if (rc)
- BUG ();
- gcry_free (string);
- }
- leave:
- if (skey)
- {
- release_mpi_array (skey);
- gcry_free (skey);
- }
- if (hash)
- mpi_free (hash);
- if (result)
- {
- release_mpi_array (result);
- gcry_free (result);
- }
- return gcry_error (rc);
- }
- /*
- Verify a signature.
- Caller has to supply the public key pkey, the signature sig and his
- hashvalue data. Public key has to be a standard public key given
- as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data
- must be an S-Exp like the one in sign too. */
- gcry_error_t
- gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
- {
- gcry_module_t module_key = NULL, module_sig = NULL;
- gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL;
- struct pk_encoding_ctx ctx;
- gcry_err_code_t rc;
- REGISTER_DEFAULT_PUBKEYS;
- rc = sexp_to_key (s_pkey, 0, NULL, &pkey, &module_key);
- if (rc)
- goto leave;
- rc = sexp_to_sig (s_sig, &sig, &module_sig);
- if (rc)
- goto leave;
- /* Fixme: Check that the algorithm of S_SIG is compatible to the one
- of S_PKEY. */
- if (module_key->mod_id != module_sig->mod_id)
- {
- rc = GPG_ERR_CONFLICT;
- goto leave;
- }
- /* Get the stuff we want to verify. */
- init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, gcry_pk_get_nbits (s_pkey));
- rc = sexp_data_to_mpi (s_hash, &hash, &ctx);
- if (rc)
- goto leave;
- rc = pubkey_verify (module_key->mod_id, hash, sig, pkey,
- ctx.verify_cmp, &ctx);
- leave:
- if (pkey)
- {
- release_mpi_array (pkey);
- gcry_free (pkey);
- }
- if (sig)
- {
- release_mpi_array (sig);
- gcry_free (sig);
- }
- if (hash)
- mpi_free (hash);
- if (module_key || module_sig)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- if (module_key)
- _gcry_module_release (module_key);
- if (module_sig)
- _gcry_module_release (module_sig);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- return gcry_error (rc);
- }
- /*
- Test a key.
- This may be used either for a public or a secret key to see whether
- the internal structure is okay.
- Returns: 0 or an errorcode.
- s_key = <key-as-defined-in-sexp_to_key> */
- gcry_error_t
- gcry_pk_testkey (gcry_sexp_t s_key)
- {
- gcry_module_t module = NULL;
- gcry_mpi_t *key = NULL;
- gcry_err_code_t rc;
- REGISTER_DEFAULT_PUBKEYS;
- /* Note we currently support only secret key checking. */
- rc = sexp_to_key (s_key, 1, NULL, &key, &module);
- if (! rc)
- {
- rc = pubkey_check_secret_key (module->mod_id, key);
- release_mpi_array (key);
- gcry_free (key);
- }
- return gcry_error (rc);
- }
- /*
- Create a public key pair and return it in r_key.
- How the key is created depends on s_parms:
- (genkey
- (algo
- (parameter_name_1 ....)
- ....
- (parameter_name_n ....)
- ))
- The key is returned in a format depending on the
- algorithm. Both, private and secret keys are returned
- and optionally some additional informatin.
- For elgamal we return this structure:
- (key-data
- (public-key
- (elg
- (p <mpi>)
- (g <mpi>)
- (y <mpi>)
- )
- )
- (private-key
- (elg
- (p <mpi>)
- (g <mpi>)
- (y <mpi>)
- (x <mpi>)
- )
- )
- (misc-key-info
- (pm1-factors n1 n2 ... nn)
- ))
- */
- gcry_error_t
- gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
- {
- gcry_pk_spec_t *pubkey = NULL;
- gcry_module_t module = NULL;
- gcry_sexp_t list = NULL;
- gcry_sexp_t l2 = NULL;
- gcry_sexp_t l3 = NULL;
- char *name = NULL;
- size_t n;
- gcry_err_code_t rc = GPG_ERR_NO_ERROR;
- int i, j;
- const char *algo_name = NULL;
- int algo;
- const char *sec_elems = NULL, *pub_elems = NULL;
- gcry_mpi_t skey[12];
- gcry_mpi_t *factors = NULL;
- gcry_sexp_t extrainfo = NULL;
- unsigned int nbits = 0;
- unsigned long use_e = 0;
- skey[0] = NULL;
- *r_key = NULL;
- REGISTER_DEFAULT_PUBKEYS;
- list = gcry_sexp_find_token (s_parms, "genkey", 0);
- if (!list)
- {
- rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */
- goto leave;
- }
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- l2 = NULL;
- if (! list)
- {
- rc = GPG_ERR_NO_OBJ; /* No cdr for the genkey. */
- goto leave;
- }
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- {
- rc = GPG_ERR_INV_OBJ; /* Algo string missing. */
- goto leave;
- }
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name (name);
- ath_mutex_unlock (&pubkeys_registered_lock);
- gcry_free (name);
- name = NULL;
- if (!module)
- {
- rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
- goto leave;
- }
- pubkey = (gcry_pk_spec_t *) module->spec;
- algo = module->mod_id;
- algo_name = pubkey->aliases? *pubkey->aliases : NULL;
- if (!algo_name || !*algo_name)
- algo_name = pubkey->name;
- pub_elems = pubkey->elements_pkey;
- sec_elems = pubkey->elements_skey;
- if (strlen (sec_elems) >= DIM(skey))
- BUG ();
- /* Handle the optional rsa-use-e element. Actually this belong into
- the algorithm module but we have this parameter in the public
- module API, so we need to parse it right here. */
- l2 = gcry_sexp_find_token (list, "rsa-use-e", 0);
- if (l2)
- {
- char buf[50];
- const char *s;
- s = gcry_sexp_nth_data (l2, 1, &n);
- if ( !s || n >= DIM (buf) - 1 )
- {
- rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
- goto leave;
- }
- memcpy (buf, s, n);
- buf[n] = 0;
- use_e = strtoul (buf, NULL, 0);
- gcry_sexp_release (l2);
- l2 = NULL;
- }
- else
- use_e = 65537; /* Not given, use the value generated by old versions. */
- /* Get the "nbits" parameter. */
- l2 = gcry_sexp_find_token (list, "nbits", 0);
- if (l2)
- {
- char buf[50];
- const char *s;
- s = gcry_sexp_nth_data (l2, 1, &n);
- if (!s || n >= DIM (buf) - 1 )
- {
- rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */
- goto leave;
- }
- memcpy (buf, s, n);
- buf[n] = 0;
- nbits = (unsigned int)strtoul (buf, NULL, 0);
- gcry_sexp_release (l2); l2 = NULL;
- }
- else
- nbits = 0;
- /* Pass control to the algorithm module. */
- rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey,
- &factors, &extrainfo);
- gcry_sexp_release (list); list = NULL;
- if (rc)
- goto leave;
- /* Key generation succeeded: Build an S-expression. */
- {
- char *string, *p;
- size_t nelem=0, nelem_cp = 0, needed=0;
- gcry_mpi_t mpis[30];
- int percent_s_idx = -1;
- /* Estimate size of format string. */
- nelem = strlen (pub_elems) + strlen (sec_elems);
- if (factors)
- {
- for (i = 0; factors[i]; i++)
- nelem++;
- }
- nelem_cp = nelem;
- needed += nelem * 10;
- /* (+5 is for EXTRAINFO ("%S")). */
- needed += 2 * strlen (algo_name) + 300 + 5;
- if (nelem > DIM (mpis))
- BUG ();
- /* Build the string. */
- nelem = 0;
- string = p = gcry_malloc (needed);
- if (!string)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- p = stpcpy (p, "(key-data");
- p = stpcpy (p, "(public-key(");
- p = stpcpy (p, algo_name);
- for(i = 0; pub_elems[i]; i++)
- {
- *p++ = '(';
- *p++ = pub_elems[i];
- p = stpcpy (p, "%m)");
- mpis[nelem++] = skey[i];
- }
- if (extrainfo && (algo == GCRY_PK_ECDSA || algo == GCRY_PK_ECDH))
- {
- /* Very ugly hack to insert the used curve parameter into the
- list of public key parameters. */
- percent_s_idx = nelem;
- p = stpcpy (p, "%S");
- }
- p = stpcpy (p, "))");
- p = stpcpy (p, "(private-key(");
- p = stpcpy (p, algo_name);
- for (i = 0; sec_elems[i]; i++)
- {
- *p++ = '(';
- *p++ = sec_elems[i];
- p = stpcpy (p, "%m)");
- mpis[nelem++] = skey[i];
- }
- p = stpcpy (p, "))");
- /* Hack to make release_mpi_array() work. */
- skey[i] = NULL;
- if (extrainfo && percent_s_idx == -1)
- {
- /* If we have extrainfo we should not have any factors. */
- p = stpcpy (p, "%S");
- }
- else if (factors && factors[0])
- {
- p = stpcpy (p, "(misc-key-info(pm1-factors");
- for(i = 0; factors[i]; i++)
- {
- p = stpcpy (p, "%m");
- mpis[nelem++] = factors[i];
- }
- p = stpcpy (p, "))");
- }
- strcpy (p, ")");
- gcry_assert (p - string < needed);
- while (nelem < DIM (mpis))
- mpis[nelem++] = NULL;
- {
- int elem_n = strlen (pub_elems) + strlen (sec_elems);
- void **arg_list;
- /* Allocate one extra for EXTRAINFO ("%S"). */
- arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list);
- if (!arg_list)
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
- for (i = j = 0; i < elem_n; i++)
- {
- if (i == percent_s_idx)
- arg_list[j++] = &extrainfo;
- arg_list[j++] = mpis + i;
- }
- if (extrainfo && percent_s_idx == -1)
- arg_list[j] = &extrainfo;
- else if (factors && factors[0])
- {
- for (; i < nelem_cp; i++)
- arg_list[j++] = factors + i - elem_n;
- }
- rc = gcry_sexp_build_array (r_key, NULL, string, arg_list);
- gcry_free (arg_list);
- if (rc)
- BUG ();
- gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that
- the array gets increased if
- new parameters are added. */
- }
- gcry_free (string);
- }
- leave:
- gcry_free (name);
- gcry_sexp_release (extrainfo);
- release_mpi_array (skey);
- /* Don't free SKEY itself, it is an stack allocated array. */
- if (factors)
- {
- release_mpi_array ( factors );
- gcry_free (factors);
- }
- gcry_sexp_release (l3);
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
- if (module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- return gcry_error (rc);
- }
- /*
- Get the number of nbits from the public key.
- Hmmm: Should we have really this function or is it better to have a
- more general function to retrieve different properties of the key? */
- unsigned int
- gcry_pk_get_nbits (gcry_sexp_t key)
- {
- gcry_module_t module = NULL;
- gcry_pk_spec_t *pubkey;
- gcry_mpi_t *keyarr = NULL;
- unsigned int nbits = 0;
- gcry_err_code_t rc;
- REGISTER_DEFAULT_PUBKEYS;
- rc = sexp_to_key (key, 0, NULL, &keyarr, &module);
- if (rc == GPG_ERR_INV_OBJ)
- rc = sexp_to_key (key, 1, NULL, &keyarr, &module);
- if (rc)
- return 0; /* Error - 0 is a suitable indication for that. */
- pubkey = (gcry_pk_spec_t *) module->spec;
- nbits = (*pubkey->get_nbits) (module->mod_id, keyarr);
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- release_mpi_array (keyarr);
- gcry_free (keyarr);
- return nbits;
- }
- /* Return the so called KEYGRIP which is the SHA-1 hash of the public
- key parameters expressed in a way depending on the algorithm.
- ARRAY must either be 20 bytes long or NULL; in the latter case a
- newly allocated array of that size is returned, otherwise ARRAY or
- NULL is returned to indicate an error which is most likely an
- unknown algorithm. The function accepts public or secret keys. */
- unsigned char *
- gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
- {
- gcry_sexp_t list = NULL, l2 = NULL;
- gcry_pk_spec_t *pubkey = NULL;
- gcry_module_t module = NULL;
- pk_extra_spec_t *extraspec;
- const char *s;
- char *name = NULL;
- int idx;
- const char *elems;
- gcry_md_hd_t md = NULL;
- int okay = 0;
- REGISTER_DEFAULT_PUBKEYS;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token (key, "public-key", 0);
- if (! list)
- list = gcry_sexp_find_token (key, "private-key", 0);
- if (! list)
- list = gcry_sexp_find_token (key, "protected-private-key", 0);
- if (! list)
- list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
- if (! list)
- return NULL; /* No public- or private-key object. */
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- l2 = NULL;
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- goto fail; /* Invalid structure of object. */
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name (name);
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!module)
- goto fail; /* Unknown algorithm. */
- pubkey = (gcry_pk_spec_t *) module->spec;
- extraspec = module->extraspec;
- elems = pubkey->elements_grip;
- if (!elems)
- goto fail; /* No grip parameter. */
- if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
- goto fail;
- if (extraspec && extraspec->comp_keygrip)
- {
- /* Module specific method to compute a keygrip. */
- if (extraspec->comp_keygrip (md, list))
- goto fail;
- }
- else
- {
- /* Generic method to compute a keygrip. */
- for (idx = 0, s = elems; *s; s++, idx++)
- {
- const char *data;
- size_t datalen;
- char buf[30];
- l2 = gcry_sexp_find_token (list, s, 1);
- if (! l2)
- goto fail;
- data = gcry_sexp_nth_data (l2, 1, &datalen);
- if (! data)
- goto fail;
- snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen);
- gcry_md_write (md, buf, strlen (buf));
- gcry_md_write (md, data, datalen);
- gcry_sexp_release (l2);
- l2 = NULL;
- gcry_md_write (md, ")", 1);
- }
- }
- if (!array)
- {
- array = gcry_malloc (20);
- if (! array)
- goto fail;
- }
- memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20);
- okay = 1;
- fail:
- gcry_free (name);
- gcry_sexp_release (l2);
- gcry_md_close (md);
- gcry_sexp_release (list);
- return okay? array : NULL;
- }
- const char *
- gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
- {
- gcry_mpi_t *pkey = NULL;
- gcry_sexp_t list = NULL;
- gcry_sexp_t l2;
- gcry_module_t module = NULL;
- pk_extra_spec_t *extraspec;
- char *name = NULL;
- const char *result = NULL;
- int want_private = 1;
- if (r_nbits)
- *r_nbits = 0;
- REGISTER_DEFAULT_PUBKEYS;
- if (key)
- {
- iterator = 0;
- /* Check that the first element is valid. */
- list = gcry_sexp_find_token (key, "public-key", 0);
- if (list)
- want_private = 0;
- if (!list)
- list = gcry_sexp_find_token (key, "private-key", 0);
- if (!list)
- return NULL; /* No public- or private-key object. */
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- l2 = NULL;
- name = _gcry_sexp_nth_string (list, 0);
- if (!name)
- goto leave; /* Invalid structure of object. */
- /* Get the key. We pass the names of the parameters for
- override_elems; this allows to call this function without the
- actual public key parameter. */
- if (sexp_to_key (key, want_private, "pabgn", &pkey, &module))
- goto leave;
- }
- else
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name ("ecc");
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (!module)
- goto leave;
- }
- extraspec = module->extraspec;
- if (!extraspec || !extraspec->get_curve)
- goto leave;
- result = extraspec->get_curve (pkey, iterator, r_nbits);
- leave:
- if (pkey)
- {
- release_mpi_array (pkey);
- gcry_free (pkey);
- }
- if (module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- gcry_free (name);
- gcry_sexp_release (list);
- return result;
- }
- gcry_sexp_t
- gcry_pk_get_param (int algo, const char *name)
- {
- gcry_module_t module = NULL;
- pk_extra_spec_t *extraspec;
- gcry_sexp_t result = NULL;
- if (algo != GCRY_PK_ECDSA && algo != GCRY_PK_ECDH)
- return NULL;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- module = gcry_pk_lookup_name ("ecc");
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (module)
- {
- extraspec = module->extraspec;
- if (extraspec && extraspec->get_curve_param)
- result = extraspec->get_curve_param (name);
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- return result;
- }
- gcry_error_t
- gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- REGISTER_DEFAULT_PUBKEYS;
- switch (cmd)
- {
- case GCRYCTL_DISABLE_ALGO:
- /* This one expects a buffer pointing to an integer with the
- algo number. */
- if ((! buffer) || (buflen != sizeof (int)))
- err = GPG_ERR_INV_ARG;
- else
- disable_pubkey_algo (*((int *) buffer));
- break;
- default:
- err = GPG_ERR_INV_OP;
- }
- return gcry_error (err);
- }
- /* Return information about the given algorithm
- WHAT selects the kind of information returned:
- GCRYCTL_TEST_ALGO:
- Returns 0 when the specified algorithm is available for use.
- Buffer must be NULL, nbytes may have the address of a variable
- with the required usage of the algorithm. It may be 0 for don't
- care or a combination of the GCRY_PK_USAGE_xxx flags;
- GCRYCTL_GET_ALGO_USAGE:
- Return the usage flags for the given algo. An invalid algo
- returns 0. Disabled algos are ignored here because we
- only want to know whether the algo is at all capable of
- the usage.
- Note: Because this function is in most cases used to return an
- integer value, we can make it easier for the caller to just look at
- the return value. The caller will in all cases consult the value
- and thereby detecting whether a error occurred or not (i.e. while
- checking the block size) */
- gcry_error_t
- gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- switch (what)
- {
- case GCRYCTL_TEST_ALGO:
- {
- int use = nbytes ? *nbytes : 0;
- if (buffer)
- err = GPG_ERR_INV_ARG;
- else if (check_pubkey_algo (algorithm, use))
- err = GPG_ERR_PUBKEY_ALGO;
- break;
- }
- case GCRYCTL_GET_ALGO_USAGE:
- {
- gcry_module_t pubkey;
- int use = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- {
- use = ((gcry_pk_spec_t *) pubkey->spec)->use;
- _gcry_module_release (pubkey);
- }
- ath_mutex_unlock (&pubkeys_registered_lock);
- /* FIXME? */
- *nbytes = use;
- break;
- }
- case GCRYCTL_GET_ALGO_NPKEY:
- {
- /* FIXME? */
- int npkey = pubkey_get_npkey (algorithm);
- *nbytes = npkey;
- break;
- }
- case GCRYCTL_GET_ALGO_NSKEY:
- {
- /* FIXME? */
- int nskey = pubkey_get_nskey (algorithm);
- *nbytes = nskey;
- break;
- }
- case GCRYCTL_GET_ALGO_NSIGN:
- {
- /* FIXME? */
- int nsign = pubkey_get_nsig (algorithm);
- *nbytes = nsign;
- break;
- }
- case GCRYCTL_GET_ALGO_NENCR:
- {
- /* FIXME? */
- int nencr = pubkey_get_nenc (algorithm);
- *nbytes = nencr;
- break;
- }
- default:
- err = GPG_ERR_INV_OP;
- }
- return gcry_error (err);
- }
- /* Explicitly initialize this module. */
- gcry_err_code_t
- _gcry_pk_init (void)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- REGISTER_DEFAULT_PUBKEYS;
- return err;
- }
- gcry_err_code_t
- _gcry_pk_module_lookup (int algorithm, gcry_module_t *module)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- gcry_module_t pubkey;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
- if (pubkey)
- *module = pubkey;
- else
- err = GPG_ERR_PUBKEY_ALGO;
- ath_mutex_unlock (&pubkeys_registered_lock);
- return err;
- }
- void
- _gcry_pk_module_release (gcry_module_t module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- /* Get a list consisting of the IDs of the loaded pubkey modules. If
- LIST is zero, write the number of loaded pubkey modules to
- LIST_LENGTH and return. If LIST is non-zero, the first
- *LIST_LENGTH algorithm IDs are stored in LIST, which must be of
- according size. In case there are less pubkey modules than
- *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */
- gcry_error_t
- gcry_pk_list (int *list, int *list_length)
- {
- gcry_err_code_t err = GPG_ERR_NO_ERROR;
- ath_mutex_lock (&pubkeys_registered_lock);
- err = _gcry_module_list (pubkeys_registered, list, list_length);
- ath_mutex_unlock (&pubkeys_registered_lock);
- return err;
- }
- /* Run the selftests for pubkey algorithm ALGO with optional reporting
- function REPORT. */
- gpg_error_t
- _gcry_pk_selftest (int algo, int extended, selftest_report_func_t report)
- {
- gcry_module_t module = NULL;
- pk_extra_spec_t *extraspec = NULL;
- gcry_err_code_t ec = 0;
- REGISTER_DEFAULT_PUBKEYS;
- ath_mutex_lock (&pubkeys_registered_lock);
- module = _gcry_module_lookup_id (pubkeys_registered, algo);
- if (module && !(module->flags & FLAG_MODULE_DISABLED))
- extraspec = module->extraspec;
- ath_mutex_unlock (&pubkeys_registered_lock);
- if (extraspec && extraspec->selftest)
- ec = extraspec->selftest (algo, extended, report);
- else
- {
- ec = GPG_ERR_PUBKEY_ALGO;
- if (report)
- report ("pubkey", algo, "module",
- module && !(module->flags & FLAG_MODULE_DISABLED)?
- "no selftest available" :
- module? "algorithm disabled" : "algorithm not found");
- }
- if (module)
- {
- ath_mutex_lock (&pubkeys_registered_lock);
- _gcry_module_release (module);
- ath_mutex_unlock (&pubkeys_registered_lock);
- }
- return gpg_error (ec);
- }
- /* This function is only used by ac.c! */
- gcry_err_code_t
- _gcry_pk_get_elements (int algo, char **enc, char **sig)
- {
- gcry_module_t pubkey;
- gcry_pk_spec_t *spec;
- gcry_err_code_t err;
- char *enc_cp;
- char *sig_cp;
- REGISTER_DEFAULT_PUBKEYS;
- enc_cp = NULL;
- sig_cp = NULL;
- spec = NULL;
- pubkey = _gcry_module_lookup_id (pubkeys_registered, algo);
- if (! pubkey)
- {
- err = GPG_ERR_INTERNAL;
- goto out;
- }
- spec = pubkey->spec;
- if (enc)
- {
- enc_cp = strdup (spec->elements_enc);
- if (! enc_cp)
- {
- err = gpg_err_code_from_syserror ();
- goto out;
- }
- }
- if (sig)
- {
- sig_cp = strdup (spec->elements_sig);
- if (! sig_cp)
- {
- err = gpg_err_code_from_syserror ();
- goto out;
- }
- }
- if (enc)
- *enc = enc_cp;
- if (sig)
- *sig = sig_cp;
- err = 0;
- out:
- _gcry_module_release (pubkey);
- if (err)
- {
- free (enc_cp);
- free (sig_cp);
- }
- return err;
- }
|