12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302 |
- /* ac.c - Alternative interface for asymmetric cryptography.
- Copyright (C) 2003, 2004, 2005, 2006
- 2007, 2008 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 <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <stddef.h>
- #include "g10lib.h"
- #include "cipher.h"
- #include "mpi.h"
- /* At the moment the ac interface is a wrapper around the pk
- interface, but this might change somewhen in the future, depending
- on how many people prefer the ac interface. */
- /* Mapping of flag numbers to the according strings as it is expected
- for S-expressions. */
- static struct number_string
- {
- int number;
- const char *string;
- } ac_flags[] =
- {
- { GCRY_AC_FLAG_NO_BLINDING, "no-blinding" },
- };
- /* The positions in this list correspond to the values contained in
- the gcry_ac_key_type_t enumeration list. */
- static const char *ac_key_identifiers[] =
- {
- "private-key",
- "public-key"
- };
- /* These specifications are needed for key-pair generation; the caller
- is allowed to pass additional, algorithm-specific `specs' to
- gcry_ac_key_pair_generate. This list is used for decoding the
- provided values according to the selected algorithm. */
- struct gcry_ac_key_generate_spec
- {
- int algorithm; /* Algorithm for which this flag is
- relevant. */
- const char *name; /* Name of this flag. */
- size_t offset; /* Offset in the cipher-specific spec
- structure at which the MPI value
- associated with this flag is to be
- found. */
- } ac_key_generate_specs[] =
- {
- { GCRY_AC_RSA, "rsa-use-e", offsetof (gcry_ac_key_spec_rsa_t, e) },
- { 0 }
- };
- /* Handle structure. */
- struct gcry_ac_handle
- {
- int algorithm; /* Algorithm ID associated with this
- handle. */
- const char *algorithm_name; /* Name of the algorithm. */
- unsigned int flags; /* Flags, not used yet. */
- gcry_module_t module; /* Reference to the algorithm
- module. */
- };
- /* A named MPI value. */
- typedef struct gcry_ac_mpi
- {
- char *name; /* Self-maintained copy of name. */
- gcry_mpi_t mpi; /* MPI value. */
- unsigned int flags; /* Flags. */
- } gcry_ac_mpi_t;
- /* A data set, that is simply a list of named MPI values. */
- struct gcry_ac_data
- {
- gcry_ac_mpi_t *data; /* List of named values. */
- unsigned int data_n; /* Number of values in DATA. */
- };
- /* A single key. */
- struct gcry_ac_key
- {
- gcry_ac_data_t data; /* Data in native ac structure. */
- gcry_ac_key_type_t type; /* Type of the key. */
- };
- /* A key pair. */
- struct gcry_ac_key_pair
- {
- gcry_ac_key_t public;
- gcry_ac_key_t secret;
- };
- /*
- * Functions for working with data sets.
- */
- /* Creates a new, empty data set and store it in DATA. */
- gcry_error_t
- _gcry_ac_data_new (gcry_ac_data_t *data)
- {
- gcry_ac_data_t data_new;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_new = gcry_malloc (sizeof (*data_new));
- if (! data_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- data_new->data = NULL;
- data_new->data_n = 0;
- *data = data_new;
- err = 0;
- out:
- return err;
- }
- /* Destroys all the entries in DATA, but not DATA itself. */
- static void
- ac_data_values_destroy (gcry_ac_data_t data)
- {
- unsigned int i;
- for (i = 0; i < data->data_n; i++)
- if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC)
- {
- gcry_mpi_release (data->data[i].mpi);
- gcry_free (data->data[i].name);
- }
- }
- /* Destroys the data set DATA. */
- void
- _gcry_ac_data_destroy (gcry_ac_data_t data)
- {
- if (data)
- {
- ac_data_values_destroy (data);
- gcry_free (data->data);
- gcry_free (data);
- }
- }
- /* This function creates a copy of the array of named MPIs DATA_MPIS,
- which is of length DATA_MPIS_N; the copy is stored in
- DATA_MPIS_CP. */
- static gcry_error_t
- ac_data_mpi_copy (gcry_ac_mpi_t *data_mpis, unsigned int data_mpis_n,
- gcry_ac_mpi_t **data_mpis_cp)
- {
- gcry_ac_mpi_t *data_mpis_new;
- gcry_error_t err;
- unsigned int i;
- gcry_mpi_t mpi;
- char *label;
- data_mpis_new = gcry_calloc (data_mpis_n, sizeof (*data_mpis_new));
- if (! data_mpis_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- memset (data_mpis_new, 0, sizeof (*data_mpis_new) * data_mpis_n);
- err = 0;
- for (i = 0; i < data_mpis_n; i++)
- {
- /* Copy values. */
- label = gcry_strdup (data_mpis[i].name);
- mpi = gcry_mpi_copy (data_mpis[i].mpi);
- if (! (label && mpi))
- {
- err = gcry_error_from_errno (errno);
- gcry_mpi_release (mpi);
- gcry_free (label);
- break;
- }
- data_mpis_new[i].flags = GCRY_AC_FLAG_DEALLOC;
- data_mpis_new[i].name = label;
- data_mpis_new[i].mpi = mpi;
- }
- if (err)
- goto out;
- *data_mpis_cp = data_mpis_new;
- err = 0;
- out:
- if (err)
- if (data_mpis_new)
- {
- for (i = 0; i < data_mpis_n; i++)
- {
- gcry_mpi_release (data_mpis_new[i].mpi);
- gcry_free (data_mpis_new[i].name);
- }
- gcry_free (data_mpis_new);
- }
- return err;
- }
- /* Create a copy of the data set DATA and store it in DATA_CP. */
- gcry_error_t
- _gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data)
- {
- gcry_ac_mpi_t *data_mpis = NULL;
- gcry_ac_data_t data_new;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- /* Allocate data set. */
- data_new = gcry_malloc (sizeof (*data_new));
- if (! data_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- err = ac_data_mpi_copy (data->data, data->data_n, &data_mpis);
- if (err)
- goto out;
- data_new->data_n = data->data_n;
- data_new->data = data_mpis;
- *data_cp = data_new;
- out:
- if (err)
- gcry_free (data_new);
- return err;
- }
- /* Returns the number of named MPI values inside of the data set
- DATA. */
- unsigned int
- _gcry_ac_data_length (gcry_ac_data_t data)
- {
- return data->data_n;
- }
- /* Add the value MPI to DATA with the label NAME. If FLAGS contains
- GCRY_AC_FLAG_COPY, the data set will contain copies of NAME
- and MPI. If FLAGS contains GCRY_AC_FLAG_DEALLOC or
- GCRY_AC_FLAG_COPY, the values contained in the data set will
- be deallocated when they are to be removed from the data set. */
- gcry_error_t
- _gcry_ac_data_set (gcry_ac_data_t data, unsigned int flags,
- const char *name, gcry_mpi_t mpi)
- {
- gcry_error_t err;
- gcry_mpi_t mpi_cp;
- char *name_cp;
- unsigned int i;
- name_cp = NULL;
- mpi_cp = NULL;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- if (flags & ~(GCRY_AC_FLAG_DEALLOC | GCRY_AC_FLAG_COPY))
- {
- err = gcry_error (GPG_ERR_INV_ARG);
- goto out;
- }
- if (flags & GCRY_AC_FLAG_COPY)
- {
- /* Create copies. */
- flags |= GCRY_AC_FLAG_DEALLOC;
- name_cp = gcry_strdup (name);
- mpi_cp = gcry_mpi_copy (mpi);
- if (! (name_cp && mpi_cp))
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- }
- /* Search for existing entry. */
- for (i = 0; i < data->data_n; i++)
- if (! strcmp (name, data->data[i].name))
- break;
- if (i < data->data_n)
- {
- /* An entry for NAME does already exist. */
- if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC)
- {
- gcry_mpi_release (data->data[i].mpi);
- gcry_free (data->data[i].name);
- }
- }
- else
- {
- /* Create a new entry. */
- gcry_ac_mpi_t *ac_mpis;
- ac_mpis = gcry_realloc (data->data,
- sizeof (*data->data) * (data->data_n + 1));
- if (! ac_mpis)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- if (data->data != ac_mpis)
- data->data = ac_mpis;
- data->data_n++;
- }
- data->data[i].name = name_cp ? name_cp : ((char *) name);
- data->data[i].mpi = mpi_cp ? mpi_cp : mpi;
- data->data[i].flags = flags;
- err = 0;
- out:
- if (err)
- {
- gcry_mpi_release (mpi_cp);
- gcry_free (name_cp);
- }
- return err;
- }
- /* Stores the value labelled with NAME found in the data set DATA in
- MPI. The returned MPI value will be released in case
- gcry_ac_data_set is used to associate the label NAME with a
- different MPI value. */
- gcry_error_t
- _gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags,
- const char *name, gcry_mpi_t *mpi)
- {
- gcry_mpi_t mpi_return;
- gcry_error_t err;
- unsigned int i;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- if (flags & ~(GCRY_AC_FLAG_COPY))
- {
- err = gcry_error (GPG_ERR_INV_ARG);
- goto out;
- }
- for (i = 0; i < data->data_n; i++)
- if (! strcmp (name, data->data[i].name))
- break;
- if (i == data->data_n)
- {
- err = gcry_error (GPG_ERR_NOT_FOUND);
- goto out;
- }
- if (flags & GCRY_AC_FLAG_COPY)
- {
- mpi_return = gcry_mpi_copy (data->data[i].mpi);
- if (! mpi_return)
- {
- err = gcry_error_from_errno (errno); /* FIXME? */
- goto out;
- }
- }
- else
- mpi_return = data->data[i].mpi;
- *mpi = mpi_return;
- err = 0;
- out:
- return err;
- }
- /* Stores in NAME and MPI the named MPI value contained in the data
- set DATA with the index IDX. NAME or MPI may be NULL. The
- returned MPI value will be released in case gcry_ac_data_set is
- used to associate the label NAME with a different MPI value. */
- gcry_error_t
- _gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int flags,
- unsigned int idx,
- const char **name, gcry_mpi_t *mpi)
- {
- gcry_error_t err;
- gcry_mpi_t mpi_cp;
- char *name_cp;
- name_cp = NULL;
- mpi_cp = NULL;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- if (flags & ~(GCRY_AC_FLAG_COPY))
- {
- err = gcry_error (GPG_ERR_INV_ARG);
- goto out;
- }
- if (idx >= data->data_n)
- {
- err = gcry_error (GPG_ERR_INV_ARG);
- goto out;
- }
- if (flags & GCRY_AC_FLAG_COPY)
- {
- /* Return copies to the user. */
- if (name)
- {
- name_cp = gcry_strdup (data->data[idx].name);
- if (! name_cp)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- }
- if (mpi)
- {
- mpi_cp = gcry_mpi_copy (data->data[idx].mpi);
- if (! mpi_cp)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- }
- }
- if (name)
- *name = name_cp ? name_cp : data->data[idx].name;
- if (mpi)
- *mpi = mpi_cp ? mpi_cp : data->data[idx].mpi;
- err = 0;
- out:
- if (err)
- {
- gcry_mpi_release (mpi_cp);
- gcry_free (name_cp);
- }
- return err;
- }
- /* Convert the data set DATA into a new S-Expression, which is to be
- stored in SEXP, according to the identifiers contained in
- IDENTIFIERS. */
- gcry_error_t
- _gcry_ac_data_to_sexp (gcry_ac_data_t data, gcry_sexp_t *sexp,
- const char **identifiers)
- {
- gcry_sexp_t sexp_new;
- gcry_error_t err;
- char *sexp_buffer;
- size_t sexp_buffer_n;
- size_t identifiers_n;
- const char *label;
- gcry_mpi_t mpi;
- void **arg_list;
- size_t data_n;
- unsigned int i;
- sexp_buffer_n = 1;
- sexp_buffer = NULL;
- arg_list = NULL;
- err = 0;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- /* Calculate size of S-expression representation. */
- i = 0;
- if (identifiers)
- while (identifiers[i])
- {
- /* For each identifier, we add "(<IDENTIFIER>)". */
- sexp_buffer_n += 1 + strlen (identifiers[i]) + 1;
- i++;
- }
- identifiers_n = i;
- if (! identifiers_n)
- /* If there are NO identifiers, we still add surrounding braces so
- that we have a list of named MPI value lists. Otherwise it
- wouldn't be too much fun to process these lists. */
- sexp_buffer_n += 2;
- data_n = _gcry_ac_data_length (data);
- for (i = 0; i < data_n; i++)
- {
- err = gcry_ac_data_get_index (data, 0, i, &label, NULL);
- if (err)
- break;
- /* For each MPI we add "(<LABEL> %m)". */
- sexp_buffer_n += 1 + strlen (label) + 4;
- }
- if (err)
- goto out;
- /* Allocate buffer. */
- sexp_buffer = gcry_malloc (sexp_buffer_n);
- if (! sexp_buffer)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Fill buffer. */
- *sexp_buffer = 0;
- sexp_buffer_n = 0;
- /* Add identifiers: (<IDENTIFIER0>(<IDENTIFIER1>...)). */
- if (identifiers_n)
- {
- /* Add nested identifier lists as usual. */
- for (i = 0; i < identifiers_n; i++)
- sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "(%s",
- identifiers[i]);
- }
- else
- {
- /* Add special list. */
- sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "(");
- }
- /* Add MPI list. */
- arg_list = gcry_calloc (data_n + 1, sizeof (*arg_list));
- if (! arg_list)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- for (i = 0; i < data_n; i++)
- {
- err = gcry_ac_data_get_index (data, 0, i, &label, &mpi);
- if (err)
- break;
- sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n,
- "(%s %%m)", label);
- arg_list[i] = &data->data[i].mpi;
- }
- if (err)
- goto out;
- if (identifiers_n)
- {
- /* Add closing braces for identifier lists as usual. */
- for (i = 0; i < identifiers_n; i++)
- sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")");
- }
- else
- {
- /* Add closing braces for special list. */
- sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")");
- }
- /* Construct. */
- err = gcry_sexp_build_array (&sexp_new, NULL, sexp_buffer, arg_list);
- if (err)
- goto out;
- *sexp = sexp_new;
- out:
- gcry_free (sexp_buffer);
- gcry_free (arg_list);
- return err;
- }
- /* Create a new data set, which is to be stored in DATA_SET, from the
- S-Expression SEXP, according to the identifiers contained in
- IDENTIFIERS. */
- gcry_error_t
- _gcry_ac_data_from_sexp (gcry_ac_data_t *data_set, gcry_sexp_t sexp,
- const char **identifiers)
- {
- gcry_ac_data_t data_set_new;
- gcry_error_t err;
- gcry_sexp_t sexp_cur;
- gcry_sexp_t sexp_tmp;
- gcry_mpi_t mpi;
- char *string;
- const char *data;
- size_t data_n;
- size_t sexp_n;
- unsigned int i;
- int skip_name;
- data_set_new = NULL;
- sexp_cur = sexp;
- sexp_tmp = NULL;
- string = NULL;
- mpi = NULL;
- err = 0;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- /* Process S-expression/identifiers. */
- if (identifiers)
- {
- for (i = 0; identifiers[i]; i++)
- {
- /* Next identifier. Extract first data item from
- SEXP_CUR. */
- data = gcry_sexp_nth_data (sexp_cur, 0, &data_n);
- if (! ((data_n == strlen (identifiers[i]))
- && (! strncmp (data, identifiers[i], data_n))))
- {
- /* Identifier mismatch -> error. */
- err = gcry_error (GPG_ERR_INV_SEXP);
- break;
- }
- /* Identifier matches. Now we have to distinguish two
- cases:
- (i) we are at the last identifier:
- leave loop
- (ii) we are not at the last identifier:
- extract next element, which is supposed to be a
- sublist. */
- if (! identifiers[i + 1])
- /* Last identifier. */
- break;
- else
- {
- /* Not the last identifier, extract next sublist. */
- sexp_tmp = gcry_sexp_nth (sexp_cur, 1);
- if (! sexp_tmp)
- {
- /* Missing sublist. */
- err = gcry_error (GPG_ERR_INV_SEXP);
- break;
- }
- /* Release old SEXP_CUR, in case it is not equal to the
- original SEXP. */
- if (sexp_cur != sexp)
- gcry_sexp_release (sexp_cur);
- /* Make SEXP_CUR point to the new current sublist. */
- sexp_cur = sexp_tmp;
- sexp_tmp = NULL;
- }
- }
- if (err)
- goto out;
- if (i)
- {
- /* We have at least one identifier in the list, this means
- the the list of named MPI values is prefixed, this means
- that we need to skip the first item (the list name), when
- processing the MPI values. */
- skip_name = 1;
- }
- else
- {
- /* Since there is no identifiers list, the list of named MPI
- values is not prefixed with a list name, therefore the
- offset to use is zero. */
- skip_name = 0;
- }
- }
- else
- /* Since there is no identifiers list, the list of named MPI
- values is not prefixed with a list name, therefore the offset
- to use is zero. */
- skip_name = 0;
- /* Create data set from S-expression data. */
- err = gcry_ac_data_new (&data_set_new);
- if (err)
- goto out;
- /* Figure out amount of named MPIs in SEXP_CUR. */
- if (sexp_cur)
- sexp_n = gcry_sexp_length (sexp_cur) - skip_name;
- else
- sexp_n = 0;
- /* Extracte the named MPIs sequentially. */
- for (i = 0; i < sexp_n; i++)
- {
- /* Store next S-Expression pair, which is supposed to consist of
- a name and an MPI value, in SEXP_TMP. */
- sexp_tmp = gcry_sexp_nth (sexp_cur, i + skip_name);
- if (! sexp_tmp)
- {
- err = gcry_error (GPG_ERR_INV_SEXP);
- break;
- }
- /* Extract name from current S-Expression pair. */
- data = gcry_sexp_nth_data (sexp_tmp, 0, &data_n);
- string = gcry_malloc (data_n + 1);
- if (! string)
- {
- err = gcry_error_from_errno (errno);
- break;
- }
- memcpy (string, data, data_n);
- string[data_n] = 0;
- /* Extract MPI value. */
- mpi = gcry_sexp_nth_mpi (sexp_tmp, 1, 0);
- if (! mpi)
- {
- err = gcry_error (GPG_ERR_INV_SEXP); /* FIXME? */
- break;
- }
- /* Store named MPI in data_set_new. */
- err = gcry_ac_data_set (data_set_new, GCRY_AC_FLAG_DEALLOC, string, mpi);
- if (err)
- break;
- /* gcry_free (string); */
- string = NULL;
- /* gcry_mpi_release (mpi); */
- mpi = NULL;
- gcry_sexp_release (sexp_tmp);
- sexp_tmp = NULL;
- }
- if (err)
- goto out;
- *data_set = data_set_new;
- out:
- if (sexp_cur != sexp)
- gcry_sexp_release (sexp_cur);
- gcry_sexp_release (sexp_tmp);
- gcry_mpi_release (mpi);
- gcry_free (string);
- if (err)
- gcry_ac_data_destroy (data_set_new);
- return err;
- }
- static void
- _gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data)
- {
- unsigned char *mpi_buffer;
- size_t mpi_buffer_n;
- unsigned int data_n;
- gcry_error_t err;
- const char *name;
- gcry_mpi_t mpi;
- unsigned int i;
- if (! data)
- return;
- if (fips_mode ())
- return;
- mpi_buffer = NULL;
- data_n = _gcry_ac_data_length (data);
- for (i = 0; i < data_n; i++)
- {
- err = gcry_ac_data_get_index (data, 0, i, &name, &mpi);
- if (err)
- {
- log_error ("failed to dump data set");
- break;
- }
- err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &mpi_buffer, &mpi_buffer_n, mpi);
- if (err)
- {
- log_error ("failed to dump data set");
- break;
- }
- log_printf ("%s%s%s: %s\n",
- prefix ? prefix : "",
- prefix ? ": " : ""
- , name, mpi_buffer);
- gcry_free (mpi_buffer);
- mpi_buffer = NULL;
- }
- gcry_free (mpi_buffer);
- }
- /* Dump the named MPI values contained in the data set DATA to
- Libgcrypt's logging stream. */
- void
- gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data)
- {
- _gcry_ac_data_dump (prefix, data);
- }
- /* Destroys any values contained in the data set DATA. */
- void
- _gcry_ac_data_clear (gcry_ac_data_t data)
- {
- ac_data_values_destroy (data);
- gcry_free (data->data);
- data->data = NULL;
- data->data_n = 0;
- }
- /*
- * Implementation of `ac io' objects.
- */
- /* Initialize AC_IO according to MODE, TYPE and the variable list of
- arguments AP. The list of variable arguments to specify depends on
- the given TYPE. */
- void
- _gcry_ac_io_init_va (gcry_ac_io_t *ac_io,
- gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, va_list ap)
- {
- memset (ac_io, 0, sizeof (*ac_io));
- if (fips_mode ())
- return;
- gcry_assert ((mode == GCRY_AC_IO_READABLE) || (mode == GCRY_AC_IO_WRITABLE));
- gcry_assert ((type == GCRY_AC_IO_STRING) || (type == GCRY_AC_IO_STRING));
- ac_io->mode = mode;
- ac_io->type = type;
- switch (mode)
- {
- case GCRY_AC_IO_READABLE:
- switch (type)
- {
- case GCRY_AC_IO_STRING:
- ac_io->io.readable.string.data = va_arg (ap, unsigned char *);
- ac_io->io.readable.string.data_n = va_arg (ap, size_t);
- break;
- case GCRY_AC_IO_CALLBACK:
- ac_io->io.readable.callback.cb = va_arg (ap, gcry_ac_data_read_cb_t);
- ac_io->io.readable.callback.opaque = va_arg (ap, void *);
- break;
- }
- break;
- case GCRY_AC_IO_WRITABLE:
- switch (type)
- {
- case GCRY_AC_IO_STRING:
- ac_io->io.writable.string.data = va_arg (ap, unsigned char **);
- ac_io->io.writable.string.data_n = va_arg (ap, size_t *);
- break;
- case GCRY_AC_IO_CALLBACK:
- ac_io->io.writable.callback.cb = va_arg (ap, gcry_ac_data_write_cb_t);
- ac_io->io.writable.callback.opaque = va_arg (ap, void *);
- break;
- }
- break;
- }
- }
- /* Initialize AC_IO according to MODE, TYPE and the variable list of
- arguments. The list of variable arguments to specify depends on
- the given TYPE. */
- void
- _gcry_ac_io_init (gcry_ac_io_t *ac_io,
- gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, ...)
- {
- va_list ap;
- va_start (ap, type);
- _gcry_ac_io_init_va (ac_io, mode, type, ap);
- va_end (ap);
- }
- /* Write to the IO object AC_IO BUFFER_N bytes from BUFFER. Return
- zero on success or error code. */
- static gcry_error_t
- _gcry_ac_io_write (gcry_ac_io_t *ac_io, unsigned char *buffer, size_t buffer_n)
- {
- gcry_error_t err;
- gcry_assert (ac_io->mode == GCRY_AC_IO_WRITABLE);
- err = 0;
- switch (ac_io->type)
- {
- case GCRY_AC_IO_STRING:
- {
- unsigned char *p;
- if (*ac_io->io.writable.string.data)
- {
- p = gcry_realloc (*ac_io->io.writable.string.data,
- *ac_io->io.writable.string.data_n + buffer_n);
- if (! p)
- err = gcry_error_from_errno (errno);
- else
- {
- if (*ac_io->io.writable.string.data != p)
- *ac_io->io.writable.string.data = p;
- memcpy (p + *ac_io->io.writable.string.data_n, buffer, buffer_n);
- *ac_io->io.writable.string.data_n += buffer_n;
- }
- }
- else
- {
- if (gcry_is_secure (buffer))
- p = gcry_malloc_secure (buffer_n);
- else
- p = gcry_malloc (buffer_n);
- if (! p)
- err = gcry_error_from_errno (errno);
- else
- {
- memcpy (p, buffer, buffer_n);
- *ac_io->io.writable.string.data = p;
- *ac_io->io.writable.string.data_n = buffer_n;
- }
- }
- }
- break;
- case GCRY_AC_IO_CALLBACK:
- err = (*ac_io->io.writable.callback.cb) (ac_io->io.writable.callback.opaque,
- buffer, buffer_n);
- break;
- }
- return err;
- }
- /* Read *BUFFER_N bytes from the IO object AC_IO into BUFFER; NREAD
- bytes have already been read from the object; on success, store the
- amount of bytes read in *BUFFER_N; zero bytes read means EOF.
- Return zero on success or error code. */
- static gcry_error_t
- _gcry_ac_io_read (gcry_ac_io_t *ac_io,
- unsigned int nread, unsigned char *buffer, size_t *buffer_n)
- {
- gcry_error_t err;
- gcry_assert (ac_io->mode == GCRY_AC_IO_READABLE);
- err = 0;
- switch (ac_io->type)
- {
- case GCRY_AC_IO_STRING:
- {
- size_t bytes_available;
- size_t bytes_to_read;
- size_t bytes_wanted;
- bytes_available = ac_io->io.readable.string.data_n - nread;
- bytes_wanted = *buffer_n;
- if (bytes_wanted > bytes_available)
- bytes_to_read = bytes_available;
- else
- bytes_to_read = bytes_wanted;
- memcpy (buffer, ac_io->io.readable.string.data + nread, bytes_to_read);
- *buffer_n = bytes_to_read;
- err = 0;
- break;
- }
- case GCRY_AC_IO_CALLBACK:
- err = (*ac_io->io.readable.callback.cb)
- (ac_io->io.readable.callback.opaque, buffer, buffer_n);
- break;
- }
- return err;
- }
- /* Read all data available from the IO object AC_IO into newly
- allocated memory, storing an appropriate pointer in *BUFFER and the
- amount of bytes read in *BUFFER_N. Return zero on success or error
- code. */
- static gcry_error_t
- _gcry_ac_io_read_all (gcry_ac_io_t *ac_io, unsigned char **buffer, size_t *buffer_n)
- {
- unsigned char *buffer_new;
- size_t buffer_new_n;
- unsigned char buf[BUFSIZ];
- size_t buf_n;
- unsigned char *p;
- gcry_error_t err;
- buffer_new = NULL;
- buffer_new_n = 0;
- while (1)
- {
- buf_n = sizeof (buf);
- err = _gcry_ac_io_read (ac_io, buffer_new_n, buf, &buf_n);
- if (err)
- break;
- if (buf_n)
- {
- p = gcry_realloc (buffer_new, buffer_new_n + buf_n);
- if (! p)
- {
- err = gcry_error_from_errno (errno);
- break;
- }
- if (buffer_new != p)
- buffer_new = p;
- memcpy (buffer_new + buffer_new_n, buf, buf_n);
- buffer_new_n += buf_n;
- }
- else
- break;
- }
- if (err)
- goto out;
- *buffer_n = buffer_new_n;
- *buffer = buffer_new;
- out:
- if (err)
- gcry_free (buffer_new);
- return err;
- }
- /* Read data chunks from the IO object AC_IO until EOF, feeding them
- to the callback function CB. Return zero on success or error
- code. */
- static gcry_error_t
- _gcry_ac_io_process (gcry_ac_io_t *ac_io,
- gcry_ac_data_write_cb_t cb, void *opaque)
- {
- unsigned char buffer[BUFSIZ];
- unsigned int nread;
- size_t buffer_n;
- gcry_error_t err;
- nread = 0;
- while (1)
- {
- buffer_n = sizeof (buffer);
- err = _gcry_ac_io_read (ac_io, nread, buffer, &buffer_n);
- if (err)
- break;
- if (buffer_n)
- {
- err = (*cb) (opaque, buffer, buffer_n);
- if (err)
- break;
- nread += buffer_n;
- }
- else
- break;
- }
- return err;
- }
- /*
- * Functions for converting data between the native ac and the
- * S-expression structure used by the pk interface.
- */
- /* Extract the S-Expression DATA_SEXP into DATA under the control of
- TYPE and NAME. This function assumes that S-Expressions are of the
- following structure:
- (IDENTIFIER [...]
- (ALGORITHM <list of named MPI values>)) */
- static gcry_error_t
- ac_data_extract (const char *identifier, const char *algorithm,
- gcry_sexp_t sexp, gcry_ac_data_t *data)
- {
- gcry_error_t err;
- gcry_sexp_t value_sexp;
- gcry_sexp_t data_sexp;
- size_t data_sexp_n;
- gcry_mpi_t value_mpi;
- char *value_name;
- const char *data_raw;
- size_t data_raw_n;
- gcry_ac_data_t data_new;
- unsigned int i;
- value_sexp = NULL;
- data_sexp = NULL;
- value_name = NULL;
- value_mpi = NULL;
- data_new = NULL;
- /* Verify that the S-expression contains the correct identifier. */
- data_raw = gcry_sexp_nth_data (sexp, 0, &data_raw_n);
- if ((! data_raw) || strncmp (identifier, data_raw, data_raw_n))
- {
- err = gcry_error (GPG_ERR_INV_SEXP);
- goto out;
- }
- /* Extract inner S-expression. */
- data_sexp = gcry_sexp_find_token (sexp, algorithm, 0);
- if (! data_sexp)
- {
- err = gcry_error (GPG_ERR_INV_SEXP);
- goto out;
- }
- /* Count data elements. */
- data_sexp_n = gcry_sexp_length (data_sexp);
- data_sexp_n--;
- /* Allocate new data set. */
- err = _gcry_ac_data_new (&data_new);
- if (err)
- goto out;
- /* Iterate through list of data elements and add them to the data
- set. */
- for (i = 0; i < data_sexp_n; i++)
- {
- /* Get the S-expression of the named MPI, that contains the name
- and the MPI value. */
- value_sexp = gcry_sexp_nth (data_sexp, i + 1);
- if (! value_sexp)
- {
- err = gcry_error (GPG_ERR_INV_SEXP);
- break;
- }
- /* Extract the name. */
- data_raw = gcry_sexp_nth_data (value_sexp, 0, &data_raw_n);
- if (! data_raw)
- {
- err = gcry_error (GPG_ERR_INV_SEXP);
- break;
- }
- /* Extract the MPI value. */
- value_mpi = gcry_sexp_nth_mpi (value_sexp, 1, GCRYMPI_FMT_USG);
- if (! value_mpi)
- {
- err = gcry_error (GPG_ERR_INTERNAL); /* FIXME? */
- break;
- }
- /* Duplicate the name. */
- value_name = gcry_malloc (data_raw_n + 1);
- if (! value_name)
- {
- err = gcry_error_from_errno (errno);
- break;
- }
- strncpy (value_name, data_raw, data_raw_n);
- value_name[data_raw_n] = 0;
- err = _gcry_ac_data_set (data_new, GCRY_AC_FLAG_DEALLOC, value_name, value_mpi);
- if (err)
- break;
- gcry_sexp_release (value_sexp);
- value_sexp = NULL;
- value_name = NULL;
- value_mpi = NULL;
- }
- if (err)
- goto out;
- /* Copy out. */
- *data = data_new;
- out:
- /* Deallocate resources. */
- if (err)
- {
- _gcry_ac_data_destroy (data_new);
- gcry_mpi_release (value_mpi);
- gcry_free (value_name);
- gcry_sexp_release (value_sexp);
- }
- gcry_sexp_release (data_sexp);
- return err;
- }
- /* Construct an S-expression from the DATA and store it in
- DATA_SEXP. The S-expression will be of the following structure:
- (IDENTIFIER [(flags [...])]
- (ALGORITHM <list of named MPI values>)) */
- static gcry_error_t
- ac_data_construct (const char *identifier, int include_flags,
- unsigned int flags, const char *algorithm,
- gcry_ac_data_t data, gcry_sexp_t *sexp)
- {
- unsigned int data_length;
- gcry_sexp_t sexp_new;
- gcry_error_t err;
- size_t sexp_format_n;
- char *sexp_format;
- void **arg_list;
- unsigned int i;
- arg_list = NULL;
- sexp_new = NULL;
- sexp_format = NULL;
- /* We build a list of arguments to pass to
- gcry_sexp_build_array(). */
- data_length = _gcry_ac_data_length (data);
- arg_list = gcry_calloc (data_length, sizeof (*arg_list) * 2);
- if (! arg_list)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Fill list with MPIs. */
- for (i = 0; i < data_length; i++)
- {
- char **nameaddr = &data->data[i].name;
- arg_list[(i * 2) + 0] = nameaddr;
- arg_list[(i * 2) + 1] = &data->data[i].mpi;
- }
- /* Calculate size of format string. */
- sexp_format_n = (3
- + (include_flags ? 7 : 0)
- + (algorithm ? (2 + strlen (algorithm)) : 0)
- + strlen (identifier));
- for (i = 0; i < data_length; i++)
- /* Per-element sizes. */
- sexp_format_n += 6;
- if (include_flags)
- /* Add flags. */
- for (i = 0; i < DIM (ac_flags); i++)
- if (flags & ac_flags[i].number)
- sexp_format_n += strlen (ac_flags[i].string) + 1;
- /* Done. */
- sexp_format = gcry_malloc (sexp_format_n);
- if (! sexp_format)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Construct the format string. */
- *sexp_format = 0;
- strcat (sexp_format, "(");
- strcat (sexp_format, identifier);
- if (include_flags)
- {
- strcat (sexp_format, "(flags");
- for (i = 0; i < DIM (ac_flags); i++)
- if (flags & ac_flags[i].number)
- {
- strcat (sexp_format, " ");
- strcat (sexp_format, ac_flags[i].string);
- }
- strcat (sexp_format, ")");
- }
- if (algorithm)
- {
- strcat (sexp_format, "(");
- strcat (sexp_format, algorithm);
- }
- for (i = 0; i < data_length; i++)
- strcat (sexp_format, "(%s%m)");
- if (algorithm)
- strcat (sexp_format, ")");
- strcat (sexp_format, ")");
- /* Create final S-expression. */
- err = gcry_sexp_build_array (&sexp_new, NULL, sexp_format, arg_list);
- if (err)
- goto out;
- *sexp = sexp_new;
- out:
- /* Deallocate resources. */
- gcry_free (sexp_format);
- gcry_free (arg_list);
- if (err)
- gcry_sexp_release (sexp_new);
- return err;
- }
- /*
- * Handle management.
- */
- /* Creates a new handle for the algorithm ALGORITHM and stores it in
- HANDLE. FLAGS is not used yet. */
- gcry_error_t
- _gcry_ac_open (gcry_ac_handle_t *handle,
- gcry_ac_id_t algorithm, unsigned int flags)
- {
- gcry_ac_handle_t handle_new;
- const char *algorithm_name;
- gcry_module_t module;
- gcry_error_t err;
- *handle = NULL;
- module = NULL;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- /* Get name. */
- algorithm_name = _gcry_pk_aliased_algo_name (algorithm);
- if (! algorithm_name)
- {
- err = gcry_error (GPG_ERR_PUBKEY_ALGO);
- goto out;
- }
- /* Acquire reference to the pubkey module. */
- err = _gcry_pk_module_lookup (algorithm, &module);
- if (err)
- goto out;
- /* Allocate. */
- handle_new = gcry_malloc (sizeof (*handle_new));
- if (! handle_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Done. */
- handle_new->algorithm = algorithm;
- handle_new->algorithm_name = algorithm_name;
- handle_new->flags = flags;
- handle_new->module = module;
- *handle = handle_new;
- out:
- /* Deallocate resources. */
- if (err)
- _gcry_pk_module_release (module);
- return err;
- }
- /* Destroys the handle HANDLE. */
- void
- _gcry_ac_close (gcry_ac_handle_t handle)
- {
- /* Release reference to pubkey module. */
- if (handle)
- {
- _gcry_pk_module_release (handle->module);
- gcry_free (handle);
- }
- }
- /*
- * Key management.
- */
- /* Initialize a key from a given data set. */
- /* FIXME/Damn: the argument HANDLE is not only unnecessary, it is
- completely WRONG here. */
- gcry_error_t
- _gcry_ac_key_init (gcry_ac_key_t *key, gcry_ac_handle_t handle,
- gcry_ac_key_type_t type, gcry_ac_data_t data)
- {
- gcry_ac_data_t data_new;
- gcry_ac_key_t key_new;
- gcry_error_t err;
- (void)handle;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- /* Allocate. */
- key_new = gcry_malloc (sizeof (*key_new));
- if (! key_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Copy data set. */
- err = _gcry_ac_data_copy (&data_new, data);
- if (err)
- goto out;
- /* Done. */
- key_new->data = data_new;
- key_new->type = type;
- *key = key_new;
- out:
- if (err)
- /* Deallocate resources. */
- gcry_free (key_new);
- return err;
- }
- /* Generates a new key pair via the handle HANDLE of NBITS bits and
- stores it in KEY_PAIR. In case non-standard settings are wanted, a
- pointer to a structure of type gcry_ac_key_spec_<algorithm>_t,
- matching the selected algorithm, can be given as KEY_SPEC.
- MISC_DATA is not used yet. */
- gcry_error_t
- _gcry_ac_key_pair_generate (gcry_ac_handle_t handle, unsigned int nbits,
- void *key_spec,
- gcry_ac_key_pair_t *key_pair,
- gcry_mpi_t **misc_data)
- {
- gcry_sexp_t genkey_sexp_request;
- gcry_sexp_t genkey_sexp_reply;
- gcry_ac_data_t key_data_secret;
- gcry_ac_data_t key_data_public;
- gcry_ac_key_pair_t key_pair_new;
- gcry_ac_key_t key_secret;
- gcry_ac_key_t key_public;
- gcry_sexp_t key_sexp;
- gcry_error_t err;
- char *genkey_format;
- size_t genkey_format_n;
- void **arg_list;
- size_t arg_list_n;
- unsigned int i;
- unsigned int j;
- (void)misc_data;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- key_data_secret = NULL;
- key_data_public = NULL;
- key_secret = NULL;
- key_public = NULL;
- genkey_format = NULL;
- arg_list = NULL;
- genkey_sexp_request = NULL;
- genkey_sexp_reply = NULL;
- key_sexp = NULL;
- /* Allocate key pair. */
- key_pair_new = gcry_malloc (sizeof (struct gcry_ac_key_pair));
- if (! key_pair_new)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Allocate keys. */
- key_secret = gcry_malloc (sizeof (*key_secret));
- if (! key_secret)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- key_public = gcry_malloc (sizeof (*key_public));
- if (! key_public)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Calculate size of the format string, that is used for creating
- the request S-expression. */
- genkey_format_n = 22;
- /* Respect any relevant algorithm specific commands. */
- if (key_spec)
- for (i = 0; i < DIM (ac_key_generate_specs); i++)
- if (handle->algorithm == ac_key_generate_specs[i].algorithm)
- genkey_format_n += 6;
- /* Create format string. */
- genkey_format = gcry_malloc (genkey_format_n);
- if (! genkey_format)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Fill format string. */
- *genkey_format = 0;
- strcat (genkey_format, "(genkey(%s(nbits%d)");
- if (key_spec)
- for (i = 0; i < DIM (ac_key_generate_specs); i++)
- if (handle->algorithm == ac_key_generate_specs[i].algorithm)
- strcat (genkey_format, "(%s%m)");
- strcat (genkey_format, "))");
- /* Build list of argument pointers, the algorithm name and the nbits
- are always needed. */
- arg_list_n = 2;
- /* Now the algorithm specific arguments. */
- if (key_spec)
- for (i = 0; i < DIM (ac_key_generate_specs); i++)
- if (handle->algorithm == ac_key_generate_specs[i].algorithm)
- arg_list_n += 2;
- /* Allocate list. */
- arg_list = gcry_calloc (arg_list_n, sizeof (*arg_list));
- if (! arg_list)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- arg_list[0] = (void *) &handle->algorithm_name;
- arg_list[1] = (void *) &nbits;
- if (key_spec)
- for (j = 2, i = 0; i < DIM (ac_key_generate_specs); i++)
- if (handle->algorithm == ac_key_generate_specs[i].algorithm)
- {
- /* Add name of this specification flag and the
- according member of the spec strucuture. */
- arg_list[j++] = (void *)(&ac_key_generate_specs[i].name);
- arg_list[j++] = (void *)
- (((char *) key_spec)
- + ac_key_generate_specs[i].offset);
- /* FIXME: above seems to suck. */
- }
- /* Construct final request S-expression. */
- err = gcry_sexp_build_array (&genkey_sexp_request,
- NULL, genkey_format, arg_list);
- if (err)
- goto out;
- /* Perform genkey operation. */
- err = gcry_pk_genkey (&genkey_sexp_reply, genkey_sexp_request);
- if (err)
- goto out;
- key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "private-key", 0);
- if (! key_sexp)
- {
- err = gcry_error (GPG_ERR_INTERNAL);
- goto out;
- }
- err = ac_data_extract ("private-key", handle->algorithm_name,
- key_sexp, &key_data_secret);
- if (err)
- goto out;
- gcry_sexp_release (key_sexp);
- key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "public-key", 0);
- if (! key_sexp)
- {
- err = gcry_error (GPG_ERR_INTERNAL);
- goto out;
- }
- err = ac_data_extract ("public-key", handle->algorithm_name,
- key_sexp, &key_data_public);
- if (err)
- goto out;
- /* Done. */
- key_secret->type = GCRY_AC_KEY_SECRET;
- key_secret->data = key_data_secret;
- key_public->type = GCRY_AC_KEY_PUBLIC;
- key_public->data = key_data_public;
- key_pair_new->secret = key_secret;
- key_pair_new->public = key_public;
- *key_pair = key_pair_new;
- out:
- /* Deallocate resources. */
- gcry_free (genkey_format);
- gcry_free (arg_list);
- gcry_sexp_release (genkey_sexp_request);
- gcry_sexp_release (genkey_sexp_reply);
- gcry_sexp_release (key_sexp);
- if (err)
- {
- _gcry_ac_data_destroy (key_data_secret);
- _gcry_ac_data_destroy (key_data_public);
- gcry_free (key_secret);
- gcry_free (key_public);
- gcry_free (key_pair_new);
- }
- return err;
- }
- /* Returns the key of type WHICH out of the key pair KEY_PAIR. */
- gcry_ac_key_t
- _gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair,
- gcry_ac_key_type_t which)
- {
- gcry_ac_key_t key;
- if (fips_mode ())
- return NULL;
- switch (which)
- {
- case GCRY_AC_KEY_SECRET:
- key = key_pair->secret;
- break;
- case GCRY_AC_KEY_PUBLIC:
- key = key_pair->public;
- break;
- default:
- key = NULL;
- break;
- }
- return key;
- }
- /* Destroys the key KEY. */
- void
- _gcry_ac_key_destroy (gcry_ac_key_t key)
- {
- unsigned int i;
- if (key)
- {
- if (key->data)
- {
- for (i = 0; i < key->data->data_n; i++)
- {
- if (key->data->data[i].mpi)
- gcry_mpi_release (key->data->data[i].mpi);
- if (key->data->data[i].name)
- gcry_free (key->data->data[i].name);
- }
- gcry_free (key->data->data);
- gcry_free (key->data);
- }
- gcry_free (key);
- }
- }
- /* Destroys the key pair KEY_PAIR. */
- void
- _gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair)
- {
- if (key_pair)
- {
- gcry_ac_key_destroy (key_pair->secret);
- gcry_ac_key_destroy (key_pair->public);
- gcry_free (key_pair);
- }
- }
- /* Returns the data set contained in the key KEY. */
- gcry_ac_data_t
- _gcry_ac_key_data_get (gcry_ac_key_t key)
- {
- if (fips_mode ())
- return NULL;
- return key->data;
- }
- /* Verifies that the key KEY is sane via HANDLE. */
- gcry_error_t
- _gcry_ac_key_test (gcry_ac_handle_t handle, gcry_ac_key_t key)
- {
- gcry_sexp_t key_sexp;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- key_sexp = NULL;
- err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
- handle->algorithm_name, key->data, &key_sexp);
- if (err)
- goto out;
- err = gcry_pk_testkey (key_sexp);
- out:
- gcry_sexp_release (key_sexp);
- return gcry_error (err);
- }
- /* Stores the number of bits of the key KEY in NBITS via HANDLE. */
- gcry_error_t
- _gcry_ac_key_get_nbits (gcry_ac_handle_t handle,
- gcry_ac_key_t key, unsigned int *nbits)
- {
- gcry_sexp_t key_sexp;
- gcry_error_t err;
- unsigned int n;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- key_sexp = NULL;
- err = ac_data_construct (ac_key_identifiers[key->type],
- 0, 0, handle->algorithm_name, key->data, &key_sexp);
- if (err)
- goto out;
- n = gcry_pk_get_nbits (key_sexp);
- if (! n)
- {
- err = gcry_error (GPG_ERR_PUBKEY_ALGO);
- goto out;
- }
- *nbits = n;
- out:
- gcry_sexp_release (key_sexp);
- return err;
- }
- /* Writes the 20 byte long key grip of the key KEY to KEY_GRIP via
- HANDLE. */
- gcry_error_t
- _gcry_ac_key_get_grip (gcry_ac_handle_t handle,
- gcry_ac_key_t key, unsigned char *key_grip)
- {
- gcry_sexp_t key_sexp;
- gcry_error_t err;
- unsigned char *ret;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- key_sexp = NULL;
- err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
- handle->algorithm_name, key->data, &key_sexp);
- if (err)
- goto out;
- ret = gcry_pk_get_keygrip (key_sexp, key_grip);
- if (! ret)
- {
- err = gcry_error (GPG_ERR_INV_OBJ);
- goto out;
- }
- err = 0;
- out:
- gcry_sexp_release (key_sexp);
- return err;
- }
- /*
- * Functions performing cryptographic operations.
- */
- /* Encrypts the plain text MPI value DATA_PLAIN with the key public
- KEY under the control of the flags FLAGS and stores the resulting
- data set into DATA_ENCRYPTED. */
- gcry_error_t
- _gcry_ac_data_encrypt (gcry_ac_handle_t handle,
- unsigned int flags,
- gcry_ac_key_t key,
- gcry_mpi_t data_plain,
- gcry_ac_data_t *data_encrypted)
- {
- gcry_ac_data_t data_encrypted_new;
- gcry_ac_data_t data_value;
- gcry_sexp_t sexp_request;
- gcry_sexp_t sexp_reply;
- gcry_sexp_t sexp_key;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_encrypted_new = NULL;
- sexp_request = NULL;
- sexp_reply = NULL;
- data_value = NULL;
- sexp_key = NULL;
- if (key->type != GCRY_AC_KEY_PUBLIC)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
- handle->algorithm_name, key->data, &sexp_key);
- if (err)
- goto out;
- err = _gcry_ac_data_new (&data_value);
- if (err)
- goto out;
- err = _gcry_ac_data_set (data_value, 0, "value", data_plain);
- if (err)
- goto out;
- err = ac_data_construct ("data", 1, flags, handle->algorithm_name,
- data_value, &sexp_request);
- if (err)
- goto out;
- /* FIXME: error vs. errcode? */
- err = gcry_pk_encrypt (&sexp_reply, sexp_request, sexp_key);
- if (err)
- goto out;
- /* Extract data. */
- err = ac_data_extract ("enc-val", handle->algorithm_name,
- sexp_reply, &data_encrypted_new);
- if (err)
- goto out;
- *data_encrypted = data_encrypted_new;
- out:
- /* Deallocate resources. */
- gcry_sexp_release (sexp_request);
- gcry_sexp_release (sexp_reply);
- gcry_sexp_release (sexp_key);
- _gcry_ac_data_destroy (data_value);
- return err;
- }
- /* Decrypts the encrypted data contained in the data set
- DATA_ENCRYPTED with the secret key KEY under the control of the
- flags FLAGS and stores the resulting plain text MPI value in
- DATA_PLAIN. */
- gcry_error_t
- _gcry_ac_data_decrypt (gcry_ac_handle_t handle,
- unsigned int flags,
- gcry_ac_key_t key,
- gcry_mpi_t *data_plain,
- gcry_ac_data_t data_encrypted)
- {
- gcry_mpi_t data_decrypted;
- gcry_sexp_t sexp_request;
- gcry_sexp_t sexp_reply;
- gcry_sexp_t sexp_value;
- gcry_sexp_t sexp_key;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- sexp_request = NULL;
- sexp_reply = NULL;
- sexp_value = NULL;
- sexp_key = NULL;
- if (key->type != GCRY_AC_KEY_SECRET)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
- handle->algorithm_name, key->data, &sexp_key);
- if (err)
- goto out;
- /* Create S-expression from data. */
- err = ac_data_construct ("enc-val", 1, flags, handle->algorithm_name,
- data_encrypted, &sexp_request);
- if (err)
- goto out;
- /* Decrypt. */
- err = gcry_pk_decrypt (&sexp_reply, sexp_request, sexp_key);
- if (err)
- goto out;
- /* Extract plain text. */
- sexp_value = gcry_sexp_find_token (sexp_reply, "value", 0);
- if (! sexp_value)
- {
- /* FIXME? */
- err = gcry_error (GPG_ERR_GENERAL);
- goto out;
- }
- data_decrypted = gcry_sexp_nth_mpi (sexp_value, 1, GCRYMPI_FMT_USG);
- if (! data_decrypted)
- {
- err = gcry_error (GPG_ERR_GENERAL);
- goto out;
- }
- *data_plain = data_decrypted;
- out:
- /* Deallocate resources. */
- gcry_sexp_release (sexp_request);
- gcry_sexp_release (sexp_reply);
- gcry_sexp_release (sexp_value);
- gcry_sexp_release (sexp_key);
- return gcry_error (err);
- }
- /* Signs the data contained in DATA with the secret key KEY and stores
- the resulting signature data set in DATA_SIGNATURE. */
- gcry_error_t
- _gcry_ac_data_sign (gcry_ac_handle_t handle,
- gcry_ac_key_t key,
- gcry_mpi_t data,
- gcry_ac_data_t *data_signature)
- {
- gcry_ac_data_t data_signed;
- gcry_ac_data_t data_value;
- gcry_sexp_t sexp_request;
- gcry_sexp_t sexp_reply;
- gcry_sexp_t sexp_key;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_signed = NULL;
- data_value = NULL;
- sexp_request = NULL;
- sexp_reply = NULL;
- sexp_key = NULL;
- if (key->type != GCRY_AC_KEY_SECRET)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- err = ac_data_construct (ac_key_identifiers[key->type], 0, 0,
- handle->algorithm_name, key->data, &sexp_key);
- if (err)
- goto out;
- err = _gcry_ac_data_new (&data_value);
- if (err)
- goto out;
- err = _gcry_ac_data_set (data_value, 0, "value", data);
- if (err)
- goto out;
- /* Create S-expression holding the data. */
- err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_request);
- if (err)
- goto out;
- /* Sign. */
- err = gcry_pk_sign (&sexp_reply, sexp_request, sexp_key);
- if (err)
- goto out;
- /* Extract data. */
- err = ac_data_extract ("sig-val", handle->algorithm_name,
- sexp_reply, &data_signed);
- if (err)
- goto out;
- /* Done. */
- *data_signature = data_signed;
- out:
- gcry_sexp_release (sexp_request);
- gcry_sexp_release (sexp_reply);
- gcry_sexp_release (sexp_key);
- _gcry_ac_data_destroy (data_value);
- return gcry_error (err);
- }
- /* Verifies that the signature contained in the data set
- DATA_SIGNATURE is indeed the result of signing the data contained
- in DATA with the secret key belonging to the public key KEY. */
- gcry_error_t
- _gcry_ac_data_verify (gcry_ac_handle_t handle,
- gcry_ac_key_t key,
- gcry_mpi_t data,
- gcry_ac_data_t data_signature)
- {
- gcry_sexp_t sexp_signature;
- gcry_ac_data_t data_value;
- gcry_sexp_t sexp_data;
- gcry_sexp_t sexp_key;
- gcry_error_t err;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- sexp_signature = NULL;
- data_value = NULL;
- sexp_data = NULL;
- sexp_key = NULL;
- err = ac_data_construct ("public-key", 0, 0,
- handle->algorithm_name, key->data, &sexp_key);
- if (err)
- goto out;
- if (key->type != GCRY_AC_KEY_PUBLIC)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- /* Construct S-expression holding the signature data. */
- err = ac_data_construct ("sig-val", 1, 0, handle->algorithm_name,
- data_signature, &sexp_signature);
- if (err)
- goto out;
- err = _gcry_ac_data_new (&data_value);
- if (err)
- goto out;
- err = _gcry_ac_data_set (data_value, 0, "value", data);
- if (err)
- goto out;
- /* Construct S-expression holding the data. */
- err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_data);
- if (err)
- goto out;
- /* Verify signature. */
- err = gcry_pk_verify (sexp_signature, sexp_data, sexp_key);
- out:
- gcry_sexp_release (sexp_signature);
- gcry_sexp_release (sexp_data);
- gcry_sexp_release (sexp_key);
- _gcry_ac_data_destroy (data_value);
- return gcry_error (err);
- }
- /*
- * Implementation of encoding methods (em).
- */
- /* Type for functions that encode or decode (hence the name) a
- message. */
- typedef gcry_error_t (*gcry_ac_em_dencode_t) (unsigned int flags,
- void *options,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write);
- /* Fill the buffer BUFFER which is BUFFER_N bytes long with non-zero
- random bytes of random level LEVEL. */
- static void
- em_randomize_nonzero (unsigned char *buffer, size_t buffer_n,
- gcry_random_level_t level)
- {
- unsigned char *buffer_rand;
- unsigned int buffer_rand_n;
- unsigned int zeros;
- unsigned int i;
- unsigned int j;
- for (i = 0; i < buffer_n; i++)
- buffer[i] = 0;
- do
- {
- /* Count zeros. */
- for (i = zeros = 0; i < buffer_n; i++)
- if (! buffer[i])
- zeros++;
- if (zeros)
- {
- /* Get random bytes. */
- buffer_rand_n = zeros + (zeros / 128);
- buffer_rand = gcry_random_bytes_secure (buffer_rand_n, level);
- /* Substitute zeros with non-zero random bytes. */
- for (i = j = 0; zeros && (i < buffer_n) && (j < buffer_rand_n); i++)
- if (! buffer[i])
- {
- while ((j < buffer_rand_n) && (! buffer_rand[j]))
- j++;
- if (j < buffer_rand_n)
- {
- buffer[i] = buffer_rand[j++];
- zeros--;
- }
- else
- break;
- }
- gcry_free (buffer_rand);
- }
- }
- while (zeros);
- }
- /* Encode a message according to the Encoding Method for Encryption
- `PKCS-V1_5' (EME-PKCS-V1_5). */
- static gcry_error_t
- eme_pkcs_v1_5_encode (unsigned int flags, void *opts,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- gcry_ac_eme_pkcs_v1_5_t *options;
- gcry_error_t err;
- unsigned char *buffer;
- unsigned char *ps;
- unsigned char *m;
- size_t m_n;
- unsigned int ps_n;
- unsigned int k;
- (void)flags;
- options = opts;
- buffer = NULL;
- m = NULL;
- err = _gcry_ac_io_read_all (ac_io_read, &m, &m_n);
- if (err)
- goto out;
- /* Figure out key length in bytes. */
- k = options->key_size / 8;
- if (m_n > k - 11)
- {
- /* Key is too short for message. */
- err = gcry_error (GPG_ERR_TOO_SHORT);
- goto out;
- }
- /* According to this encoding method, the first byte of the encoded
- message is zero. This byte will be lost anyway, when the encoded
- message is to be converted into an MPI, that's why we skip
- it. */
- /* Allocate buffer. */
- buffer = gcry_malloc (k - 1);
- if (! buffer)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- /* Generate an octet string PS of length k - mLen - 3 consisting
- of pseudorandomly generated nonzero octets. The length of PS
- will be at least eight octets. */
- ps_n = k - m_n - 3;
- ps = buffer + 1;
- em_randomize_nonzero (ps, ps_n, GCRY_STRONG_RANDOM);
- /* Concatenate PS, the message M, and other padding to form an
- encoded message EM of length k octets as:
- EM = 0x00 || 0x02 || PS || 0x00 || M. */
- buffer[0] = 0x02;
- buffer[ps_n + 1] = 0x00;
- memcpy (buffer + ps_n + 2, m, m_n);
- err = _gcry_ac_io_write (ac_io_write, buffer, k - 1);
- out:
- gcry_free (buffer);
- gcry_free (m);
- return err;
- }
- /* Decode a message according to the Encoding Method for Encryption
- `PKCS-V1_5' (EME-PKCS-V1_5). */
- static gcry_error_t
- eme_pkcs_v1_5_decode (unsigned int flags, void *opts,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- gcry_ac_eme_pkcs_v1_5_t *options;
- unsigned char *buffer;
- unsigned char *em;
- size_t em_n;
- gcry_error_t err;
- unsigned int i;
- unsigned int k;
- (void)flags;
- options = opts;
- buffer = NULL;
- em = NULL;
- err = _gcry_ac_io_read_all (ac_io_read, &em, &em_n);
- if (err)
- goto out;
- /* Figure out key size. */
- k = options->key_size / 8;
- /* Search for zero byte. */
- for (i = 0; (i < em_n) && em[i]; i++);
- /* According to this encoding method, the first byte of the encoded
- message should be zero. This byte is lost. */
- if (! ((em_n >= 10)
- && (em_n == (k - 1))
- && (em[0] == 0x02)
- && (i < em_n)
- && ((i - 1) >= 8)))
- {
- err = gcry_error (GPG_ERR_DECRYPT_FAILED);
- goto out;
- }
- i++;
- buffer = gcry_malloc (em_n - i);
- if (! buffer)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- memcpy (buffer, em + i, em_n - i);
- err = _gcry_ac_io_write (ac_io_write, buffer, em_n - i);
- out:
- gcry_free (buffer);
- gcry_free (em);
- return err;
- }
- static gcry_error_t
- emsa_pkcs_v1_5_encode_data_cb (void *opaque,
- unsigned char *buffer, size_t buffer_n)
- {
- gcry_md_hd_t md_handle;
- md_handle = opaque;
- gcry_md_write (md_handle, buffer, buffer_n);
- return 0;
- }
- /* Encode a message according to the Encoding Method for Signatures
- with Appendix `PKCS-V1_5' (EMSA-PKCS-V1_5). */
- static gcry_error_t
- emsa_pkcs_v1_5_encode (unsigned int flags, void *opts,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- gcry_ac_emsa_pkcs_v1_5_t *options;
- gcry_error_t err;
- gcry_md_hd_t md;
- unsigned char *t;
- size_t t_n;
- unsigned char *h;
- size_t h_n;
- unsigned char *ps;
- size_t ps_n;
- unsigned char *buffer;
- size_t buffer_n;
- unsigned char asn[100]; /* FIXME, always enough? */
- size_t asn_n;
- unsigned int i;
- (void)flags;
- options = opts;
- buffer = NULL;
- md = NULL;
- ps = NULL;
- t = NULL;
- /* Create hashing handle and get the necessary information. */
- err = gcry_md_open (&md, options->md, 0);
- if (err)
- goto out;
- asn_n = DIM (asn);
- err = gcry_md_algo_info (options->md, GCRYCTL_GET_ASNOID, asn, &asn_n);
- if (err)
- goto out;
- h_n = gcry_md_get_algo_dlen (options->md);
- err = _gcry_ac_io_process (ac_io_read, emsa_pkcs_v1_5_encode_data_cb, md);
- if (err)
- goto out;
- h = gcry_md_read (md, 0);
- /* Encode the algorithm ID for the hash function and the hash value
- into an ASN.1 value of type DigestInfo with the Distinguished
- Encoding Rules (DER), where the type DigestInfo has the syntax:
- DigestInfo ::== SEQUENCE {
- digestAlgorithm AlgorithmIdentifier,
- digest OCTET STRING
- }
- The first field identifies the hash function and the second
- contains the hash value. Let T be the DER encoding of the
- DigestInfo value and let tLen be the length in octets of T. */
- t_n = asn_n + h_n;
- t = gcry_malloc (t_n);
- if (! t)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- for (i = 0; i < asn_n; i++)
- t[i] = asn[i];
- for (i = 0; i < h_n; i++)
- t[asn_n + i] = h[i];
- /* If emLen < tLen + 11, output "intended encoded message length
- too short" and stop. */
- if (options->em_n < t_n + 11)
- {
- err = gcry_error (GPG_ERR_TOO_SHORT);
- goto out;
- }
- /* Generate an octet string PS consisting of emLen - tLen - 3 octets
- with hexadecimal value 0xFF. The length of PS will be at least 8
- octets. */
- ps_n = options->em_n - t_n - 3;
- ps = gcry_malloc (ps_n);
- if (! ps)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- for (i = 0; i < ps_n; i++)
- ps[i] = 0xFF;
- /* Concatenate PS, the DER encoding T, and other padding to form the
- encoded message EM as:
- EM = 0x00 || 0x01 || PS || 0x00 || T. */
- buffer_n = ps_n + t_n + 3;
- buffer = gcry_malloc (buffer_n);
- if (! buffer)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- buffer[0] = 0x00;
- buffer[1] = 0x01;
- for (i = 0; i < ps_n; i++)
- buffer[2 + i] = ps[i];
- buffer[2 + ps_n] = 0x00;
- for (i = 0; i < t_n; i++)
- buffer[3 + ps_n + i] = t[i];
- err = _gcry_ac_io_write (ac_io_write, buffer, buffer_n);
- out:
- gcry_md_close (md);
- gcry_free (buffer);
- gcry_free (ps);
- gcry_free (t);
- return err;
- }
- /* `Actions' for data_dencode(). */
- typedef enum dencode_action
- {
- DATA_ENCODE,
- DATA_DECODE,
- }
- dencode_action_t;
- /* Encode or decode a message according to the the encoding method
- METHOD; ACTION specifies whether the message that is contained in
- BUFFER_IN and of length BUFFER_IN_N should be encoded or decoded.
- The resulting message will be stored in a newly allocated buffer in
- BUFFER_OUT and BUFFER_OUT_N. */
- static gcry_error_t
- ac_data_dencode (gcry_ac_em_t method, dencode_action_t action,
- unsigned int flags, void *options,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- struct
- {
- gcry_ac_em_t method;
- gcry_ac_em_dencode_t encode;
- gcry_ac_em_dencode_t decode;
- } methods[] =
- {
- { GCRY_AC_EME_PKCS_V1_5,
- eme_pkcs_v1_5_encode, eme_pkcs_v1_5_decode },
- { GCRY_AC_EMSA_PKCS_V1_5,
- emsa_pkcs_v1_5_encode, NULL },
- };
- size_t methods_n;
- gcry_error_t err;
- unsigned int i;
- methods_n = sizeof (methods) / sizeof (*methods);
- for (i = 0; i < methods_n; i++)
- if (methods[i].method == method)
- break;
- if (i == methods_n)
- {
- err = gcry_error (GPG_ERR_NOT_FOUND); /* FIXME? */
- goto out;
- }
- err = 0;
- switch (action)
- {
- case DATA_ENCODE:
- if (methods[i].encode)
- /* FIXME? */
- err = (*methods[i].encode) (flags, options, ac_io_read, ac_io_write);
- break;
- case DATA_DECODE:
- if (methods[i].decode)
- /* FIXME? */
- err = (*methods[i].decode) (flags, options, ac_io_read, ac_io_write);
- break;
- default:
- err = gcry_error (GPG_ERR_INV_ARG);
- break;
- }
- out:
- return err;
- }
- /* Encode a message according to the encoding method METHOD. OPTIONS
- must be a pointer to a method-specific structure
- (gcry_ac_em*_t). */
- gcry_error_t
- _gcry_ac_data_encode (gcry_ac_em_t method,
- unsigned int flags, void *options,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- return ac_data_dencode (method, DATA_ENCODE, flags, options,
- ac_io_read, ac_io_write);
- }
- /* Dencode a message according to the encoding method METHOD. OPTIONS
- must be a pointer to a method-specific structure
- (gcry_ac_em*_t). */
- gcry_error_t
- _gcry_ac_data_decode (gcry_ac_em_t method,
- unsigned int flags, void *options,
- gcry_ac_io_t *ac_io_read,
- gcry_ac_io_t *ac_io_write)
- {
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- return ac_data_dencode (method, DATA_DECODE, flags, options,
- ac_io_read, ac_io_write);
- }
- /* Convert an MPI into an octet string. */
- void
- _gcry_ac_mpi_to_os (gcry_mpi_t mpi, unsigned char *os, size_t os_n)
- {
- unsigned long digit;
- gcry_mpi_t base;
- unsigned int i;
- unsigned int n;
- gcry_mpi_t m;
- gcry_mpi_t d;
- if (fips_mode ())
- return;
- base = gcry_mpi_new (0);
- gcry_mpi_set_ui (base, 256);
- n = 0;
- m = gcry_mpi_copy (mpi);
- while (gcry_mpi_cmp_ui (m, 0))
- {
- n++;
- gcry_mpi_div (m, NULL, m, base, 0);
- }
- gcry_mpi_set (m, mpi);
- d = gcry_mpi_new (0);
- for (i = 0; (i < n) && (i < os_n); i++)
- {
- gcry_mpi_mod (d, m, base);
- _gcry_mpi_get_ui (d, &digit);
- gcry_mpi_div (m, NULL, m, base, 0);
- os[os_n - i - 1] = (digit & 0xFF);
- }
- for (; i < os_n; i++)
- os[os_n - i - 1] = 0;
- gcry_mpi_release (base);
- gcry_mpi_release (d);
- gcry_mpi_release (m);
- }
- /* Convert an MPI into an newly allocated octet string. */
- gcry_error_t
- _gcry_ac_mpi_to_os_alloc (gcry_mpi_t mpi, unsigned char **os, size_t *os_n)
- {
- unsigned char *buffer;
- size_t buffer_n;
- gcry_error_t err;
- unsigned int nbits;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- nbits = gcry_mpi_get_nbits (mpi);
- buffer_n = (nbits + 7) / 8;
- buffer = gcry_malloc (buffer_n);
- if (! buffer)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- _gcry_ac_mpi_to_os (mpi, buffer, buffer_n);
- *os = buffer;
- *os_n = buffer_n;
- err = 0;
- out:
- return err;
- }
- /* Convert an octet string into an MPI. */
- void
- _gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n)
- {
- unsigned int i;
- gcry_mpi_t xi;
- gcry_mpi_t x;
- gcry_mpi_t a;
- if (fips_mode ())
- return;
- a = gcry_mpi_new (0);
- gcry_mpi_set_ui (a, 1);
- x = gcry_mpi_new (0);
- gcry_mpi_set_ui (x, 0);
- xi = gcry_mpi_new (0);
- for (i = 0; i < os_n; i++)
- {
- gcry_mpi_mul_ui (xi, a, os[os_n - i - 1]);
- gcry_mpi_add (x, x, xi);
- gcry_mpi_mul_ui (a, a, 256);
- }
- gcry_mpi_release (xi);
- gcry_mpi_release (a);
- gcry_mpi_set (mpi, x);
- gcry_mpi_release (x); /* FIXME: correct? */
- }
- /*
- * Implementation of Encryption Schemes (ES) and Signature Schemes
- * with Appendix (SSA).
- */
- /* Schemes consist of two things: encoding methods and cryptographic
- primitives.
- Since encoding methods are accessible through a common API with
- method-specific options passed as an anonymous struct, schemes have
- to provide functions that construct this method-specific structure;
- this is what the functions of type `gcry_ac_dencode_prepare_t' are
- there for. */
- typedef gcry_error_t (*gcry_ac_dencode_prepare_t) (gcry_ac_handle_t handle,
- gcry_ac_key_t key,
- void *opts,
- void *opts_em);
- /* The `dencode_prepare' function for ES-PKCS-V1_5. */
- static gcry_error_t
- ac_es_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key,
- void *opts, void *opts_em)
- {
- gcry_ac_eme_pkcs_v1_5_t *options_em;
- unsigned int nbits;
- gcry_error_t err;
- (void)opts;
- err = _gcry_ac_key_get_nbits (handle, key, &nbits);
- if (err)
- goto out;
- options_em = opts_em;
- options_em->key_size = nbits;
- out:
- return err;
- }
- /* The `dencode_prepare' function for SSA-PKCS-V1_5. */
- static gcry_error_t
- ac_ssa_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key,
- void *opts, void *opts_em)
- {
- gcry_ac_emsa_pkcs_v1_5_t *options_em;
- gcry_ac_ssa_pkcs_v1_5_t *options;
- gcry_error_t err;
- unsigned int k;
- options_em = opts_em;
- options = opts;
- err = _gcry_ac_key_get_nbits (handle, key, &k);
- if (err)
- goto out;
- k = (k + 7) / 8;
- options_em->md = options->md;
- options_em->em_n = k;
- out:
- return err;
- }
- /* Type holding the information about each supported
- Encryption/Signature Scheme. */
- typedef struct ac_scheme
- {
- gcry_ac_scheme_t scheme;
- gcry_ac_em_t scheme_encoding;
- gcry_ac_dencode_prepare_t dencode_prepare;
- size_t options_em_n;
- } ac_scheme_t;
- /* List of supported Schemes. */
- static ac_scheme_t ac_schemes[] =
- {
- { GCRY_AC_ES_PKCS_V1_5, GCRY_AC_EME_PKCS_V1_5,
- ac_es_dencode_prepare_pkcs_v1_5,
- sizeof (gcry_ac_eme_pkcs_v1_5_t) },
- { GCRY_AC_SSA_PKCS_V1_5, GCRY_AC_EMSA_PKCS_V1_5,
- ac_ssa_dencode_prepare_pkcs_v1_5,
- sizeof (gcry_ac_emsa_pkcs_v1_5_t) }
- };
- /* Lookup a scheme by it's ID. */
- static ac_scheme_t *
- ac_scheme_get (gcry_ac_scheme_t scheme)
- {
- ac_scheme_t *ac_scheme;
- unsigned int i;
- for (i = 0; i < DIM (ac_schemes); i++)
- if (scheme == ac_schemes[i].scheme)
- break;
- if (i == DIM (ac_schemes))
- ac_scheme = NULL;
- else
- ac_scheme = ac_schemes + i;
- return ac_scheme;
- }
- /* Prepares the encoding/decoding by creating an according option
- structure. */
- static gcry_error_t
- ac_dencode_prepare (gcry_ac_handle_t handle, gcry_ac_key_t key, void *opts,
- ac_scheme_t scheme, void **opts_em)
- {
- gcry_error_t err;
- void *options_em;
- options_em = gcry_malloc (scheme.options_em_n);
- if (! options_em)
- {
- err = gcry_error_from_errno (errno);
- goto out;
- }
- err = (*scheme.dencode_prepare) (handle, key, opts, options_em);
- if (err)
- goto out;
- *opts_em = options_em;
- out:
- if (err)
- free (options_em);
- return err;
- }
- /* Convert a data set into a single MPI; currently, this is only
- supported for data sets containing a single MPI. */
- static gcry_error_t
- ac_data_set_to_mpi (gcry_ac_data_t data, gcry_mpi_t *mpi)
- {
- gcry_error_t err;
- gcry_mpi_t mpi_new;
- unsigned int elems;
- elems = _gcry_ac_data_length (data);
- if (elems != 1)
- {
- /* FIXME: I guess, we should be more flexible in this respect by
- allowing the actual encryption/signature schemes to implement
- this conversion mechanism. */
- err = gcry_error (GPG_ERR_CONFLICT);
- goto out;
- }
- err = _gcry_ac_data_get_index (data, GCRY_AC_FLAG_COPY, 0, NULL, &mpi_new);
- if (err)
- goto out;
- *mpi = mpi_new;
- out:
- return err;
- }
- /* Encrypts the plain text message contained in M, which is of size
- M_N, with the public key KEY_PUBLIC according to the Encryption
- Scheme SCHEME_ID. HANDLE is used for accessing the low-level
- cryptographic primitives. If OPTS is not NULL, it has to be an
- anonymous structure specific to the chosen scheme (gcry_ac_es_*_t).
- The encrypted message will be stored in C and C_N. */
- gcry_error_t
- _gcry_ac_data_encrypt_scheme (gcry_ac_handle_t handle,
- gcry_ac_scheme_t scheme_id,
- unsigned int flags, void *opts,
- gcry_ac_key_t key,
- gcry_ac_io_t *io_message,
- gcry_ac_io_t *io_cipher)
- {
- gcry_error_t err;
- gcry_ac_io_t io_em;
- unsigned char *em;
- size_t em_n;
- gcry_mpi_t mpi_plain;
- gcry_ac_data_t data_encrypted;
- gcry_mpi_t mpi_encrypted;
- unsigned char *buffer;
- size_t buffer_n;
- void *opts_em;
- ac_scheme_t *scheme;
- (void)flags;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_encrypted = NULL;
- mpi_encrypted = NULL;
- mpi_plain = NULL;
- opts_em = NULL;
- buffer = NULL;
- em = NULL;
- scheme = ac_scheme_get (scheme_id);
- if (! scheme)
- {
- err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME);
- goto out;
- }
- if (key->type != GCRY_AC_KEY_PUBLIC)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em);
- if (err)
- goto out;
- _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE,
- GCRY_AC_IO_STRING, &em, &em_n);
- err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em,
- io_message, &io_em);
- if (err)
- goto out;
- mpi_plain = gcry_mpi_snew (0);
- gcry_ac_os_to_mpi (mpi_plain, em, em_n);
- err = _gcry_ac_data_encrypt (handle, 0, key, mpi_plain, &data_encrypted);
- if (err)
- goto out;
- err = ac_data_set_to_mpi (data_encrypted, &mpi_encrypted);
- if (err)
- goto out;
- err = _gcry_ac_mpi_to_os_alloc (mpi_encrypted, &buffer, &buffer_n);
- if (err)
- goto out;
- err = _gcry_ac_io_write (io_cipher, buffer, buffer_n);
- out:
- gcry_ac_data_destroy (data_encrypted);
- gcry_mpi_release (mpi_encrypted);
- gcry_mpi_release (mpi_plain);
- gcry_free (opts_em);
- gcry_free (buffer);
- gcry_free (em);
- return err;
- }
- /* Decryptes the cipher message contained in C, which is of size C_N,
- with the secret key KEY_SECRET according to the Encryption Scheme
- SCHEME_ID. Handle is used for accessing the low-level
- cryptographic primitives. If OPTS is not NULL, it has to be an
- anonymous structure specific to the chosen scheme (gcry_ac_es_*_t).
- The decrypted message will be stored in M and M_N. */
- gcry_error_t
- _gcry_ac_data_decrypt_scheme (gcry_ac_handle_t handle,
- gcry_ac_scheme_t scheme_id,
- unsigned int flags, void *opts,
- gcry_ac_key_t key,
- gcry_ac_io_t *io_cipher,
- gcry_ac_io_t *io_message)
- {
- gcry_ac_io_t io_em;
- gcry_error_t err;
- gcry_ac_data_t data_encrypted;
- unsigned char *em;
- size_t em_n;
- gcry_mpi_t mpi_encrypted;
- gcry_mpi_t mpi_decrypted;
- void *opts_em;
- ac_scheme_t *scheme;
- char *elements_enc;
- size_t elements_enc_n;
- unsigned char *c;
- size_t c_n;
- (void)flags;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_encrypted = NULL;
- mpi_encrypted = NULL;
- mpi_decrypted = NULL;
- elements_enc = NULL;
- opts_em = NULL;
- em = NULL;
- c = NULL;
- scheme = ac_scheme_get (scheme_id);
- if (! scheme)
- {
- err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME);
- goto out;
- }
- if (key->type != GCRY_AC_KEY_SECRET)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- err = _gcry_ac_io_read_all (io_cipher, &c, &c_n);
- if (err)
- goto out;
- mpi_encrypted = gcry_mpi_snew (0);
- gcry_ac_os_to_mpi (mpi_encrypted, c, c_n);
- err = _gcry_pk_get_elements (handle->algorithm, &elements_enc, NULL);
- if (err)
- goto out;
- elements_enc_n = strlen (elements_enc);
- if (elements_enc_n != 1)
- {
- /* FIXME? */
- err = gcry_error (GPG_ERR_CONFLICT);
- goto out;
- }
- err = _gcry_ac_data_new (&data_encrypted);
- if (err)
- goto out;
- err = _gcry_ac_data_set (data_encrypted, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC,
- elements_enc, mpi_encrypted);
- if (err)
- goto out;
- err = _gcry_ac_data_decrypt (handle, 0, key, &mpi_decrypted, data_encrypted);
- if (err)
- goto out;
- err = _gcry_ac_mpi_to_os_alloc (mpi_decrypted, &em, &em_n);
- if (err)
- goto out;
- err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em);
- if (err)
- goto out;
- _gcry_ac_io_init (&io_em, GCRY_AC_IO_READABLE,
- GCRY_AC_IO_STRING, em, em_n);
- err = _gcry_ac_data_decode (scheme->scheme_encoding, 0, opts_em,
- &io_em, io_message);
- if (err)
- goto out;
- out:
- _gcry_ac_data_destroy (data_encrypted);
- gcry_mpi_release (mpi_encrypted);
- gcry_mpi_release (mpi_decrypted);
- free (elements_enc);
- gcry_free (opts_em);
- gcry_free (em);
- gcry_free (c);
- return err;
- }
- /* Signs the message contained in M, which is of size M_N, with the
- secret key KEY according to the Signature Scheme SCHEME_ID. Handle
- is used for accessing the low-level cryptographic primitives. If
- OPTS is not NULL, it has to be an anonymous structure specific to
- the chosen scheme (gcry_ac_ssa_*_t). The signed message will be
- stored in S and S_N. */
- gcry_error_t
- _gcry_ac_data_sign_scheme (gcry_ac_handle_t handle,
- gcry_ac_scheme_t scheme_id,
- unsigned int flags, void *opts,
- gcry_ac_key_t key,
- gcry_ac_io_t *io_message,
- gcry_ac_io_t *io_signature)
- {
- gcry_ac_io_t io_em;
- gcry_error_t err;
- gcry_ac_data_t data_signed;
- unsigned char *em;
- size_t em_n;
- gcry_mpi_t mpi;
- void *opts_em;
- unsigned char *buffer;
- size_t buffer_n;
- gcry_mpi_t mpi_signed;
- ac_scheme_t *scheme;
- (void)flags;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- data_signed = NULL;
- mpi_signed = NULL;
- opts_em = NULL;
- buffer = NULL;
- mpi = NULL;
- em = NULL;
- if (key->type != GCRY_AC_KEY_SECRET)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- scheme = ac_scheme_get (scheme_id);
- if (! scheme)
- {
- /* FIXME: adjust api of scheme_get in respect to err codes. */
- err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME);
- goto out;
- }
- err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em);
- if (err)
- goto out;
- _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE,
- GCRY_AC_IO_STRING, &em, &em_n);
- err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em,
- io_message, &io_em);
- if (err)
- goto out;
- mpi = gcry_mpi_new (0);
- _gcry_ac_os_to_mpi (mpi, em, em_n);
- err = _gcry_ac_data_sign (handle, key, mpi, &data_signed);
- if (err)
- goto out;
- err = ac_data_set_to_mpi (data_signed, &mpi_signed);
- if (err)
- goto out;
- err = _gcry_ac_mpi_to_os_alloc (mpi_signed, &buffer, &buffer_n);
- if (err)
- goto out;
- err = _gcry_ac_io_write (io_signature, buffer, buffer_n);
- out:
- _gcry_ac_data_destroy (data_signed);
- gcry_mpi_release (mpi_signed);
- gcry_mpi_release (mpi);
- gcry_free (opts_em);
- gcry_free (buffer);
- gcry_free (em);
- return err;
- }
- /* Verifies that the signature contained in S, which is of length S_N,
- is indeed the result of signing the message contained in M, which
- is of size M_N, with the secret key belonging to the public key
- KEY_PUBLIC. If OPTS is not NULL, it has to be an anonymous
- structure (gcry_ac_ssa_*_t) specific to the Signature Scheme, whose
- ID is contained in SCHEME_ID. */
- gcry_error_t
- _gcry_ac_data_verify_scheme (gcry_ac_handle_t handle,
- gcry_ac_scheme_t scheme_id,
- unsigned int flags, void *opts,
- gcry_ac_key_t key,
- gcry_ac_io_t *io_message,
- gcry_ac_io_t *io_signature)
- {
- gcry_ac_io_t io_em;
- gcry_error_t err;
- gcry_ac_data_t data_signed;
- unsigned char *em;
- size_t em_n;
- void *opts_em;
- gcry_mpi_t mpi_signature;
- gcry_mpi_t mpi_data;
- ac_scheme_t *scheme;
- char *elements_sig;
- size_t elements_sig_n;
- unsigned char *s;
- size_t s_n;
- (void)flags;
- if (fips_mode ())
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
- mpi_signature = NULL;
- elements_sig = NULL;
- data_signed = NULL;
- mpi_data = NULL;
- opts_em = NULL;
- em = NULL;
- s = NULL;
- if (key->type != GCRY_AC_KEY_PUBLIC)
- {
- err = gcry_error (GPG_ERR_WRONG_KEY_USAGE);
- goto out;
- }
- scheme = ac_scheme_get (scheme_id);
- if (! scheme)
- {
- err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME);
- goto out;
- }
- err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em);
- if (err)
- goto out;
- _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE,
- GCRY_AC_IO_STRING, &em, &em_n);
- err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em,
- io_message, &io_em);
- if (err)
- goto out;
- mpi_data = gcry_mpi_new (0);
- _gcry_ac_os_to_mpi (mpi_data, em, em_n);
- err = _gcry_ac_io_read_all (io_signature, &s, &s_n);
- if (err)
- goto out;
- mpi_signature = gcry_mpi_new (0);
- _gcry_ac_os_to_mpi (mpi_signature, s, s_n);
- err = _gcry_pk_get_elements (handle->algorithm, NULL, &elements_sig);
- if (err)
- goto out;
- elements_sig_n = strlen (elements_sig);
- if (elements_sig_n != 1)
- {
- /* FIXME? */
- err = gcry_error (GPG_ERR_CONFLICT);
- goto out;
- }
- err = _gcry_ac_data_new (&data_signed);
- if (err)
- goto out;
- err = _gcry_ac_data_set (data_signed, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC,
- elements_sig, mpi_signature);
- if (err)
- goto out;
- gcry_mpi_release (mpi_signature);
- mpi_signature = NULL;
- err = _gcry_ac_data_verify (handle, key, mpi_data, data_signed);
- out:
- _gcry_ac_data_destroy (data_signed);
- gcry_mpi_release (mpi_signature);
- gcry_mpi_release (mpi_data);
- free (elements_sig);
- gcry_free (opts_em);
- gcry_free (em);
- gcry_free (s);
- return err;
- }
- /*
- * General functions.
- */
- gcry_err_code_t
- _gcry_ac_init (void)
- {
- if (fips_mode ())
- return GPG_ERR_NOT_SUPPORTED;
- return 0;
- }
|