CryptoAlgorithms.cpp 235 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647
  1. /*
  2. * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
  3. * Copyright (c) 2024, stelar7 <dudedbz@gmail.com>
  4. * Copyright (c) 2024, Jelle Raaijmakers <jelle@ladybird.org>
  5. * Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include <AK/Base64.h>
  10. #include <AK/HashTable.h>
  11. #include <AK/QuickSort.h>
  12. #include <LibCrypto/ASN1/ASN1.h>
  13. #include <LibCrypto/ASN1/DER.h>
  14. #include <LibCrypto/Authentication/HMAC.h>
  15. #include <LibCrypto/Certificate/Certificate.h>
  16. #include <LibCrypto/Cipher/AES.h>
  17. #include <LibCrypto/Curves/Ed25519.h>
  18. #include <LibCrypto/Curves/SECPxxxr1.h>
  19. #include <LibCrypto/Curves/X25519.h>
  20. #include <LibCrypto/Curves/X448.h>
  21. #include <LibCrypto/Hash/HKDF.h>
  22. #include <LibCrypto/Hash/HashManager.h>
  23. #include <LibCrypto/Hash/MGF.h>
  24. #include <LibCrypto/Hash/PBKDF2.h>
  25. #include <LibCrypto/Hash/SHA1.h>
  26. #include <LibCrypto/Hash/SHA2.h>
  27. #include <LibCrypto/PK/RSA.h>
  28. #include <LibCrypto/Padding/OAEP.h>
  29. #include <LibJS/Runtime/Array.h>
  30. #include <LibJS/Runtime/ArrayBuffer.h>
  31. #include <LibJS/Runtime/DataView.h>
  32. #include <LibJS/Runtime/TypedArray.h>
  33. #include <LibWeb/Crypto/CryptoAlgorithms.h>
  34. #include <LibWeb/Crypto/KeyAlgorithms.h>
  35. #include <LibWeb/Crypto/SubtleCrypto.h>
  36. #include <LibWeb/WebIDL/AbstractOperations.h>
  37. namespace Web::Crypto {
  38. static JS::ThrowCompletionOr<HashAlgorithmIdentifier> hash_algorithm_identifier_from_value(JS::VM& vm, JS::Value hash_value)
  39. {
  40. if (hash_value.is_string()) {
  41. auto hash_string = TRY(hash_value.to_string(vm));
  42. return HashAlgorithmIdentifier { hash_string };
  43. }
  44. auto hash_object = TRY(hash_value.to_object(vm));
  45. return HashAlgorithmIdentifier { hash_object };
  46. }
  47. // https://w3c.github.io/webcrypto/#concept-usage-intersection
  48. static Vector<Bindings::KeyUsage> usage_intersection(ReadonlySpan<Bindings::KeyUsage> a, ReadonlySpan<Bindings::KeyUsage> b)
  49. {
  50. Vector<Bindings::KeyUsage> result;
  51. for (auto const& usage : a) {
  52. if (b.contains_slow(usage))
  53. result.append(usage);
  54. }
  55. quick_sort(result);
  56. return result;
  57. }
  58. // Out of line to ensure this class has a key function
  59. AlgorithmMethods::~AlgorithmMethods() = default;
  60. // https://w3c.github.io/webcrypto/#big-integer
  61. static ::Crypto::UnsignedBigInteger big_integer_from_api_big_integer(GC::Ptr<JS::Uint8Array> const& big_integer)
  62. {
  63. // The BigInteger typedef is a Uint8Array that holds an arbitrary magnitude unsigned integer
  64. // **in big-endian order**. Values read from the API SHALL have minimal typed array length
  65. // (that is, at most 7 leading zero bits, except the value 0 which shall have length 8 bits).
  66. // The API SHALL accept values with any number of leading zero bits, including the empty array, which represents zero.
  67. auto const& buffer = big_integer->viewed_array_buffer()->buffer();
  68. ::Crypto::UnsignedBigInteger result(0);
  69. if (buffer.size() > 0) {
  70. if constexpr (AK::HostIsLittleEndian) {
  71. // We need to reverse the buffer to get it into little-endian order
  72. Vector<u8, 32> reversed_buffer;
  73. reversed_buffer.resize(buffer.size());
  74. for (size_t i = 0; i < buffer.size(); ++i) {
  75. reversed_buffer[buffer.size() - i - 1] = buffer[i];
  76. }
  77. return ::Crypto::UnsignedBigInteger::import_data(reversed_buffer.data(), reversed_buffer.size());
  78. } else {
  79. return ::Crypto::UnsignedBigInteger::import_data(buffer.data(), buffer.size());
  80. }
  81. }
  82. return ::Crypto::UnsignedBigInteger(0);
  83. }
  84. // https://www.rfc-editor.org/rfc/rfc7518#section-2
  85. ErrorOr<String> base64_url_uint_encode(::Crypto::UnsignedBigInteger integer)
  86. {
  87. // The representation of a positive or zero integer value as the
  88. // base64url encoding of the value's unsigned big-endian
  89. // representation as an octet sequence. The octet sequence MUST
  90. // utilize the minimum number of octets needed to represent the
  91. // value. Zero is represented as BASE64URL(single zero-valued
  92. // octet), which is "AA".
  93. auto bytes = TRY(ByteBuffer::create_uninitialized(integer.trimmed_byte_length()));
  94. bool const remove_leading_zeroes = true;
  95. auto data_size = integer.export_data(bytes.span(), remove_leading_zeroes);
  96. auto data_slice_be = bytes.bytes().slice(bytes.size() - data_size, data_size);
  97. String encoded;
  98. if constexpr (AK::HostIsLittleEndian) {
  99. // We need to encode the integer's big endian representation as a base64 string
  100. Vector<u8, 32> data_slice_cpu;
  101. data_slice_cpu.ensure_capacity(data_size);
  102. for (size_t i = 0; i < data_size; ++i) {
  103. data_slice_cpu.append(data_slice_be[data_size - i - 1]);
  104. }
  105. encoded = TRY(encode_base64url(data_slice_cpu));
  106. } else {
  107. encoded = TRY(encode_base64url(data_slice_be));
  108. }
  109. // FIXME: create a version of encode_base64url that omits padding bytes
  110. if (auto first_padding_byte = encoded.find_byte_offset('='); first_padding_byte.has_value())
  111. return encoded.substring_from_byte_offset(0, first_padding_byte.value());
  112. return encoded;
  113. }
  114. WebIDL::ExceptionOr<ByteBuffer> base64_url_bytes_decode(JS::Realm& realm, String const& base64_url_string)
  115. {
  116. auto& vm = realm.vm();
  117. // FIXME: Create a version of decode_base64url that ignores padding inconsistencies
  118. auto padded_string = base64_url_string;
  119. if (padded_string.byte_count() % 4 != 0) {
  120. padded_string = TRY_OR_THROW_OOM(vm, String::formatted("{}{}", padded_string, TRY_OR_THROW_OOM(vm, String::repeated('=', 4 - (padded_string.byte_count() % 4)))));
  121. }
  122. auto base64_bytes_or_error = decode_base64url(padded_string);
  123. if (base64_bytes_or_error.is_error()) {
  124. if (base64_bytes_or_error.error().code() == ENOMEM)
  125. return vm.throw_completion<JS::InternalError>(vm.error_message(::JS::VM::ErrorMessage::OutOfMemory));
  126. return WebIDL::DataError::create(realm, MUST(String::formatted("base64 decode: {}", base64_bytes_or_error.release_error())));
  127. }
  128. return base64_bytes_or_error.release_value();
  129. }
  130. WebIDL::ExceptionOr<::Crypto::UnsignedBigInteger> base64_url_uint_decode(JS::Realm& realm, String const& base64_url_string)
  131. {
  132. auto base64_bytes_be = TRY(base64_url_bytes_decode(realm, base64_url_string));
  133. if constexpr (AK::HostIsLittleEndian) {
  134. // We need to swap the integer's big-endian representation to little endian in order to import it
  135. Vector<u8, 32> base64_bytes_cpu;
  136. base64_bytes_cpu.ensure_capacity(base64_bytes_be.size());
  137. for (size_t i = 0; i < base64_bytes_be.size(); ++i) {
  138. base64_bytes_cpu.append(base64_bytes_be[base64_bytes_be.size() - i - 1]);
  139. }
  140. return ::Crypto::UnsignedBigInteger::import_data(base64_bytes_cpu.data(), base64_bytes_cpu.size());
  141. } else {
  142. return ::Crypto::UnsignedBigInteger::import_data(base64_bytes_be.data(), base64_bytes_be.size());
  143. }
  144. }
  145. // https://w3c.github.io/webcrypto/#concept-parse-an-asn1-structure
  146. template<typename Structure>
  147. static WebIDL::ExceptionOr<Structure> parse_an_ASN1_structure(JS::Realm& realm, ReadonlyBytes data, bool exact_data = true)
  148. {
  149. // 1. Let data be a sequence of bytes to be parsed.
  150. // 2. Let structure be the ASN.1 structure to be parsed.
  151. // 3. Let exactData be an optional boolean value. If it is not supplied, let it be initialized to true.
  152. // 4. Parse data according to the Distinguished Encoding Rules of [X690], using structure as the ASN.1 structure to be decoded.
  153. ::Crypto::ASN1::Decoder decoder(data);
  154. Structure structure;
  155. if constexpr (IsSame<Structure, ::Crypto::Certificate::SubjectPublicKey>) {
  156. auto maybe_subject_public_key = ::Crypto::Certificate::parse_subject_public_key_info(decoder);
  157. if (maybe_subject_public_key.is_error())
  158. return WebIDL::DataError::create(realm, MUST(String::formatted("Error parsing subjectPublicKeyInfo: {}", maybe_subject_public_key.release_error())));
  159. structure = maybe_subject_public_key.release_value();
  160. } else if constexpr (IsSame<Structure, ::Crypto::Certificate::PrivateKey>) {
  161. auto maybe_private_key = ::Crypto::Certificate::parse_private_key_info(decoder);
  162. if (maybe_private_key.is_error())
  163. return WebIDL::DataError::create(realm, MUST(String::formatted("Error parsing privateKeyInfo: {}", maybe_private_key.release_error())));
  164. structure = maybe_private_key.release_value();
  165. } else if constexpr (IsSame<Structure, StringView>) {
  166. auto read_result = decoder.read<StringView>(::Crypto::ASN1::Class::Universal, ::Crypto::ASN1::Kind::OctetString);
  167. if (read_result.is_error())
  168. return WebIDL::DataError::create(realm, MUST(String::formatted("Read of kind OctetString failed: {}", read_result.error())));
  169. structure = read_result.release_value();
  170. } else {
  171. static_assert(DependentFalse<Structure>, "Don't know how to parse ASN.1 structure type");
  172. }
  173. // 5. If exactData was specified, and all of the bytes of data were not consumed during the parsing phase, then throw a DataError.
  174. if (exact_data && !decoder.eof())
  175. return WebIDL::DataError::create(realm, "Not all bytes were consumed during the parsing phase"_string);
  176. // 6. Return the parsed ASN.1 structure.
  177. return structure;
  178. }
  179. // https://w3c.github.io/webcrypto/#concept-parse-a-spki
  180. static WebIDL::ExceptionOr<::Crypto::Certificate::SubjectPublicKey> parse_a_subject_public_key_info(JS::Realm& realm, ReadonlyBytes bytes)
  181. {
  182. // When this specification says to parse a subjectPublicKeyInfo, the user agent must parse an ASN.1 structure,
  183. // with data set to the sequence of bytes to be parsed, structure as the ASN.1 structure of subjectPublicKeyInfo,
  184. // as specified in [RFC5280], and exactData set to true.
  185. return parse_an_ASN1_structure<::Crypto::Certificate::SubjectPublicKey>(realm, bytes, true);
  186. }
  187. // https://w3c.github.io/webcrypto/#concept-parse-a-privateKeyInfo
  188. static WebIDL::ExceptionOr<::Crypto::Certificate::PrivateKey> parse_a_private_key_info(JS::Realm& realm, ReadonlyBytes bytes)
  189. {
  190. // When this specification says to parse a PrivateKeyInfo, the user agent must parse an ASN.1 structure
  191. // with data set to the sequence of bytes to be parsed, structure as the ASN.1 structure of PrivateKeyInfo,
  192. // as specified in [RFC5208], and exactData set to true.
  193. return parse_an_ASN1_structure<::Crypto::Certificate::PrivateKey>(realm, bytes, true);
  194. }
  195. static WebIDL::ExceptionOr<::Crypto::PK::RSAPrivateKey<>> parse_jwk_rsa_private_key(JS::Realm& realm, Bindings::JsonWebKey const& jwk)
  196. {
  197. auto n = TRY(base64_url_uint_decode(realm, *jwk.n));
  198. auto d = TRY(base64_url_uint_decode(realm, *jwk.d));
  199. auto e = TRY(base64_url_uint_decode(realm, *jwk.e));
  200. // We know that if any of the extra parameters are provided, all of them must be
  201. if (!jwk.p.has_value())
  202. return ::Crypto::PK::RSAPrivateKey<>(move(n), move(d), move(e), 0, 0);
  203. auto p = TRY(base64_url_uint_decode(realm, *jwk.p));
  204. auto q = TRY(base64_url_uint_decode(realm, *jwk.q));
  205. auto dp = TRY(base64_url_uint_decode(realm, *jwk.dp));
  206. auto dq = TRY(base64_url_uint_decode(realm, *jwk.dq));
  207. auto qi = TRY(base64_url_uint_decode(realm, *jwk.qi));
  208. return ::Crypto::PK::RSAPrivateKey<>(move(n), move(d), move(e), move(p), move(q), move(dp), move(dq), move(qi));
  209. }
  210. static WebIDL::ExceptionOr<::Crypto::PK::RSAPublicKey<>> parse_jwk_rsa_public_key(JS::Realm& realm, Bindings::JsonWebKey const& jwk)
  211. {
  212. auto e = TRY(base64_url_uint_decode(realm, *jwk.e));
  213. auto n = TRY(base64_url_uint_decode(realm, *jwk.n));
  214. return ::Crypto::PK::RSAPublicKey<>(move(n), move(e));
  215. }
  216. static WebIDL::ExceptionOr<ByteBuffer> parse_jwk_symmetric_key(JS::Realm& realm, Bindings::JsonWebKey const& jwk)
  217. {
  218. if (!jwk.k.has_value()) {
  219. return WebIDL::DataError::create(realm, "JWK has no 'k' field"_string);
  220. }
  221. return base64_url_bytes_decode(realm, *jwk.k);
  222. }
  223. // https://www.rfc-editor.org/rfc/rfc7517#section-4.3
  224. static WebIDL::ExceptionOr<void> validate_jwk_key_ops(JS::Realm& realm, Bindings::JsonWebKey const& jwk, Vector<Bindings::KeyUsage> const& usages)
  225. {
  226. // Use of the "key_ops" member is OPTIONAL, unless the application requires its presence.
  227. if (!jwk.key_ops.has_value())
  228. return {};
  229. auto key_operations = *jwk.key_ops;
  230. // Duplicate key operation values MUST NOT be present in the array
  231. HashTable<String> seen_operations;
  232. for (auto const& key_operation : key_operations) {
  233. if (seen_operations.set(key_operation) != HashSetResult::InsertedNewEntry)
  234. return WebIDL::DataError::create(realm, MUST(String::formatted("Duplicate key operation: {}", key_operation)));
  235. }
  236. // Multiple unrelated key operations SHOULD NOT be specified for a key because of the potential
  237. // vulnerabilities associated with using the same key with multiple algorithms. Thus, the
  238. // combinations "sign" with "verify", "encrypt" with "decrypt", and "wrapKey" with "unwrapKey"
  239. // are permitted, but other combinations SHOULD NOT be used.
  240. auto is_used_for_signing = seen_operations.contains("sign"sv) || seen_operations.contains("verify"sv);
  241. auto is_used_for_encryption = seen_operations.contains("encrypt"sv) || seen_operations.contains("decrypt"sv);
  242. auto is_used_for_wrapping = seen_operations.contains("wrapKey"sv) || seen_operations.contains("unwrapKey"sv);
  243. auto number_of_operation_types = is_used_for_signing + is_used_for_encryption + is_used_for_wrapping;
  244. if (number_of_operation_types > 1)
  245. return WebIDL::DataError::create(realm, "Multiple unrelated key operations are specified"_string);
  246. // The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both are used,
  247. // the information they convey MUST be consistent. Applications should specify which of these
  248. // members they use, if either is to be used by the application.
  249. if (jwk.use.has_value()) {
  250. for (auto const& key_operation : key_operations) {
  251. if (key_operation == "deriveKey"sv || key_operation == "deriveBits"sv)
  252. continue;
  253. if (jwk.use == "sig"sv && key_operation != "sign"sv && key_operation != "verify"sv)
  254. return WebIDL::DataError::create(realm, "use=sig but key_ops does not contain 'sign' or 'verify'"_string);
  255. if (jwk.use == "enc"sv && (key_operation == "sign"sv || key_operation == "verify"sv))
  256. return WebIDL::DataError::create(realm, "use=enc but key_ops contains 'sign' or 'verify'"_string);
  257. }
  258. }
  259. // NOTE: This validation happens in multiple places in the spec, so it is here for convenience.
  260. for (auto const& usage : usages) {
  261. if (!seen_operations.contains(Bindings::idl_enum_to_string(usage)))
  262. return WebIDL::DataError::create(realm, MUST(String::formatted("Missing key_ops usage: {}", Bindings::idl_enum_to_string(usage))));
  263. }
  264. return {};
  265. }
  266. static WebIDL::ExceptionOr<ByteBuffer> generate_random_key(JS::VM& vm, u16 const size_in_bits)
  267. {
  268. auto key_buffer = TRY_OR_THROW_OOM(vm, ByteBuffer::create_uninitialized(size_in_bits / 8));
  269. // FIXME: Use a cryptographically secure random generator
  270. fill_with_random(key_buffer);
  271. return key_buffer;
  272. }
  273. AlgorithmParams::~AlgorithmParams() = default;
  274. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AlgorithmParams::from_value(JS::VM& vm, JS::Value value)
  275. {
  276. auto& object = value.as_object();
  277. auto name = TRY(object.get("name"));
  278. auto name_string = TRY(name.to_string(vm));
  279. return adopt_own(*new AlgorithmParams { name_string });
  280. }
  281. AesCbcParams::~AesCbcParams() = default;
  282. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AesCbcParams::from_value(JS::VM& vm, JS::Value value)
  283. {
  284. auto& object = value.as_object();
  285. auto name_value = TRY(object.get("name"));
  286. auto name = TRY(name_value.to_string(vm));
  287. auto iv_value = TRY(object.get("iv"));
  288. if (!iv_value.is_object() || !(is<JS::TypedArrayBase>(iv_value.as_object()) || is<JS::ArrayBuffer>(iv_value.as_object()) || is<JS::DataView>(iv_value.as_object())))
  289. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  290. auto iv = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(iv_value.as_object()));
  291. return adopt_own<AlgorithmParams>(*new AesCbcParams { name, iv });
  292. }
  293. AesCtrParams::~AesCtrParams() = default;
  294. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AesCtrParams::from_value(JS::VM& vm, JS::Value value)
  295. {
  296. auto& object = value.as_object();
  297. auto name_value = TRY(object.get("name"));
  298. auto name = TRY(name_value.to_string(vm));
  299. auto iv_value = TRY(object.get("counter"));
  300. if (!iv_value.is_object() || !(is<JS::TypedArrayBase>(iv_value.as_object()) || is<JS::ArrayBuffer>(iv_value.as_object()) || is<JS::DataView>(iv_value.as_object())))
  301. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  302. auto iv = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(iv_value.as_object()));
  303. auto length_value = TRY(object.get("length"));
  304. auto length = TRY(length_value.to_u8(vm));
  305. return adopt_own<AlgorithmParams>(*new AesCtrParams { name, iv, length });
  306. }
  307. AesGcmParams::~AesGcmParams() = default;
  308. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AesGcmParams::from_value(JS::VM& vm, JS::Value value)
  309. {
  310. auto& object = value.as_object();
  311. auto name_value = TRY(object.get("name"));
  312. auto name = TRY(name_value.to_string(vm));
  313. auto iv_value = TRY(object.get("iv"));
  314. if (!iv_value.is_object() || !(is<JS::TypedArrayBase>(iv_value.as_object()) || is<JS::ArrayBuffer>(iv_value.as_object()) || is<JS::DataView>(iv_value.as_object())))
  315. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  316. auto iv = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(iv_value.as_object()));
  317. auto maybe_additional_data = Optional<ByteBuffer> {};
  318. if (MUST(object.has_property("additionalData"))) {
  319. auto additional_data_value = TRY(object.get("additionalData"));
  320. if (!additional_data_value.is_object() || !(is<JS::TypedArrayBase>(additional_data_value.as_object()) || is<JS::ArrayBuffer>(additional_data_value.as_object()) || is<JS::DataView>(additional_data_value.as_object())))
  321. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  322. maybe_additional_data = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(additional_data_value.as_object()));
  323. }
  324. auto maybe_tag_length = Optional<u8> {};
  325. if (MUST(object.has_property("tagLength"))) {
  326. auto tag_length_value = TRY(object.get("tagLength"));
  327. maybe_tag_length = TRY(tag_length_value.to_u8(vm));
  328. }
  329. return adopt_own<AlgorithmParams>(*new AesGcmParams { name, iv, maybe_additional_data, maybe_tag_length });
  330. }
  331. HKDFParams::~HKDFParams() = default;
  332. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> HKDFParams::from_value(JS::VM& vm, JS::Value value)
  333. {
  334. auto& object = value.as_object();
  335. auto name_value = TRY(object.get("name"));
  336. auto name = TRY(name_value.to_string(vm));
  337. auto hash_value = TRY(object.get("hash"));
  338. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  339. auto salt_value = TRY(object.get("salt"));
  340. if (!salt_value.is_object() || !(is<JS::TypedArrayBase>(salt_value.as_object()) || is<JS::ArrayBuffer>(salt_value.as_object()) || is<JS::DataView>(salt_value.as_object())))
  341. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  342. auto salt = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(salt_value.as_object()));
  343. auto info_value = TRY(object.get("info"));
  344. if (!info_value.is_object() || !(is<JS::TypedArrayBase>(info_value.as_object()) || is<JS::ArrayBuffer>(info_value.as_object()) || is<JS::DataView>(info_value.as_object())))
  345. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  346. auto info = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(info_value.as_object()));
  347. return adopt_own<AlgorithmParams>(*new HKDFParams { name, hash, salt, info });
  348. }
  349. PBKDF2Params::~PBKDF2Params() = default;
  350. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> PBKDF2Params::from_value(JS::VM& vm, JS::Value value)
  351. {
  352. auto& object = value.as_object();
  353. auto name_value = TRY(object.get("name"));
  354. auto name = TRY(name_value.to_string(vm));
  355. auto salt_value = TRY(object.get("salt"));
  356. if (!salt_value.is_object() || !(is<JS::TypedArrayBase>(salt_value.as_object()) || is<JS::ArrayBuffer>(salt_value.as_object()) || is<JS::DataView>(salt_value.as_object())))
  357. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  358. auto salt = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(salt_value.as_object()));
  359. auto iterations_value = TRY(object.get("iterations"));
  360. auto iterations = TRY(iterations_value.to_u32(vm));
  361. auto hash_value = TRY(object.get("hash"));
  362. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  363. return adopt_own<AlgorithmParams>(*new PBKDF2Params { name, salt, iterations, hash });
  364. }
  365. RsaKeyGenParams::~RsaKeyGenParams() = default;
  366. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> RsaKeyGenParams::from_value(JS::VM& vm, JS::Value value)
  367. {
  368. auto& object = value.as_object();
  369. auto name_value = TRY(object.get("name"));
  370. auto name = TRY(name_value.to_string(vm));
  371. auto modulus_length_value = TRY(object.get("modulusLength"));
  372. auto modulus_length = TRY(modulus_length_value.to_u32(vm));
  373. auto public_exponent_value = TRY(object.get("publicExponent"));
  374. GC::Ptr<JS::Uint8Array> public_exponent;
  375. if (!public_exponent_value.is_object() || !is<JS::Uint8Array>(public_exponent_value.as_object()))
  376. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Uint8Array");
  377. public_exponent = static_cast<JS::Uint8Array&>(public_exponent_value.as_object());
  378. return adopt_own<AlgorithmParams>(*new RsaKeyGenParams { name, modulus_length, big_integer_from_api_big_integer(public_exponent) });
  379. }
  380. RsaHashedKeyGenParams::~RsaHashedKeyGenParams() = default;
  381. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> RsaHashedKeyGenParams::from_value(JS::VM& vm, JS::Value value)
  382. {
  383. auto& object = value.as_object();
  384. auto name_value = TRY(object.get("name"));
  385. auto name = TRY(name_value.to_string(vm));
  386. auto modulus_length_value = TRY(object.get("modulusLength"));
  387. auto modulus_length = TRY(modulus_length_value.to_u32(vm));
  388. auto public_exponent_value = TRY(object.get("publicExponent"));
  389. GC::Ptr<JS::Uint8Array> public_exponent;
  390. if (!public_exponent_value.is_object() || !is<JS::Uint8Array>(public_exponent_value.as_object()))
  391. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "Uint8Array");
  392. public_exponent = static_cast<JS::Uint8Array&>(public_exponent_value.as_object());
  393. auto hash_value = TRY(object.get("hash"));
  394. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  395. return adopt_own<AlgorithmParams>(*new RsaHashedKeyGenParams { name, modulus_length, big_integer_from_api_big_integer(public_exponent), hash });
  396. }
  397. RsaHashedImportParams::~RsaHashedImportParams() = default;
  398. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> RsaHashedImportParams::from_value(JS::VM& vm, JS::Value value)
  399. {
  400. auto& object = value.as_object();
  401. auto name_value = TRY(object.get("name"));
  402. auto name = TRY(name_value.to_string(vm));
  403. auto hash_value = TRY(object.get("hash"));
  404. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  405. return adopt_own<AlgorithmParams>(*new RsaHashedImportParams { name, hash });
  406. }
  407. RsaOaepParams::~RsaOaepParams() = default;
  408. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> RsaOaepParams::from_value(JS::VM& vm, JS::Value value)
  409. {
  410. auto& object = value.as_object();
  411. auto name_value = TRY(object.get("name"));
  412. auto name = TRY(name_value.to_string(vm));
  413. auto label_value = TRY(object.get("label"));
  414. ByteBuffer label;
  415. if (!label_value.is_nullish()) {
  416. if (!label_value.is_object() || !(is<JS::TypedArrayBase>(label_value.as_object()) || is<JS::ArrayBuffer>(label_value.as_object()) || is<JS::DataView>(label_value.as_object())))
  417. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "BufferSource");
  418. label = TRY_OR_THROW_OOM(vm, WebIDL::get_buffer_source_copy(label_value.as_object()));
  419. }
  420. return adopt_own<AlgorithmParams>(*new RsaOaepParams { name, move(label) });
  421. }
  422. EcdsaParams::~EcdsaParams() = default;
  423. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> EcdsaParams::from_value(JS::VM& vm, JS::Value value)
  424. {
  425. auto& object = value.as_object();
  426. auto name_value = TRY(object.get("name"));
  427. auto name = TRY(name_value.to_string(vm));
  428. auto hash_value = TRY(object.get("hash"));
  429. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  430. return adopt_own<AlgorithmParams>(*new EcdsaParams { name, hash });
  431. }
  432. EcKeyGenParams::~EcKeyGenParams() = default;
  433. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> EcKeyGenParams::from_value(JS::VM& vm, JS::Value value)
  434. {
  435. auto& object = value.as_object();
  436. auto name_value = TRY(object.get("name"));
  437. auto name = TRY(name_value.to_string(vm));
  438. auto curve_value = TRY(object.get("namedCurve"));
  439. auto curve = TRY(curve_value.to_string(vm));
  440. return adopt_own<AlgorithmParams>(*new EcKeyGenParams { name, curve });
  441. }
  442. AesKeyGenParams::~AesKeyGenParams() = default;
  443. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AesKeyGenParams::from_value(JS::VM& vm, JS::Value value)
  444. {
  445. auto& object = value.as_object();
  446. auto name_value = TRY(object.get("name"));
  447. auto name = TRY(name_value.to_string(vm));
  448. auto length_value = TRY(object.get("length"));
  449. auto length = TRY(length_value.to_u16(vm));
  450. return adopt_own<AlgorithmParams>(*new AesKeyGenParams { name, length });
  451. }
  452. AesDerivedKeyParams::~AesDerivedKeyParams() = default;
  453. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> AesDerivedKeyParams::from_value(JS::VM& vm, JS::Value value)
  454. {
  455. auto& object = value.as_object();
  456. auto name_value = TRY(object.get("name"));
  457. auto name = TRY(name_value.to_string(vm));
  458. auto length_value = TRY(object.get("length"));
  459. auto length = TRY(length_value.to_u16(vm));
  460. return adopt_own<AlgorithmParams>(*new AesDerivedKeyParams { name, length });
  461. }
  462. EcdhKeyDerivePrams::~EcdhKeyDerivePrams() = default;
  463. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> EcdhKeyDerivePrams::from_value(JS::VM& vm, JS::Value value)
  464. {
  465. auto& object = value.as_object();
  466. auto name_value = TRY(object.get("name"));
  467. auto name = TRY(name_value.to_string(vm));
  468. auto key_value = TRY(object.get("public"));
  469. auto key_object = TRY(key_value.to_object(vm));
  470. if (!is<CryptoKey>(*key_object)) {
  471. return vm.throw_completion<JS::TypeError>(JS::ErrorType::NotAnObjectOfType, "CryptoKey");
  472. }
  473. auto& key = verify_cast<CryptoKey>(*key_object);
  474. return adopt_own<AlgorithmParams>(*new EcdhKeyDerivePrams { name, key });
  475. }
  476. HmacImportParams::~HmacImportParams() = default;
  477. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> HmacImportParams::from_value(JS::VM& vm, JS::Value value)
  478. {
  479. auto& object = value.as_object();
  480. auto name_value = TRY(object.get("name"));
  481. auto name = TRY(name_value.to_string(vm));
  482. auto hash_value = TRY(object.get("hash"));
  483. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  484. auto maybe_length = Optional<WebIDL::UnsignedLong> {};
  485. if (MUST(object.has_property("length"))) {
  486. auto length_value = TRY(object.get("length"));
  487. maybe_length = TRY(length_value.to_u32(vm));
  488. }
  489. return adopt_own<AlgorithmParams>(*new HmacImportParams { name, hash, maybe_length });
  490. }
  491. HmacKeyGenParams::~HmacKeyGenParams() = default;
  492. JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> HmacKeyGenParams::from_value(JS::VM& vm, JS::Value value)
  493. {
  494. auto& object = value.as_object();
  495. auto name_value = TRY(object.get("name"));
  496. auto name = TRY(name_value.to_string(vm));
  497. auto hash_value = TRY(object.get("hash"));
  498. auto hash = TRY(hash_algorithm_identifier_from_value(vm, hash_value));
  499. auto maybe_length = Optional<WebIDL::UnsignedLong> {};
  500. if (MUST(object.has_property("length"))) {
  501. auto length_value = TRY(object.get("length"));
  502. maybe_length = TRY(length_value.to_u32(vm));
  503. }
  504. return adopt_own<AlgorithmParams>(*new HmacKeyGenParams { name, hash, maybe_length });
  505. }
  506. // https://w3c.github.io/webcrypto/#rsa-oaep-operations
  507. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> RSAOAEP::encrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& plaintext)
  508. {
  509. auto& realm = *m_realm;
  510. auto& vm = realm.vm();
  511. auto const& normalized_algorithm = static_cast<RsaOaepParams const&>(params);
  512. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  513. if (key->type() != Bindings::KeyType::Public)
  514. return WebIDL::InvalidAccessError::create(realm, "Key is not a public key"_string);
  515. // 2. Let label be the contents of the label member of normalizedAlgorithm or the empty octet string if the label member of normalizedAlgorithm is not present.
  516. auto const& label = normalized_algorithm.label;
  517. auto const& handle = key->handle();
  518. auto public_key = handle.get<::Crypto::PK::RSAPublicKey<>>();
  519. auto hash = TRY(verify_cast<RsaHashedKeyAlgorithm>(*key->algorithm()).hash().name(vm));
  520. // 3. Perform the encryption operation defined in Section 7.1 of [RFC3447] with the key represented by key as the recipient's RSA public key,
  521. // the contents of plaintext as the message to be encrypted, M and label as the label, L, and with the hash function specified by the hash attribute
  522. // of the [[algorithm]] internal slot of key as the Hash option and MGF1 (defined in Section B.2.1 of [RFC3447]) as the MGF option.
  523. auto error_message = MUST(String::formatted("Invalid hash function '{}'", hash));
  524. ErrorOr<ByteBuffer> maybe_padding = Error::from_string_view(error_message.bytes_as_string_view());
  525. if (hash.equals_ignoring_ascii_case("SHA-1"sv)) {
  526. maybe_padding = ::Crypto::Padding::OAEP::eme_encode<::Crypto::Hash::SHA1, ::Crypto::Hash::MGF>(plaintext, label, public_key.length());
  527. } else if (hash.equals_ignoring_ascii_case("SHA-256"sv)) {
  528. maybe_padding = ::Crypto::Padding::OAEP::eme_encode<::Crypto::Hash::SHA256, ::Crypto::Hash::MGF>(plaintext, label, public_key.length());
  529. } else if (hash.equals_ignoring_ascii_case("SHA-384"sv)) {
  530. maybe_padding = ::Crypto::Padding::OAEP::eme_encode<::Crypto::Hash::SHA384, ::Crypto::Hash::MGF>(plaintext, label, public_key.length());
  531. } else if (hash.equals_ignoring_ascii_case("SHA-512"sv)) {
  532. maybe_padding = ::Crypto::Padding::OAEP::eme_encode<::Crypto::Hash::SHA512, ::Crypto::Hash::MGF>(plaintext, label, public_key.length());
  533. }
  534. // 4. If performing the operation results in an error, then throw an OperationError.
  535. if (maybe_padding.is_error()) {
  536. auto error_message = MUST(String::from_utf8(maybe_padding.error().string_literal()));
  537. return WebIDL::OperationError::create(realm, error_message);
  538. }
  539. auto padding = maybe_padding.release_value();
  540. // 5. Let ciphertext be the value C that results from performing the operation.
  541. auto ciphertext = TRY_OR_THROW_OOM(vm, ByteBuffer::create_uninitialized(public_key.length()));
  542. auto ciphertext_bytes = ciphertext.bytes();
  543. auto rsa = ::Crypto::PK::RSA {};
  544. rsa.set_public_key(public_key);
  545. rsa.encrypt(padding, ciphertext_bytes);
  546. // 6. Return the result of creating an ArrayBuffer containing ciphertext.
  547. return JS::ArrayBuffer::create(realm, move(ciphertext));
  548. }
  549. // https://w3c.github.io/webcrypto/#rsa-oaep-operations
  550. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> RSAOAEP::decrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, AK::ByteBuffer const& ciphertext)
  551. {
  552. auto& realm = *m_realm;
  553. auto& vm = realm.vm();
  554. auto const& normalized_algorithm = static_cast<RsaOaepParams const&>(params);
  555. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  556. if (key->type() != Bindings::KeyType::Private)
  557. return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_string);
  558. // 2. Let label be the contents of the label member of normalizedAlgorithm or the empty octet string if the label member of normalizedAlgorithm is not present.
  559. auto const& label = normalized_algorithm.label;
  560. auto const& handle = key->handle();
  561. auto private_key = handle.get<::Crypto::PK::RSAPrivateKey<>>();
  562. auto hash = TRY(verify_cast<RsaHashedKeyAlgorithm>(*key->algorithm()).hash().name(vm));
  563. // 3. Perform the decryption operation defined in Section 7.1 of [RFC3447] with the key represented by key as the recipient's RSA private key,
  564. // the contents of ciphertext as the ciphertext to be decrypted, C, and label as the label, L, and with the hash function specified by the hash attribute
  565. // of the [[algorithm]] internal slot of key as the Hash option and MGF1 (defined in Section B.2.1 of [RFC3447]) as the MGF option.
  566. auto rsa = ::Crypto::PK::RSA {};
  567. rsa.set_private_key(private_key);
  568. u32 private_key_length = private_key.length();
  569. auto padding = TRY_OR_THROW_OOM(vm, ByteBuffer::create_uninitialized(private_key_length));
  570. auto padding_bytes = padding.bytes();
  571. rsa.decrypt(ciphertext, padding_bytes);
  572. auto error_message = MUST(String::formatted("Invalid hash function '{}'", hash));
  573. ErrorOr<ByteBuffer> maybe_plaintext = Error::from_string_view(error_message.bytes_as_string_view());
  574. if (hash.equals_ignoring_ascii_case("SHA-1"sv)) {
  575. maybe_plaintext = ::Crypto::Padding::OAEP::eme_decode<::Crypto::Hash::SHA1, ::Crypto::Hash::MGF>(padding, label, private_key_length);
  576. } else if (hash.equals_ignoring_ascii_case("SHA-256"sv)) {
  577. maybe_plaintext = ::Crypto::Padding::OAEP::eme_decode<::Crypto::Hash::SHA256, ::Crypto::Hash::MGF>(padding, label, private_key_length);
  578. } else if (hash.equals_ignoring_ascii_case("SHA-384"sv)) {
  579. maybe_plaintext = ::Crypto::Padding::OAEP::eme_decode<::Crypto::Hash::SHA384, ::Crypto::Hash::MGF>(padding, label, private_key_length);
  580. } else if (hash.equals_ignoring_ascii_case("SHA-512"sv)) {
  581. maybe_plaintext = ::Crypto::Padding::OAEP::eme_decode<::Crypto::Hash::SHA512, ::Crypto::Hash::MGF>(padding, label, private_key_length);
  582. }
  583. // 4. If performing the operation results in an error, then throw an OperationError.
  584. if (maybe_plaintext.is_error()) {
  585. auto error_message = MUST(String::from_utf8(maybe_plaintext.error().string_literal()));
  586. return WebIDL::OperationError::create(realm, error_message);
  587. }
  588. // 5. Let plaintext the value M that results from performing the operation.
  589. auto plaintext = maybe_plaintext.release_value();
  590. // 6. Return the result of creating an ArrayBuffer containing plaintext.
  591. return JS::ArrayBuffer::create(realm, move(plaintext));
  592. }
  593. // https://w3c.github.io/webcrypto/#rsa-oaep-operations
  594. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> RSAOAEP::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  595. {
  596. // 1. If usages contains an entry which is not "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  597. for (auto const& usage : key_usages) {
  598. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  599. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  600. }
  601. }
  602. // 2. Generate an RSA key pair, as defined in [RFC3447], with RSA modulus length equal to the modulusLength member of normalizedAlgorithm
  603. // and RSA public exponent equal to the publicExponent member of normalizedAlgorithm.
  604. // 3. If performing the operation results in an error, then throw an OperationError.
  605. auto const& normalized_algorithm = static_cast<RsaHashedKeyGenParams const&>(params);
  606. auto key_pair = ::Crypto::PK::RSA::generate_key_pair(normalized_algorithm.modulus_length, normalized_algorithm.public_exponent);
  607. // 4. Let algorithm be a new RsaHashedKeyAlgorithm object.
  608. auto algorithm = RsaHashedKeyAlgorithm::create(m_realm);
  609. // 5. Set the name attribute of algorithm to "RSA-OAEP".
  610. algorithm->set_name("RSA-OAEP"_string);
  611. // 6. Set the modulusLength attribute of algorithm to equal the modulusLength member of normalizedAlgorithm.
  612. algorithm->set_modulus_length(normalized_algorithm.modulus_length);
  613. // 7. Set the publicExponent attribute of algorithm to equal the publicExponent member of normalizedAlgorithm.
  614. TRY(algorithm->set_public_exponent(normalized_algorithm.public_exponent));
  615. // 8. Set the hash attribute of algorithm to equal the hash member of normalizedAlgorithm.
  616. algorithm->set_hash(normalized_algorithm.hash);
  617. // 9. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
  618. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_pair.public_key });
  619. // 10. Set the [[type]] internal slot of publicKey to "public"
  620. public_key->set_type(Bindings::KeyType::Public);
  621. // 11. Set the [[algorithm]] internal slot of publicKey to algorithm.
  622. public_key->set_algorithm(algorithm);
  623. // 12. Set the [[extractable]] internal slot of publicKey to true.
  624. public_key->set_extractable(true);
  625. // 13. Set the [[usages]] internal slot of publicKey to be the usage intersection of usages and [ "encrypt", "wrapKey" ].
  626. public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Encrypt, Bindings::KeyUsage::Wrapkey } }));
  627. // 14. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
  628. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_pair.private_key });
  629. // 15. Set the [[type]] internal slot of privateKey to "private"
  630. private_key->set_type(Bindings::KeyType::Private);
  631. // 16. Set the [[algorithm]] internal slot of privateKey to algorithm.
  632. private_key->set_algorithm(algorithm);
  633. // 17. Set the [[extractable]] internal slot of privateKey to extractable.
  634. private_key->set_extractable(extractable);
  635. // 18. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "decrypt", "unwrapKey" ].
  636. private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Decrypt, Bindings::KeyUsage::Unwrapkey } }));
  637. // 19. Let result be a new CryptoKeyPair dictionary.
  638. // 20. Set the publicKey attribute of result to be publicKey.
  639. // 21. Set the privateKey attribute of result to be privateKey.
  640. // 22. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  641. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
  642. }
  643. // https://w3c.github.io/webcrypto/#rsa-oaep-operations
  644. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> RSAOAEP::import_key(Web::Crypto::AlgorithmParams const& params, Bindings::KeyFormat key_format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& usages)
  645. {
  646. auto& realm = *m_realm;
  647. // 1. Let keyData be the key data to be imported.
  648. GC::Ptr<CryptoKey> key = nullptr;
  649. auto const& normalized_algorithm = static_cast<RsaHashedImportParams const&>(params);
  650. // 2. -> If format is "spki":
  651. if (key_format == Bindings::KeyFormat::Spki) {
  652. // 1. If usages contains an entry which is not "encrypt" or "wrapKey", then throw a SyntaxError.
  653. for (auto const& usage : usages) {
  654. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Wrapkey) {
  655. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  656. }
  657. }
  658. VERIFY(key_data.has<ByteBuffer>());
  659. // 2. Let spki be the result of running the parse a subjectPublicKeyInfo algorithm over keyData.
  660. // 3. If an error occurred while parsing, then throw a DataError.
  661. auto spki = TRY(parse_a_subject_public_key_info(m_realm, key_data.get<ByteBuffer>()));
  662. // 4. If the algorithm object identifier field of the algorithm AlgorithmIdentifier field of spki
  663. // is not equal to the rsaEncryption object identifier defined in [RFC3447], then throw a DataError.
  664. if (spki.algorithm.identifier != ::Crypto::Certificate::rsa_encryption_oid)
  665. return WebIDL::DataError::create(m_realm, "Algorithm object identifier is not the rsaEncryption object identifier"_string);
  666. // 5. Let publicKey be the result of performing the parse an ASN.1 structure algorithm,
  667. // with data as the subjectPublicKeyInfo field of spki, structure as the RSAPublicKey structure
  668. // specified in Section A.1.1 of [RFC3447], and exactData set to true.
  669. // NOTE: We already did this in parse_a_subject_public_key_info
  670. auto& public_key = spki.rsa;
  671. // 6. If an error occurred while parsing, or it can be determined that publicKey is not
  672. // a valid public key according to [RFC3447], then throw a DataError.
  673. // FIXME: Validate the public key
  674. // 7. Let key be a new CryptoKey that represents the RSA public key identified by publicKey.
  675. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  676. // 8. Set the [[type]] internal slot of key to "public"
  677. key->set_type(Bindings::KeyType::Public);
  678. }
  679. // -> If format is "pkcs8":
  680. else if (key_format == Bindings::KeyFormat::Pkcs8) {
  681. // 1. If usages contains an entry which is not "decrypt" or "unwrapKey", then throw a SyntaxError.
  682. for (auto const& usage : usages) {
  683. if (usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Unwrapkey) {
  684. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  685. }
  686. }
  687. VERIFY(key_data.has<ByteBuffer>());
  688. // 2. Let privateKeyInfo be the result of running the parse a privateKeyInfo algorithm over keyData.
  689. // 3. If an error occurred while parsing, then throw a DataError.
  690. auto private_key_info = TRY(parse_a_private_key_info(m_realm, key_data.get<ByteBuffer>()));
  691. // 4. If the algorithm object identifier field of the privateKeyAlgorithm PrivateKeyAlgorithm field of privateKeyInfo
  692. // is not equal to the rsaEncryption object identifier defined in [RFC3447], then throw a DataError.
  693. if (private_key_info.algorithm.identifier != ::Crypto::Certificate::rsa_encryption_oid)
  694. return WebIDL::DataError::create(m_realm, "Algorithm object identifier is not the rsaEncryption object identifier"_string);
  695. // 5. Let rsaPrivateKey be the result of performing the parse an ASN.1 structure algorithm,
  696. // with data as the privateKey field of privateKeyInfo, structure as the RSAPrivateKey structure
  697. // specified in Section A.1.2 of [RFC3447], and exactData set to true.
  698. // NOTE: We already did this in parse_a_private_key_info
  699. auto& rsa_private_key = private_key_info.rsa;
  700. // 6. If an error occurred while parsing, or if rsaPrivateKey is not
  701. // a valid RSA private key according to [RFC3447], then throw a DataError.
  702. // FIXME: Validate the private key
  703. // 7. Let key be a new CryptoKey that represents the RSA private key identified by rsaPrivateKey.
  704. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { rsa_private_key });
  705. // 8. Set the [[type]] internal slot of key to "private"
  706. key->set_type(Bindings::KeyType::Private);
  707. }
  708. // -> If format is "jwk":
  709. else if (key_format == Bindings::KeyFormat::Jwk) {
  710. // 1. -> If keyData is a JsonWebKey dictionary:
  711. // Let jwk equal keyData.
  712. // -> Otherwise:
  713. // Throw a DataError.
  714. if (!key_data.has<Bindings::JsonWebKey>())
  715. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  716. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  717. // 2. If the d field of jwk is present and usages contains an entry which is not "decrypt" or "unwrapKey", then throw a SyntaxError.
  718. if (jwk.d.has_value()) {
  719. for (auto const& usage : usages) {
  720. if (usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Unwrapkey) {
  721. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", Bindings::idl_enum_to_string(usage))));
  722. }
  723. }
  724. }
  725. // 3. If the d field of jwk is not present and usages contains an entry which is not "encrypt" or "wrapKey", then throw a SyntaxError.
  726. if (!jwk.d.has_value()) {
  727. for (auto const& usage : usages) {
  728. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Wrapkey) {
  729. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", Bindings::idl_enum_to_string(usage))));
  730. }
  731. }
  732. }
  733. // 4. If the kty field of jwk is not a case-sensitive string match to "RSA", then throw a DataError.
  734. if (jwk.kty != "RSA"_string)
  735. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  736. // 5. If usages is non-empty and the use field of jwk is present and is not a case-sensitive string match to "enc", then throw a DataError.
  737. if (!usages.is_empty() && jwk.use.has_value() && *jwk.use != "enc"_string)
  738. return WebIDL::DataError::create(m_realm, "Invalid use field"_string);
  739. // 6. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK]
  740. // or does not contain all of the specified usages values, then throw a DataError.
  741. TRY(validate_jwk_key_ops(realm, jwk, usages));
  742. // 7. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  743. if (jwk.ext.has_value() && !*jwk.ext && extractable)
  744. return WebIDL::DataError::create(m_realm, "Invalid ext field"_string);
  745. Optional<String> hash = {};
  746. // 8. -> If the alg field of jwk is not present:
  747. if (!jwk.alg.has_value()) {
  748. // Let hash be undefined.
  749. }
  750. // -> If the alg field of jwk is equal to "RSA-OAEP":
  751. else if (jwk.alg == "RSA-OAEP"sv) {
  752. // Let hash be the string "SHA-1".
  753. hash = "SHA-1"_string;
  754. }
  755. // -> If the alg field of jwk is equal to "RSA-OAEP-256":
  756. else if (jwk.alg == "RSA-OAEP-256"sv) {
  757. // Let hash be the string "SHA-256".
  758. hash = "SHA-256"_string;
  759. }
  760. // -> If the alg field of jwk is equal to "RSA-OAEP-384":
  761. else if (jwk.alg == "RSA-OAEP-384"sv) {
  762. // Let hash be the string "SHA-384".
  763. hash = "SHA-384"_string;
  764. }
  765. // -> If the alg field of jwk is equal to "RSA-OAEP-512":
  766. else if (jwk.alg == "RSA-OAEP-512"sv) {
  767. // Let hash be the string "SHA-512".
  768. hash = "SHA-512"_string;
  769. }
  770. // -> Otherwise:
  771. else {
  772. // FIXME: Support 'other applicable specifications'
  773. // 1. Perform any key import steps defined by other applicable specifications, passing format, jwk and obtaining hash.
  774. // 2. If an error occurred or there are no applicable specifications, throw a DataError.
  775. return WebIDL::DataError::create(m_realm, "Invalid alg field"_string);
  776. }
  777. // 9. If hash is not undefined:
  778. if (hash.has_value()) {
  779. // 1. Let normalizedHash be the result of normalize an algorithm with alg set to hash and op set to digest.
  780. auto normalized_hash = TRY(normalize_an_algorithm(m_realm, AlgorithmIdentifier { *hash }, "digest"_string));
  781. // 2. If normalizedHash is not equal to the hash member of normalizedAlgorithm, throw a DataError.
  782. if (normalized_hash.parameter->name != TRY(normalized_algorithm.hash.name(realm.vm())))
  783. return WebIDL::DataError::create(m_realm, "Invalid hash"_string);
  784. }
  785. // 10. -> If the d field of jwk is present:
  786. if (jwk.d.has_value()) {
  787. // 1. If jwk does not meet the requirements of Section 6.3.2 of JSON Web Algorithms [JWA], then throw a DataError.
  788. bool meets_requirements = jwk.e.has_value() && jwk.n.has_value() && jwk.d.has_value();
  789. if (jwk.p.has_value() || jwk.q.has_value() || jwk.dp.has_value() || jwk.dq.has_value() || jwk.qi.has_value())
  790. meets_requirements |= jwk.p.has_value() && jwk.q.has_value() && jwk.dp.has_value() && jwk.dq.has_value() && jwk.qi.has_value();
  791. if (jwk.oth.has_value()) {
  792. // FIXME: We don't support > 2 primes in RSA keys
  793. meets_requirements = false;
  794. }
  795. if (!meets_requirements)
  796. return WebIDL::DataError::create(m_realm, "Invalid JWK private key"_string);
  797. // FIXME: Spec error, it should say 'the RSA private key identified by interpreting jwk according to section 6.3.2'
  798. // 2. Let privateKey represent the RSA public key identified by interpreting jwk according to Section 6.3.1 of JSON Web Algorithms [JWA].
  799. auto private_key = TRY(parse_jwk_rsa_private_key(realm, jwk));
  800. // FIXME: Spec error, it should say 'not to be a valid RSA private key'
  801. // 3. If privateKey can be determined to not be a valid RSA public key according to [RFC3447], then throw a DataError.
  802. // FIXME: Validate the private key
  803. // 4. Let key be a new CryptoKey representing privateKey.
  804. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
  805. // 5. Set the [[type]] internal slot of key to "private"
  806. key->set_type(Bindings::KeyType::Private);
  807. }
  808. // -> Otherwise:
  809. else {
  810. // 1. If jwk does not meet the requirements of Section 6.3.1 of JSON Web Algorithms [JWA], then throw a DataError.
  811. if (!jwk.e.has_value() || !jwk.n.has_value())
  812. return WebIDL::DataError::create(m_realm, "Invalid JWK public key"_string);
  813. // 2. Let publicKey represent the RSA public key identified by interpreting jwk according to Section 6.3.1 of JSON Web Algorithms [JWA].
  814. auto public_key = TRY(parse_jwk_rsa_public_key(realm, jwk));
  815. // 3. If publicKey can be determined to not be a valid RSA public key according to [RFC3447], then throw a DataError.
  816. // FIXME: Validate the public key
  817. // 4. Let key be a new CryptoKey representing publicKey.
  818. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  819. // 5. Set the [[type]] internal slot of key to "public"
  820. key->set_type(Bindings::KeyType::Public);
  821. }
  822. }
  823. // -> Otherwise: throw a NotSupportedError.
  824. else {
  825. return WebIDL::NotSupportedError::create(m_realm, "Unsupported key format"_string);
  826. }
  827. // 3. Let algorithm be a new RsaHashedKeyAlgorithm.
  828. auto algorithm = RsaHashedKeyAlgorithm::create(m_realm);
  829. // 4. Set the name attribute of algorithm to "RSA-OAEP"
  830. algorithm->set_name("RSA-OAEP"_string);
  831. // 5. Set the modulusLength attribute of algorithm to the length, in bits, of the RSA public modulus.
  832. // 6. Set the publicExponent attribute of algorithm to the BigInteger representation of the RSA public exponent.
  833. TRY(key->handle().visit(
  834. [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> WebIDL::ExceptionOr<void> {
  835. algorithm->set_modulus_length(public_key.modulus().trimmed_byte_length() * 8);
  836. TRY(algorithm->set_public_exponent(public_key.public_exponent()));
  837. return {};
  838. },
  839. [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> WebIDL::ExceptionOr<void> {
  840. algorithm->set_modulus_length(private_key.modulus().trimmed_byte_length() * 8);
  841. TRY(algorithm->set_public_exponent(private_key.public_exponent()));
  842. return {};
  843. },
  844. [](auto) -> WebIDL::ExceptionOr<void> { VERIFY_NOT_REACHED(); }));
  845. // 7. Set the hash attribute of algorithm to the hash member of normalizedAlgorithm.
  846. algorithm->set_hash(normalized_algorithm.hash);
  847. // 8. Set the [[algorithm]] internal slot of key to algorithm
  848. key->set_algorithm(algorithm);
  849. // 9. Return key.
  850. return GC::Ref { *key };
  851. }
  852. // https://w3c.github.io/webcrypto/#rsa-oaep-operations
  853. WebIDL::ExceptionOr<GC::Ref<JS::Object>> RSAOAEP::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  854. {
  855. auto& realm = *m_realm;
  856. auto& vm = realm.vm();
  857. // 1. Let key be the key to be exported.
  858. // 2. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  859. // Note: In our impl this is always accessible
  860. auto const& handle = key->handle();
  861. GC::Ptr<JS::Object> result = nullptr;
  862. // 3. If format is "spki"
  863. if (format == Bindings::KeyFormat::Spki) {
  864. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  865. if (key->type() != Bindings::KeyType::Public)
  866. return WebIDL::InvalidAccessError::create(realm, "Key is not public"_string);
  867. // 2. Let data be an instance of the subjectPublicKeyInfo ASN.1 structure defined in [RFC5280] with the following properties:
  868. // - Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the following properties:
  869. // - Set the algorithm field to the OID rsaEncryption defined in [RFC3447].
  870. // - Set the params field to the ASN.1 type NULL.
  871. // - Set the subjectPublicKey field to the result of DER-encoding an RSAPublicKey ASN.1 type, as defined in [RFC3447], Appendix A.1.1,
  872. // that represents the RSA public key represented by the [[handle]] internal slot of key
  873. auto maybe_data = handle.visit(
  874. [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> ErrorOr<ByteBuffer> {
  875. return TRY(::Crypto::PK::wrap_in_subject_public_key_info(public_key, Array { ::Crypto::Certificate::rsa_encryption_oid }, nullptr));
  876. },
  877. [](auto) -> ErrorOr<ByteBuffer> {
  878. VERIFY_NOT_REACHED();
  879. });
  880. // FIXME: clang-format butchers the visit if we do the TRY inline
  881. auto data = TRY_OR_THROW_OOM(vm, maybe_data);
  882. // 3. Let result be the result of creating an ArrayBuffer containing data.
  883. result = JS::ArrayBuffer::create(realm, data);
  884. }
  885. // If format is "pkcs8"
  886. else if (format == Bindings::KeyFormat::Pkcs8) {
  887. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  888. if (key->type() != Bindings::KeyType::Private)
  889. return WebIDL::InvalidAccessError::create(realm, "Key is not private"_string);
  890. // 2. Let data be the result of encoding a privateKeyInfo structure with the following properties:
  891. // - Set the version field to 0.
  892. // - Set the privateKeyAlgorithm field to an PrivateKeyAlgorithmIdentifier ASN.1 type with the following properties:
  893. // - - Set the algorithm field to the OID rsaEncryption defined in [RFC3447].
  894. // - - Set the params field to the ASN.1 type NULL.
  895. // - Set the privateKey field to the result of DER-encoding an RSAPrivateKey ASN.1 type, as defined in [RFC3447], Appendix A.1.2,
  896. // that represents the RSA private key represented by the [[handle]] internal slot of key
  897. auto maybe_data = handle.visit(
  898. [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> ErrorOr<ByteBuffer> {
  899. return TRY(::Crypto::PK::wrap_in_private_key_info(private_key, Array { ::Crypto::Certificate::rsa_encryption_oid }, nullptr));
  900. },
  901. [](auto) -> ErrorOr<ByteBuffer> {
  902. VERIFY_NOT_REACHED();
  903. });
  904. // FIXME: clang-format butchers the visit if we do the TRY inline
  905. auto data = TRY_OR_THROW_OOM(vm, maybe_data);
  906. // 3. Let result be the result of creating an ArrayBuffer containing data.
  907. result = JS::ArrayBuffer::create(realm, data);
  908. }
  909. // If format is "jwk"
  910. else if (format == Bindings::KeyFormat::Jwk) {
  911. // 1. Let jwk be a new JsonWebKey dictionary.
  912. Bindings::JsonWebKey jwk = {};
  913. // 2. Set the kty attribute of jwk to the string "RSA".
  914. jwk.kty = "RSA"_string;
  915. // 4. Let hash be the name attribute of the hash attribute of the [[algorithm]] internal slot of key.
  916. auto hash = TRY(verify_cast<RsaHashedKeyAlgorithm>(*key->algorithm()).hash().name(vm));
  917. // 4. If hash is "SHA-1":
  918. // - Set the alg attribute of jwk to the string "RSA-OAEP".
  919. if (hash == "SHA-1"sv) {
  920. jwk.alg = "RSA-OAEP"_string;
  921. }
  922. // If hash is "SHA-256":
  923. // - Set the alg attribute of jwk to the string "RSA-OAEP-256".
  924. else if (hash == "SHA-256"sv) {
  925. jwk.alg = "RSA-OAEP-256"_string;
  926. }
  927. // If hash is "SHA-384":
  928. // - Set the alg attribute of jwk to the string "RSA-OAEP-384".
  929. else if (hash == "SHA-384"sv) {
  930. jwk.alg = "RSA-OAEP-384"_string;
  931. }
  932. // If hash is "SHA-512":
  933. // - Set the alg attribute of jwk to the string "RSA-OAEP-512".
  934. else if (hash == "SHA-512"sv) {
  935. jwk.alg = "RSA-OAEP-512"_string;
  936. } else {
  937. // FIXME: Support 'other applicable specifications'
  938. // - Perform any key export steps defined by other applicable specifications,
  939. // passing format and the hash attribute of the [[algorithm]] internal slot of key and obtaining alg.
  940. // - Set the alg attribute of jwk to alg.
  941. return WebIDL::NotSupportedError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("Unsupported hash algorithm '{}'", hash)));
  942. }
  943. // 10. Set the attributes n and e of jwk according to the corresponding definitions in JSON Web Algorithms [JWA], Section 6.3.1.
  944. auto maybe_error = handle.visit(
  945. [&](::Crypto::PK::RSAPublicKey<> const& public_key) -> ErrorOr<void> {
  946. jwk.n = TRY(base64_url_uint_encode(public_key.modulus()));
  947. jwk.e = TRY(base64_url_uint_encode(public_key.public_exponent()));
  948. return {};
  949. },
  950. [&](::Crypto::PK::RSAPrivateKey<> const& private_key) -> ErrorOr<void> {
  951. jwk.n = TRY(base64_url_uint_encode(private_key.modulus()));
  952. jwk.e = TRY(base64_url_uint_encode(private_key.public_exponent()));
  953. // 11. If the [[type]] internal slot of key is "private":
  954. // 1. Set the attributes named d, p, q, dp, dq, and qi of jwk according to the corresponding definitions in JSON Web Algorithms [JWA], Section 6.3.2.
  955. jwk.d = TRY(base64_url_uint_encode(private_key.private_exponent()));
  956. jwk.p = TRY(base64_url_uint_encode(private_key.prime1()));
  957. jwk.q = TRY(base64_url_uint_encode(private_key.prime2()));
  958. jwk.dp = TRY(base64_url_uint_encode(private_key.exponent1()));
  959. jwk.dq = TRY(base64_url_uint_encode(private_key.exponent2()));
  960. jwk.qi = TRY(base64_url_uint_encode(private_key.coefficient()));
  961. // 12. If the underlying RSA private key represented by the [[handle]] internal slot of key is represented by more than two primes,
  962. // set the attribute named oth of jwk according to the corresponding definition in JSON Web Algorithms [JWA], Section 6.3.2.7
  963. // FIXME: We don't support more than 2 primes on RSA keys
  964. return {};
  965. },
  966. [](auto) -> ErrorOr<void> {
  967. VERIFY_NOT_REACHED();
  968. });
  969. // FIXME: clang-format butchers the visit if we do the TRY inline
  970. TRY_OR_THROW_OOM(vm, maybe_error);
  971. // 13. Set the key_ops attribute of jwk to the usages attribute of key.
  972. jwk.key_ops = Vector<String> {};
  973. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  974. for (auto const& usage : key->internal_usages()) {
  975. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  976. }
  977. // 14. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
  978. jwk.ext = key->extractable();
  979. // 15. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  980. result = TRY(jwk.to_object(realm));
  981. }
  982. // Otherwise throw a NotSupportedError.
  983. else {
  984. return WebIDL::NotSupportedError::create(realm, TRY_OR_THROW_OOM(vm, String::formatted("Exporting to format {} is not supported", Bindings::idl_enum_to_string(format))));
  985. }
  986. // 8. Return result
  987. return GC::Ref { *result };
  988. }
  989. // https://w3c.github.io/webcrypto/#aes-cbc-operations
  990. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesCbc::encrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& plaintext)
  991. {
  992. auto const& normalized_algorithm = static_cast<AesCbcParams const&>(params);
  993. // 1. If the iv member of normalizedAlgorithm does not have length 16 bytes, then throw an OperationError.
  994. if (normalized_algorithm.iv.size() != 16)
  995. return WebIDL::OperationError::create(m_realm, "IV to AES-CBC must be exactly 16 bytes"_string);
  996. // 2. Let paddedPlaintext be the result of adding padding octets to the contents of plaintext according to the procedure defined in Section 10.3 of [RFC2315], step 2, with a value of k of 16.
  997. // Note: This is identical to RFC 5652 Cryptographic Message Syntax (CMS).
  998. // We do this during encryption, which avoid reallocating a potentially-large buffer.
  999. auto mode = ::Crypto::Cipher::PaddingMode::CMS;
  1000. // 3. Let ciphertext be the result of performing the CBC Encryption operation described in Section 6.2 of [NIST-SP800-38A] using AES as the block cipher, the contents of the iv member of normalizedAlgorithm as the IV input parameter and paddedPlaintext as the input plaintext.
  1001. auto key_bytes = key->handle().get<ByteBuffer>();
  1002. auto key_bits = key_bytes.size() * 8;
  1003. ::Crypto::Cipher::AESCipher::CBCMode cipher(key_bytes, key_bits, ::Crypto::Cipher::Intent::Encryption, mode);
  1004. auto iv = normalized_algorithm.iv;
  1005. auto ciphertext = TRY_OR_THROW_OOM(m_realm->vm(), cipher.create_aligned_buffer(plaintext.size() + 1));
  1006. auto ciphertext_view = ciphertext.bytes();
  1007. cipher.encrypt(plaintext, ciphertext_view, iv);
  1008. ciphertext.trim(ciphertext_view.size(), false);
  1009. // 4. Return the result of creating an ArrayBuffer containing ciphertext.
  1010. return JS::ArrayBuffer::create(m_realm, move(ciphertext));
  1011. }
  1012. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesCbc::decrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& ciphertext)
  1013. {
  1014. auto const& normalized_algorithm = static_cast<AesCbcParams const&>(params);
  1015. // 1. If the iv member of normalizedAlgorithm does not have length 16 bytes, then throw an OperationError.
  1016. if (normalized_algorithm.iv.size() != 16)
  1017. return WebIDL::OperationError::create(m_realm, "IV to AES-CBC must be exactly 16 bytes"_string);
  1018. // Spec bug? TODO: https://github.com/w3c/webcrypto/issues/381
  1019. // If ciphertext does not have a length that is a multiple of 16 bytes, then throw an OperationError. (Note that a zero-length ciphertext will result in an OperationError in all cases.)
  1020. if (ciphertext.size() % 16 != 0)
  1021. return WebIDL::OperationError::create(m_realm, "Ciphertext length must be a multiple of 16 bytes"_string);
  1022. // 2. Let paddedPlaintext be the result of performing the CBC Decryption operation described in Section 6.2 of [NIST-SP800-38A] using AES as the block cipher, the contents of the iv member of normalizedAlgorithm as the IV input parameter and the contents of ciphertext as the input ciphertext.
  1023. auto mode = ::Crypto::Cipher::PaddingMode::CMS;
  1024. auto key_bytes = key->handle().get<ByteBuffer>();
  1025. auto key_bits = key_bytes.size() * 8;
  1026. ::Crypto::Cipher::AESCipher::CBCMode cipher(key_bytes, key_bits, ::Crypto::Cipher::Intent::Decryption, mode);
  1027. auto iv = normalized_algorithm.iv;
  1028. auto plaintext = TRY_OR_THROW_OOM(m_realm->vm(), cipher.create_aligned_buffer(ciphertext.size()));
  1029. auto plaintext_view = plaintext.bytes();
  1030. cipher.decrypt(ciphertext, plaintext_view, iv);
  1031. plaintext.trim(plaintext_view.size(), false);
  1032. // 3. Let p be the value of the last octet of paddedPlaintext.
  1033. // 4. If p is zero or greater than 16, or if any of the last p octets of paddedPlaintext have a value which is not p, then throw an OperationError.
  1034. // 5. Let plaintext be the result of removing p octets from the end of paddedPlaintext.
  1035. // Note that LibCrypto already does the padding removal for us.
  1036. // In the case that any issues arise (e.g. inconsistent padding), the padding is instead not trimmed.
  1037. // This is *ONLY* meaningful for the specific case of PaddingMode::CMS, as this is the only padding mode that always appends a block.
  1038. if (plaintext.size() == ciphertext.size()) {
  1039. // Padding was not removed for an unknown reason. Apply Step 4:
  1040. return WebIDL::OperationError::create(m_realm, "Inconsistent padding"_string);
  1041. }
  1042. // 6. Return the result of creating an ArrayBuffer containing plaintext.
  1043. return JS::ArrayBuffer::create(m_realm, move(plaintext));
  1044. }
  1045. // https://w3c.github.io/webcrypto/#aes-cbc-operations
  1046. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> AesCbc::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1047. {
  1048. // 1. If usages contains an entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1049. for (auto& usage : key_usages) {
  1050. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1051. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1052. }
  1053. }
  1054. // 2.
  1055. ByteBuffer data;
  1056. if (format == Bindings::KeyFormat::Raw) {
  1057. // -> If format is "raw":
  1058. // 1. Let data be the octet string contained in keyData.
  1059. // 2. If the length in bits of data is not 128, 192 or 256 then throw a DataError.
  1060. data = key_data.get<ByteBuffer>();
  1061. auto length_in_bits = data.size() * 8;
  1062. if (length_in_bits != 128 && length_in_bits != 192 && length_in_bits != 256) {
  1063. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key length '{}' bits (must be either 128, 192, or 256 bits)", length_in_bits)));
  1064. }
  1065. } else if (format == Bindings::KeyFormat::Jwk) {
  1066. // -> If format is "jwk":
  1067. // 1. -> If keyData is a JsonWebKey dictionary:
  1068. // Let jwk equal keyData.
  1069. // -> Otherwise:
  1070. // Throw a DataError.
  1071. if (!key_data.has<Bindings::JsonWebKey>())
  1072. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  1073. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  1074. // 2. If the kty field of jwk is not "oct", then throw a DataError.
  1075. if (jwk.kty != "oct"_string)
  1076. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  1077. // 3. If jwk does not meet the requirements of Section 6.4 of JSON Web Algorithms [JWA], then throw a DataError.
  1078. // Specifically, those requirements are:
  1079. // - ".k" is a valid bas64url encoded octet stream, which we do by just parsing it, in step 4.
  1080. // - ".alg" is checked only in step 5.
  1081. // 4. Let data be the octet string obtained by decoding the k field of jwk.
  1082. data = TRY(parse_jwk_symmetric_key(m_realm, jwk));
  1083. // 5. -> If data has length 128 bits:
  1084. // If the alg field of jwk is present, and is not "A128CBC", then throw a DataError.
  1085. // -> If data has length 192 bits:
  1086. // If the alg field of jwk is present, and is not "A192CBC", then throw a DataError.
  1087. // -> If data has length 256 bits:
  1088. // If the alg field of jwk is present, and is not "A256CBC", then throw a DataError.
  1089. // -> Otherwise:
  1090. // throw a DataError.
  1091. auto data_bits = data.size() * 8;
  1092. auto const& alg = jwk.alg;
  1093. if (data_bits == 128) {
  1094. if (alg.has_value() && alg != "A128CBC") {
  1095. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 128 bits, but alg specifies non-128-bit algorithm"_string);
  1096. }
  1097. } else if (data_bits == 192) {
  1098. if (alg.has_value() && alg != "A192CBC") {
  1099. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 192 bits, but alg specifies non-192-bit algorithm"_string);
  1100. }
  1101. } else if (data_bits == 256) {
  1102. if (alg.has_value() && alg != "A256CBC") {
  1103. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 256 bits, but alg specifies non-256-bit algorithm"_string);
  1104. }
  1105. } else {
  1106. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key size: {} bits", data_bits)));
  1107. }
  1108. // 6. If usages is non-empty and the use field of jwk is present and is not "enc", then throw a DataError.
  1109. if (!key_usages.is_empty() && jwk.use.has_value() && *jwk.use != "enc"_string)
  1110. return WebIDL::DataError::create(m_realm, "Invalid use field"_string);
  1111. // 7. If the key_ops field of jwk is present, and is invalid according to the
  1112. // requirements of JSON Web Key [JWK] or does not contain all of the specified usages
  1113. // values, then throw a DataError.
  1114. TRY(validate_jwk_key_ops(m_realm, jwk, key_usages));
  1115. // 8. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  1116. if (jwk.ext.has_value() && !*jwk.ext && extractable)
  1117. return WebIDL::DataError::create(m_realm, "Invalid ext field"_string);
  1118. } else {
  1119. // Otherwise:
  1120. // throw a NotSupportedError
  1121. return WebIDL::NotSupportedError::create(m_realm, "Only raw and jwk formats are supported"_string);
  1122. }
  1123. // 3. Let key be a new CryptoKey object representing an AES key with value data.
  1124. auto data_bits = data.size() * 8;
  1125. auto key = CryptoKey::create(m_realm, move(data));
  1126. // 4. Set the [[type]] internal slot of key to "secret".
  1127. key->set_type(Bindings::KeyType::Secret);
  1128. // 5. Let algorithm be a new AesKeyAlgorithm.
  1129. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1130. // 6. Set the name attribute of algorithm to "AES-CBC".
  1131. algorithm->set_name("AES-CBC"_string);
  1132. // 7. Set the length attribute of algorithm to the length, in bits, of data.
  1133. algorithm->set_length(data_bits);
  1134. // 8. Set the [[algorithm]] internal slot of key to algorithm.
  1135. key->set_algorithm(algorithm);
  1136. // 9. Return key.
  1137. return key;
  1138. }
  1139. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> AesCbc::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1140. {
  1141. // 1. If usages contains any entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1142. for (auto const& usage : key_usages) {
  1143. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1144. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1145. }
  1146. }
  1147. auto const& normalized_algorithm = static_cast<AesKeyGenParams const&>(params);
  1148. // 2. If the length member of normalizedAlgorithm is not equal to one of 128, 192 or 256, then throw an OperationError.
  1149. auto const bits = normalized_algorithm.length;
  1150. if (bits != 128 && bits != 192 && bits != 256) {
  1151. return WebIDL::OperationError::create(m_realm, MUST(String::formatted("Cannot create AES-CBC key with unusual amount of {} bits", bits)));
  1152. }
  1153. // 3. Generate an AES key of length equal to the length member of normalizedAlgorithm.
  1154. auto key_buffer = TRY(generate_random_key(m_realm->vm(), bits));
  1155. // 4. If the key generation step fails, then throw an OperationError.
  1156. // Note: Cannot happen in our implementation; and if we OOM, then allocating the Exception is probably going to crash anyway.
  1157. // 5. Let key be a new CryptoKey object representing the generated AES key.
  1158. auto key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_buffer });
  1159. // 6. Let algorithm be a new AesKeyAlgorithm.
  1160. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1161. // 7. Set the name attribute of algorithm to "AES-CBC".
  1162. algorithm->set_name("AES-CBC"_string);
  1163. // 8. Set the length attribute of algorithm to equal the length member of normalizedAlgorithm.
  1164. algorithm->set_length(bits);
  1165. // 9. Set the [[type]] internal slot of key to "secret".
  1166. key->set_type(Bindings::KeyType::Secret);
  1167. // 10. Set the [[algorithm]] internal slot of key to algorithm.
  1168. key->set_algorithm(algorithm);
  1169. // 11. Set the [[extractable]] internal slot of key to be extractable.
  1170. key->set_extractable(extractable);
  1171. // 12. Set the [[usages]] internal slot of key to be usages.
  1172. key->set_usages(key_usages);
  1173. // 13. Return key.
  1174. return { key };
  1175. }
  1176. WebIDL::ExceptionOr<GC::Ref<JS::Object>> AesCbc::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  1177. {
  1178. // 1. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  1179. // Note: In our impl this is always accessible
  1180. auto const& handle = key->handle();
  1181. GC::Ptr<JS::Object> result = nullptr;
  1182. // 2. -> If format is "raw":
  1183. if (format == Bindings::KeyFormat::Raw) {
  1184. // 1. Let data be the raw octets of the key represented by [[handle]] internal slot of key.
  1185. auto data = handle.get<ByteBuffer>();
  1186. // 2. Let result be the result of creating an ArrayBuffer containing data.
  1187. result = JS::ArrayBuffer::create(m_realm, data);
  1188. }
  1189. // -> If format is "jwk":
  1190. else if (format == Bindings::KeyFormat::Jwk) {
  1191. // 1. Let jwk be a new JsonWebKey dictionary.
  1192. Bindings::JsonWebKey jwk = {};
  1193. // 2. Set the kty attribute of jwk to the string "oct".
  1194. jwk.kty = "oct"_string;
  1195. // 3. Set the k attribute of jwk to be a string containing the raw octets of the key represented by [[handle]] internal slot of key, encoded according to Section 6.4 of JSON Web Algorithms [JWA].
  1196. auto const& key_bytes = handle.get<ByteBuffer>();
  1197. jwk.k = TRY_OR_THROW_OOM(m_realm->vm(), encode_base64url(key_bytes, AK::OmitPadding::Yes));
  1198. // 4. -> If the length attribute of key is 128:
  1199. // Set the alg attribute of jwk to the string "A128CBC".
  1200. // -> If the length attribute of key is 192:
  1201. // Set the alg attribute of jwk to the string "A192CBC".
  1202. // -> If the length attribute of key is 256:
  1203. // Set the alg attribute of jwk to the string "A256CBC".
  1204. auto key_bits = key_bytes.size() * 8;
  1205. if (key_bits == 128) {
  1206. jwk.alg = "A128CBC"_string;
  1207. } else if (key_bits == 192) {
  1208. jwk.alg = "A192CBC"_string;
  1209. } else if (key_bits == 256) {
  1210. jwk.alg = "A256CBC"_string;
  1211. } else {
  1212. return WebIDL::OperationError::create(m_realm, "unclear key size"_string);
  1213. }
  1214. // 5. Set the key_ops attribute of jwk to equal the usages attribute of key.
  1215. jwk.key_ops = Vector<String> {};
  1216. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  1217. for (auto const& usage : key->internal_usages()) {
  1218. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  1219. }
  1220. // 6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of key.
  1221. jwk.ext = key->extractable();
  1222. // 7. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  1223. result = TRY(jwk.to_object(m_realm));
  1224. }
  1225. // -> Otherwise:
  1226. else {
  1227. // throw a NotSupportedError.
  1228. return WebIDL::NotSupportedError::create(m_realm, "Cannot export to unsupported format"_string);
  1229. }
  1230. // 3. Return result.
  1231. return GC::Ref { *result };
  1232. }
  1233. WebIDL::ExceptionOr<JS::Value> AesCbc::get_key_length(AlgorithmParams const& params)
  1234. {
  1235. // 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then throw an OperationError.
  1236. auto const& normalized_algorithm = static_cast<AesDerivedKeyParams const&>(params);
  1237. auto length = normalized_algorithm.length;
  1238. if (length != 128 && length != 192 && length != 256)
  1239. return WebIDL::OperationError::create(m_realm, "Invalid key length"_string);
  1240. // 2. Return the length member of normalizedDerivedKeyAlgorithm.
  1241. return JS::Value(length);
  1242. }
  1243. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> AesCtr::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1244. {
  1245. // 1. If usages contains an entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1246. for (auto& usage : key_usages) {
  1247. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1248. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1249. }
  1250. }
  1251. ByteBuffer data;
  1252. // 2. If format is "raw":
  1253. if (format == Bindings::KeyFormat::Raw) {
  1254. // 1. Let data be the octet string contained in keyData.
  1255. data = key_data.get<ByteBuffer>();
  1256. // 2. If the length in bits of data is not 128, 192 or 256 then throw a DataError.
  1257. auto length_in_bits = data.size() * 8;
  1258. if (length_in_bits != 128 && length_in_bits != 192 && length_in_bits != 256) {
  1259. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key length '{}' bits (must be either 128, 192, or 256 bits)", length_in_bits)));
  1260. }
  1261. }
  1262. // 2. If format is "jwk":
  1263. else if (format == Bindings::KeyFormat::Jwk) {
  1264. // 1. -> If keyData is a JsonWebKey dictionary:
  1265. // Let jwk equal keyData.
  1266. // -> Otherwise:
  1267. // Throw a DataError.
  1268. if (!key_data.has<Bindings::JsonWebKey>())
  1269. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  1270. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  1271. // 2. If the kty field of jwk is not "oct", then throw a DataError.
  1272. if (jwk.kty != "oct"_string)
  1273. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  1274. // 3. If jwk does not meet the requirements of Section 6.4 of JSON Web Algorithms [JWA], then throw a DataError.
  1275. // Specifically, those requirements are:
  1276. // * the member "k" is used to represent a symmetric key (or another key whose value is a single octet sequence).
  1277. // * An "alg" member SHOULD also be present to identify the algorithm intended to be used with the key,
  1278. // unless the application uses another means or convention to determine the algorithm used.
  1279. if (!jwk.k.has_value())
  1280. return WebIDL::DataError::create(m_realm, "Missing 'k' field"_string);
  1281. if (!jwk.alg.has_value())
  1282. return WebIDL::DataError::create(m_realm, "Missing 'alg' field"_string);
  1283. // 4. Let data be the octet string obtained by decoding the k field of jwk.
  1284. data = TRY(parse_jwk_symmetric_key(m_realm, jwk));
  1285. // 5. -> If data has length 128 bits:
  1286. // If the alg field of jwk is present, and is not "A128CTR", then throw a DataError.
  1287. // -> If data has length 192 bits:
  1288. // If the alg field of jwk is present, and is not "A192CTR", then throw a DataError.
  1289. // -> If data has length 256 bits:
  1290. // If the alg field of jwk is present, and is not "A256CTR", then throw a DataError.
  1291. // -> Otherwise:
  1292. // throw a DataError.
  1293. auto data_bits = data.size() * 8;
  1294. auto const& alg = jwk.alg;
  1295. if (data_bits == 128 && alg != "A128CTR") {
  1296. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 128 bits, but alg specifies non-128-bit algorithm"_string);
  1297. } else if (data_bits == 192 && alg != "A192CTR") {
  1298. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 192 bits, but alg specifies non-192-bit algorithm"_string);
  1299. } else if (data_bits == 256 && alg != "A256CTR") {
  1300. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 256 bits, but alg specifies non-256-bit algorithm"_string);
  1301. } else {
  1302. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key size: {} bits", data_bits)));
  1303. }
  1304. // 6. If usages is non-empty and the use field of jwk is present and is not "enc", then throw a DataError.
  1305. if (!key_usages.is_empty() && jwk.use.has_value() && *jwk.use != "enc"_string)
  1306. return WebIDL::DataError::create(m_realm, "Invalid use field"_string);
  1307. // 7. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK]
  1308. // or does not contain all of the specified usages values, then throw a DataError.
  1309. TRY(validate_jwk_key_ops(m_realm, jwk, key_usages));
  1310. // 8. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  1311. if (jwk.ext.has_value() && !*jwk.ext && extractable)
  1312. return WebIDL::DataError::create(m_realm, "Invalid ext field"_string);
  1313. }
  1314. // 2. Otherwise:
  1315. else {
  1316. // 1. throw a NotSupportedError.
  1317. return WebIDL::NotSupportedError::create(m_realm, "Only raw and jwk formats are supported"_string);
  1318. }
  1319. auto data_bits = data.size() * 8;
  1320. // 3. Let key be a new CryptoKey object representing an AES key with value data.
  1321. auto key = CryptoKey::create(m_realm, move(data));
  1322. // 4. Set the [[type]] internal slot of key to "secret".
  1323. key->set_type(Bindings::KeyType::Secret);
  1324. // 5. Let algorithm be a new AesKeyAlgorithm.
  1325. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1326. // 6. Set the name attribute of algorithm to "AES-CTR".
  1327. algorithm->set_name("AES-CTR"_string);
  1328. // 7. Set the length attribute of algorithm to the length, in bits, of data.
  1329. algorithm->set_length(data_bits);
  1330. // 8. Set the [[algorithm]] internal slot of key to algorithm.
  1331. key->set_algorithm(algorithm);
  1332. // 9. Return key.
  1333. return key;
  1334. }
  1335. WebIDL::ExceptionOr<GC::Ref<JS::Object>> AesCtr::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  1336. {
  1337. // 1. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  1338. // Note: In our impl this is always accessible
  1339. GC::Ptr<JS::Object> result = nullptr;
  1340. // 2. If format is "raw":
  1341. if (format == Bindings::KeyFormat::Raw) {
  1342. // 1. Let data be the raw octets of the key represented by [[handle]] internal slot of key.
  1343. auto data = key->handle().get<ByteBuffer>();
  1344. // 2. Let result be the result of creating an ArrayBuffer containing data.
  1345. result = JS::ArrayBuffer::create(m_realm, data);
  1346. }
  1347. // 2. If format is "jwk":
  1348. else if (format == Bindings::KeyFormat::Jwk) {
  1349. // 1. Let jwk be a new JsonWebKey dictionary.
  1350. Bindings::JsonWebKey jwk = {};
  1351. // 2. Set the kty attribute of jwk to the string "oct".
  1352. jwk.kty = "oct"_string;
  1353. // 3. Set the k attribute of jwk to be a string containing the raw octets of the key represented by [[handle]] internal slot of key,
  1354. // encoded according to Section 6.4 of JSON Web Algorithms [JWA].
  1355. auto const& key_bytes = key->handle().get<ByteBuffer>();
  1356. jwk.k = TRY_OR_THROW_OOM(m_realm->vm(), encode_base64url(key_bytes, AK::OmitPadding::Yes));
  1357. // 4. -> If the length attribute of key is 128:
  1358. // Set the alg attribute of jwk to the string "A128CTR".
  1359. // -> If the length attribute of key is 192:
  1360. // Set the alg attribute of jwk to the string "A192CTR".
  1361. // -> If the length attribute of key is 256:
  1362. // Set the alg attribute of jwk to the string "A256CTR".
  1363. auto key_bits = key_bytes.size() * 8;
  1364. if (key_bits == 128) {
  1365. jwk.alg = "A128CTR"_string;
  1366. } else if (key_bits == 192) {
  1367. jwk.alg = "A192CTR"_string;
  1368. } else if (key_bits == 256) {
  1369. jwk.alg = "A256CTR"_string;
  1370. }
  1371. // 5. Set the key_ops attribute of jwk to the usages attribute of key.
  1372. jwk.key_ops = Vector<String> {};
  1373. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  1374. for (auto const& usage : key->internal_usages()) {
  1375. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  1376. }
  1377. // 6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of key.
  1378. jwk.ext = key->extractable();
  1379. // 7. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  1380. result = TRY(jwk.to_object(m_realm));
  1381. }
  1382. // 2. Otherwise:
  1383. else {
  1384. // 1. throw a NotSupportedError.
  1385. return WebIDL::NotSupportedError::create(m_realm, "Cannot export to unsupported format"_string);
  1386. }
  1387. // 3. Return result.
  1388. return GC::Ref { *result };
  1389. }
  1390. WebIDL::ExceptionOr<JS::Value> AesCtr::get_key_length(AlgorithmParams const& params)
  1391. {
  1392. // 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then throw a OperationError.
  1393. auto const& normalized_algorithm = static_cast<AesDerivedKeyParams const&>(params);
  1394. auto length = normalized_algorithm.length;
  1395. if (length != 128 && length != 192 && length != 256)
  1396. return WebIDL::OperationError::create(m_realm, "Invalid key length"_string);
  1397. // 2. Return the length member of normalizedDerivedKeyAlgorithm.
  1398. return JS::Value(length);
  1399. }
  1400. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> AesCtr::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1401. {
  1402. // 1. If usages contains any entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1403. for (auto const& usage : key_usages) {
  1404. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1405. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1406. }
  1407. }
  1408. // 2. If the length member of normalizedAlgorithm is not equal to one of 128, 192 or 256, then throw an OperationError.
  1409. auto const& normalized_algorithm = static_cast<AesKeyGenParams const&>(params);
  1410. auto const bits = normalized_algorithm.length;
  1411. if (bits != 128 && bits != 192 && bits != 256) {
  1412. return WebIDL::OperationError::create(m_realm, MUST(String::formatted("Cannot create AES-CTR key with unusual amount of {} bits", bits)));
  1413. }
  1414. // 3. Generate an AES key of length equal to the length member of normalizedAlgorithm.
  1415. // 4. If the key generation step fails, then throw an OperationError.
  1416. auto key_buffer = TRY(generate_random_key(m_realm->vm(), bits));
  1417. // 5. Let key be a new CryptoKey object representing the generated AES key.
  1418. auto key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_buffer });
  1419. // 6. Let algorithm be a new AesKeyAlgorithm.
  1420. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1421. // 7. Set the name attribute of algorithm to "AES-CTR".
  1422. algorithm->set_name("AES-CTR"_string);
  1423. // 8. Set the length attribute of algorithm to equal the length member of normalizedAlgorithm.
  1424. algorithm->set_length(bits);
  1425. // 9. Set the [[type]] internal slot of key to "secret".
  1426. key->set_type(Bindings::KeyType::Secret);
  1427. // 10. Set the [[algorithm]] internal slot of key to algorithm.
  1428. key->set_algorithm(algorithm);
  1429. // 11. Set the [[extractable]] internal slot of key to be extractable.
  1430. key->set_extractable(extractable);
  1431. // 12. Set the [[usages]] internal slot of key to be usages.
  1432. key->set_usages(key_usages);
  1433. // 13. Return key.
  1434. return { key };
  1435. }
  1436. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesCtr::encrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& plaintext)
  1437. {
  1438. // 1. If the counter member of normalizedAlgorithm does not have length 16 bytes, then throw an OperationError.
  1439. auto const& normalized_algorithm = static_cast<AesCtrParams const&>(params);
  1440. auto const& counter = normalized_algorithm.counter;
  1441. if (counter.size() != 16)
  1442. return WebIDL::OperationError::create(m_realm, "Invalid counter length"_string);
  1443. // 2. If the length member of normalizedAlgorithm is zero or is greater than 128, then throw an OperationError.
  1444. auto const& length = normalized_algorithm.length;
  1445. if (length == 0 || length > 128)
  1446. return WebIDL::OperationError::create(m_realm, "Invalid length"_string);
  1447. // 3. Let ciphertext be the result of performing the CTR Encryption operation described in Section 6.5 of [NIST-SP800-38A] using
  1448. // AES as the block cipher,
  1449. // the contents of the counter member of normalizedAlgorithm as the initial value of the counter block,
  1450. // the length member of normalizedAlgorithm as the input parameter m to the standard counter block incrementing function defined in Appendix B.1 of [NIST-SP800-38A]
  1451. // and the contents of plaintext as the input plaintext.
  1452. auto& aes_algorithm = static_cast<AesKeyAlgorithm const&>(*key->algorithm());
  1453. auto key_length = aes_algorithm.length();
  1454. auto key_bytes = key->handle().get<ByteBuffer>();
  1455. ::Crypto::Cipher::AESCipher::CTRMode cipher(key_bytes, key_length, ::Crypto::Cipher::Intent::Encryption);
  1456. ByteBuffer ciphertext = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::create_zeroed(plaintext.size()));
  1457. Bytes ciphertext_span = ciphertext.bytes();
  1458. cipher.encrypt(plaintext, ciphertext_span, counter);
  1459. // 4. Return the result of creating an ArrayBuffer containing plaintext.
  1460. return JS::ArrayBuffer::create(m_realm, ciphertext);
  1461. }
  1462. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesCtr::decrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& ciphertext)
  1463. {
  1464. // 1. If the counter member of normalizedAlgorithm does not have length 16 bytes, then throw an OperationError.
  1465. auto const& normalized_algorithm = static_cast<AesCtrParams const&>(params);
  1466. auto const& counter = normalized_algorithm.counter;
  1467. if (counter.size() != 16)
  1468. return WebIDL::OperationError::create(m_realm, "Invalid counter length"_string);
  1469. // 2. If the length member of normalizedAlgorithm is zero or is greater than 128, then throw an OperationError.
  1470. auto const& length = normalized_algorithm.length;
  1471. if (length == 0 || length > 128)
  1472. return WebIDL::OperationError::create(m_realm, "Invalid length"_string);
  1473. // 3. Let plaintext be the result of performing the CTR Decryption operation described in Section 6.5 of [NIST-SP800-38A] using
  1474. // AES as the block cipher,
  1475. // the contents of the counter member of normalizedAlgorithm as the initial value of the counter block,
  1476. // the length member of normalizedAlgorithm as the input parameter m to the standard counter block incrementing function defined in Appendix B.1 of [NIST-SP800-38A]
  1477. // and the contents of ciphertext as the input ciphertext.
  1478. auto& aes_algorithm = static_cast<AesKeyAlgorithm const&>(*key->algorithm());
  1479. auto key_length = aes_algorithm.length();
  1480. auto key_bytes = key->handle().get<ByteBuffer>();
  1481. ::Crypto::Cipher::AESCipher::CTRMode cipher(key_bytes, key_length, ::Crypto::Cipher::Intent::Decryption);
  1482. ByteBuffer plaintext = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::create_zeroed(ciphertext.size()));
  1483. Bytes plaintext_span = plaintext.bytes();
  1484. cipher.decrypt(ciphertext, plaintext_span, counter);
  1485. // 4. Return the result of creating an ArrayBuffer containing plaintext.
  1486. return JS::ArrayBuffer::create(m_realm, plaintext);
  1487. }
  1488. WebIDL::ExceptionOr<JS::Value> AesGcm::get_key_length(AlgorithmParams const& params)
  1489. {
  1490. // 1. If the length member of normalizedDerivedKeyAlgorithm is not 128, 192 or 256, then throw a OperationError.
  1491. auto const& normalized_algorithm = static_cast<AesDerivedKeyParams const&>(params);
  1492. auto length = normalized_algorithm.length;
  1493. if (length != 128 && length != 192 && length != 256)
  1494. return WebIDL::OperationError::create(m_realm, "Invalid key length"_string);
  1495. // 2. Return the length member of normalizedDerivedKeyAlgorithm.
  1496. return JS::Value(length);
  1497. }
  1498. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> AesGcm::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1499. {
  1500. // 1. If usages contains an entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1501. for (auto& usage : key_usages) {
  1502. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1503. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1504. }
  1505. }
  1506. ByteBuffer data;
  1507. // 2. If format is "raw":
  1508. if (format == Bindings::KeyFormat::Raw) {
  1509. // 1. Let data be the octet string contained in keyData.
  1510. data = key_data.get<ByteBuffer>();
  1511. // 2. If the length in bits of data is not 128, 192 or 256 then throw a DataError.
  1512. auto length_in_bits = data.size() * 8;
  1513. if (length_in_bits != 128 && length_in_bits != 192 && length_in_bits != 256) {
  1514. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key length '{}' bits (must be either 128, 192, or 256 bits)", length_in_bits)));
  1515. }
  1516. }
  1517. // 2. If format is "jwk":
  1518. else if (format == Bindings::KeyFormat::Jwk) {
  1519. // 1. -> If keyData is a JsonWebKey dictionary:
  1520. // Let jwk equal keyData.
  1521. // -> Otherwise:
  1522. // Throw a DataError.
  1523. if (!key_data.has<Bindings::JsonWebKey>())
  1524. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  1525. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  1526. // 2. If the kty field of jwk is not "oct", then throw a DataError.
  1527. if (jwk.kty != "oct"_string)
  1528. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  1529. // 3. If jwk does not meet the requirements of Section 6.4 of JSON Web Algorithms [JWA], then throw a DataError.
  1530. // Specifically, those requirements are:
  1531. // * the member "k" is used to represent a symmetric key (or another key whose value is a single octet sequence).
  1532. // * An "alg" member SHOULD also be present to identify the algorithm intended to be used with the key,
  1533. // unless the application uses another means or convention to determine the algorithm used.
  1534. if (!jwk.k.has_value())
  1535. return WebIDL::DataError::create(m_realm, "Missing 'k' field"_string);
  1536. if (!jwk.alg.has_value())
  1537. return WebIDL::DataError::create(m_realm, "Missing 'alg' field"_string);
  1538. // 4. Let data be the octet string obtained by decoding the k field of jwk.
  1539. data = TRY(parse_jwk_symmetric_key(m_realm, jwk));
  1540. // 5. -> If data has length 128 bits:
  1541. // If the alg field of jwk is present, and is not "A128GCM", then throw a DataError.
  1542. // -> If data has length 192 bits:
  1543. // If the alg field of jwk is present, and is not "A192GCM", then throw a DataError.
  1544. // -> If data has length 256 bits:
  1545. // If the alg field of jwk is present, and is not "A256GCM", then throw a DataError.
  1546. // -> Otherwise:
  1547. // throw a DataError.
  1548. auto data_bits = data.size() * 8;
  1549. auto const& alg = jwk.alg;
  1550. if (data_bits == 128 && alg != "A128GCM") {
  1551. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 128 bits, but alg specifies non-128-bit algorithm"_string);
  1552. } else if (data_bits == 192 && alg != "A192GCM") {
  1553. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 192 bits, but alg specifies non-192-bit algorithm"_string);
  1554. } else if (data_bits == 256 && alg != "A256GCM") {
  1555. return WebIDL::DataError::create(m_realm, "Contradictory key size: key has 256 bits, but alg specifies non-256-bit algorithm"_string);
  1556. } else {
  1557. return WebIDL::DataError::create(m_realm, MUST(String::formatted("Invalid key size: {} bits", data_bits)));
  1558. }
  1559. // 6. If usages is non-empty and the use field of jwk is present and is not "enc", then throw a DataError.
  1560. if (!key_usages.is_empty() && jwk.use.has_value() && *jwk.use != "enc"_string)
  1561. return WebIDL::DataError::create(m_realm, "Invalid use field"_string);
  1562. // 7. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK]
  1563. // or does not contain all of the specified usages values, then throw a DataError.
  1564. TRY(validate_jwk_key_ops(m_realm, jwk, key_usages));
  1565. // 8. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  1566. if (jwk.ext.has_value() && !*jwk.ext && extractable)
  1567. return WebIDL::DataError::create(m_realm, "Invalid ext field"_string);
  1568. }
  1569. // 2. Otherwise:
  1570. else {
  1571. // 1. throw a NotSupportedError.
  1572. return WebIDL::NotSupportedError::create(m_realm, "Only raw and jwk formats are supported"_string);
  1573. }
  1574. auto data_bits = data.size() * 8;
  1575. // 3. Let key be a new CryptoKey object representing an AES key with value data.
  1576. auto key = CryptoKey::create(m_realm, move(data));
  1577. // 4. Set the [[type]] internal slot of key to "secret".
  1578. key->set_type(Bindings::KeyType::Secret);
  1579. // 5. Let algorithm be a new AesKeyAlgorithm.
  1580. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1581. // 6. Set the name attribute of algorithm to "AES-GCM".
  1582. algorithm->set_name("AES-GCM"_string);
  1583. // 7. Set the length attribute of algorithm to the length, in bits, of data.
  1584. algorithm->set_length(data_bits);
  1585. // 8. Set the [[algorithm]] internal slot of key to algorithm.
  1586. key->set_algorithm(algorithm);
  1587. // 9. Return key.
  1588. return key;
  1589. }
  1590. WebIDL::ExceptionOr<GC::Ref<JS::Object>> AesGcm::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  1591. {
  1592. // 1. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  1593. // Note: In our impl this is always accessible
  1594. GC::Ptr<JS::Object> result = nullptr;
  1595. // 2. If format is "raw":
  1596. if (format == Bindings::KeyFormat::Raw) {
  1597. // 1. Let data be the raw octets of the key represented by [[handle]] internal slot of key.
  1598. auto data = key->handle().get<ByteBuffer>();
  1599. // 2. Let result be the result of creating an ArrayBuffer containing data.
  1600. result = JS::ArrayBuffer::create(m_realm, data);
  1601. }
  1602. // 2. If format is "jwk":
  1603. else if (format == Bindings::KeyFormat::Jwk) {
  1604. // 1. Let jwk be a new JsonWebKey dictionary.
  1605. Bindings::JsonWebKey jwk = {};
  1606. // 2. Set the kty attribute of jwk to the string "oct".
  1607. jwk.kty = "oct"_string;
  1608. // 3. Set the k attribute of jwk to be a string containing the raw octets of the key represented by [[handle]] internal slot of key,
  1609. // encoded according to Section 6.4 of JSON Web Algorithms [JWA].
  1610. auto const& key_bytes = key->handle().get<ByteBuffer>();
  1611. jwk.k = TRY_OR_THROW_OOM(m_realm->vm(), encode_base64url(key_bytes, AK::OmitPadding::Yes));
  1612. // 4. -> If the length attribute of key is 128:
  1613. // Set the alg attribute of jwk to the string "A128GCM".
  1614. // -> If the length attribute of key is 192:
  1615. // Set the alg attribute of jwk to the string "A192GCM".
  1616. // -> If the length attribute of key is 256:
  1617. // Set the alg attribute of jwk to the string "A256GCM".
  1618. auto key_bits = key_bytes.size() * 8;
  1619. if (key_bits == 128) {
  1620. jwk.alg = "A128GCM"_string;
  1621. } else if (key_bits == 192) {
  1622. jwk.alg = "A192GCM"_string;
  1623. } else if (key_bits == 256) {
  1624. jwk.alg = "A256GCM"_string;
  1625. }
  1626. // 5. Set the key_ops attribute of jwk to the usages attribute of key.
  1627. jwk.key_ops = Vector<String> {};
  1628. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  1629. for (auto const& usage : key->internal_usages()) {
  1630. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  1631. }
  1632. // 6. Set the ext attribute of jwk to equal the [[extractable]] internal slot of key.
  1633. jwk.ext = key->extractable();
  1634. // 7. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  1635. result = TRY(jwk.to_object(m_realm));
  1636. }
  1637. // 2. Otherwise:
  1638. else {
  1639. // 1. throw a NotSupportedError.
  1640. return WebIDL::NotSupportedError::create(m_realm, "Cannot export to unsupported format"_string);
  1641. }
  1642. // 3. Return result.
  1643. return GC::Ref { *result };
  1644. }
  1645. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesGcm::encrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& plaintext)
  1646. {
  1647. auto const& normalized_algorithm = static_cast<AesGcmParams const&>(params);
  1648. // FIXME: 1. If plaintext has a length greater than 2^39 - 256 bytes, then throw an OperationError.
  1649. // FIXME: 2. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes, then throw an OperationError.
  1650. // FIXME: 3. If the additionalData member of normalizedAlgorithm is present and has a length greater than 2^64 - 1 bytes, then throw an OperationError.
  1651. // 4. If the tagLength member of normalizedAlgorithm is not present: Let tagLength be 128.
  1652. auto tag_length = 0;
  1653. auto to_compare_against = Vector<int> { 32, 64, 96, 104, 112, 120, 128 };
  1654. if (!normalized_algorithm.tag_length.has_value())
  1655. tag_length = 128;
  1656. // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128: Let tagLength be equal to the tagLength member of normalizedAlgorithm
  1657. else if (to_compare_against.contains_slow(normalized_algorithm.tag_length.value()))
  1658. tag_length = normalized_algorithm.tag_length.value();
  1659. // Otherwise: throw an OperationError.
  1660. else
  1661. return WebIDL::OperationError::create(m_realm, "Invalid tag length"_string);
  1662. // 5. Let additionalData be the contents of the additionalData member of normalizedAlgorithm if present or the empty octet string otherwise.
  1663. auto additional_data = normalized_algorithm.additional_data.value_or(ByteBuffer {});
  1664. // 6. Let C and T be the outputs that result from performing the Authenticated Encryption Function described in Section 7.1 of [NIST-SP800-38D] using
  1665. // AES as the block cipher,
  1666. // the contents of the iv member of normalizedAlgorithm as the IV input parameter,
  1667. // the contents of additionalData as the A input parameter,
  1668. // tagLength as the t pre-requisite
  1669. // and the contents of plaintext as the input plaintext.
  1670. auto& aes_algorithm = static_cast<AesKeyAlgorithm const&>(*key->algorithm());
  1671. auto key_length = aes_algorithm.length();
  1672. auto key_bytes = key->handle().get<ByteBuffer>();
  1673. ::Crypto::Cipher::AESCipher::GCMMode cipher(key_bytes, key_length, ::Crypto::Cipher::Intent::Encryption);
  1674. ByteBuffer ciphertext = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::create_zeroed(plaintext.size()));
  1675. ByteBuffer tag = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::create_zeroed(tag_length / 8));
  1676. [[maybe_unused]] Bytes ciphertext_span = ciphertext.bytes();
  1677. [[maybe_unused]] Bytes tag_span = tag.bytes();
  1678. // FIXME: cipher.encrypt(plaintext, ciphertext_span, normalized_algorithm.iv, additional_data, tag_span);
  1679. // 7. Let ciphertext be equal to C | T, where '|' denotes concatenation.
  1680. TRY_OR_THROW_OOM(m_realm->vm(), ciphertext.try_append(tag));
  1681. // 8. Return the result of creating an ArrayBuffer containing ciphertext.
  1682. return JS::ArrayBuffer::create(m_realm, ciphertext);
  1683. }
  1684. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> AesGcm::decrypt(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& ciphertext)
  1685. {
  1686. auto const& normalized_algorithm = static_cast<AesGcmParams const&>(params);
  1687. // 1. If the tagLength member of normalizedAlgorithm is not present: Let tagLength be 128.
  1688. u32 tag_length = 0;
  1689. auto to_compare_against = Vector<u32> { 32, 64, 96, 104, 112, 120, 128 };
  1690. if (!normalized_algorithm.tag_length.has_value())
  1691. tag_length = 128;
  1692. // If the tagLength member of normalizedAlgorithm is one of 32, 64, 96, 104, 112, 120 or 128: Let tagLength be equal to the tagLength member of normalizedAlgorithm
  1693. else if (to_compare_against.contains_slow(normalized_algorithm.tag_length.value()))
  1694. tag_length = normalized_algorithm.tag_length.value();
  1695. // Otherwise: throw an OperationError.
  1696. else
  1697. return WebIDL::OperationError::create(m_realm, "Invalid tag length"_string);
  1698. // 2. If ciphertext has a length less than tagLength bits, then throw an OperationError.
  1699. if (ciphertext.size() < tag_length / 8)
  1700. return WebIDL::OperationError::create(m_realm, "Invalid ciphertext length"_string);
  1701. // FIXME: 3. If the iv member of normalizedAlgorithm has a length greater than 2^64 - 1 bytes, then throw an OperationError.
  1702. // FIXME: 4. If the additionalData member of normalizedAlgorithm is present and has a length greater than 2^64 - 1 bytes, then throw an OperationError.
  1703. // 5. Let tag be the last tagLength bits of ciphertext.
  1704. auto tag_bits = tag_length / 8;
  1705. auto tag = TRY_OR_THROW_OOM(m_realm->vm(), ciphertext.slice(ciphertext.size() - tag_bits, tag_bits));
  1706. // 6. Let actualCiphertext be the result of removing the last tagLength bits from ciphertext.
  1707. auto actual_ciphertext = TRY_OR_THROW_OOM(m_realm->vm(), ciphertext.slice(0, ciphertext.size() - tag_bits));
  1708. // 7. Let additionalData be the contents of the additionalData member of normalizedAlgorithm if present or the empty octet string otherwise.
  1709. auto additional_data = normalized_algorithm.additional_data.value_or(ByteBuffer {});
  1710. // 8. Perform the Authenticated Decryption Function described in Section 7.2 of [NIST-SP800-38D] using
  1711. // AES as the block cipher,
  1712. // the contents of the iv member of normalizedAlgorithm as the IV input parameter,
  1713. // the contents of additionalData as the A input parameter,
  1714. // tagLength as the t pre-requisite,
  1715. // the contents of actualCiphertext as the input ciphertext, C
  1716. // and the contents of tag as the authentication tag, T.
  1717. auto& aes_algorithm = static_cast<AesKeyAlgorithm const&>(*key->algorithm());
  1718. auto key_length = aes_algorithm.length();
  1719. auto key_bytes = key->handle().get<ByteBuffer>();
  1720. ::Crypto::Cipher::AESCipher::GCMMode cipher(key_bytes, key_length, ::Crypto::Cipher::Intent::Decryption);
  1721. ByteBuffer plaintext = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::create_zeroed(actual_ciphertext.size()));
  1722. [[maybe_unused]] Bytes plaintext_span = plaintext.bytes();
  1723. [[maybe_unused]] Bytes actual_ciphertext_span = actual_ciphertext.bytes();
  1724. [[maybe_unused]] Bytes tag_span = tag.bytes();
  1725. // FIXME: auto result = cipher.decrypt(ciphertext, plaintext_span, normalized_algorithm.iv, additional_data, tag_span);
  1726. auto result = ::Crypto::VerificationConsistency::Inconsistent;
  1727. // If the result of the algorithm is the indication of inauthenticity, "FAIL": throw an OperationError
  1728. if (result == ::Crypto::VerificationConsistency::Inconsistent)
  1729. return WebIDL::OperationError::create(m_realm, "Decryption failed"_string);
  1730. // Otherwise: Let plaintext be the output P of the Authenticated Decryption Function.
  1731. // 9. Return the result of creating an ArrayBuffer containing plaintext.
  1732. return JS::ArrayBuffer::create(m_realm, plaintext);
  1733. }
  1734. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> AesGcm::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1735. {
  1736. // 1. If usages contains any entry which is not one of "encrypt", "decrypt", "wrapKey" or "unwrapKey", then throw a SyntaxError.
  1737. for (auto const& usage : key_usages) {
  1738. if (usage != Bindings::KeyUsage::Encrypt && usage != Bindings::KeyUsage::Decrypt && usage != Bindings::KeyUsage::Wrapkey && usage != Bindings::KeyUsage::Unwrapkey) {
  1739. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1740. }
  1741. }
  1742. // 2. If the length member of normalizedAlgorithm is not equal to one of 128, 192 or 256, then throw an OperationError.
  1743. auto const& normalized_algorithm = static_cast<AesKeyGenParams const&>(params);
  1744. auto const bits = normalized_algorithm.length;
  1745. if (bits != 128 && bits != 192 && bits != 256) {
  1746. return WebIDL::OperationError::create(m_realm, MUST(String::formatted("Cannot create AES-GCM key with unusual amount of {} bits", bits)));
  1747. }
  1748. // 3. Generate an AES key of length equal to the length member of normalizedAlgorithm.
  1749. // 4. If the key generation step fails, then throw an OperationError.
  1750. auto key_buffer = TRY(generate_random_key(m_realm->vm(), bits));
  1751. // 5. Let key be a new CryptoKey object representing the generated AES key.
  1752. auto key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { key_buffer });
  1753. // 6. Let algorithm be a new AesKeyAlgorithm.
  1754. auto algorithm = AesKeyAlgorithm::create(m_realm);
  1755. // 7. Set the name attribute of algorithm to "AES-GCM".
  1756. algorithm->set_name("AES-GCM"_string);
  1757. // 8. Set the length attribute of algorithm to equal the length member of normalizedAlgorithm.
  1758. algorithm->set_length(bits);
  1759. // 9. Set the [[type]] internal slot of key to "secret".
  1760. key->set_type(Bindings::KeyType::Secret);
  1761. // 10. Set the [[algorithm]] internal slot of key to algorithm.
  1762. key->set_algorithm(algorithm);
  1763. // 11. Set the [[extractable]] internal slot of key to be extractable.
  1764. key->set_extractable(extractable);
  1765. // 12. Set the [[usages]] internal slot of key to be usages.
  1766. key->set_usages(key_usages);
  1767. // 13. Return key.
  1768. return { key };
  1769. }
  1770. // https://w3c.github.io/webcrypto/#hkdf-operations
  1771. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> HKDF::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1772. {
  1773. // 1. Let keyData be the key data to be imported.
  1774. // 2. If format is "raw":
  1775. // (… see below …)
  1776. // Otherwise:
  1777. // throw a NotSupportedError.
  1778. if (format != Bindings::KeyFormat::Raw) {
  1779. return WebIDL::NotSupportedError::create(m_realm, "Only raw format is supported"_string);
  1780. }
  1781. // 1. If usages contains a value that is not "deriveKey" or "deriveBits", then throw a SyntaxError.
  1782. for (auto& usage : key_usages) {
  1783. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  1784. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1785. }
  1786. }
  1787. // 2. If extractable is not false, then throw a SyntaxError.
  1788. if (extractable)
  1789. return WebIDL::SyntaxError::create(m_realm, "extractable must be false"_string);
  1790. // 3. Let key be a new CryptoKey representing the key data provided in keyData.
  1791. auto key = CryptoKey::create(m_realm, move(key_data));
  1792. // 4. Set the [[type]] internal slot of key to "secret".
  1793. key->set_type(Bindings::KeyType::Secret);
  1794. // 5. Let algorithm be a new KeyAlgorithm object.
  1795. auto algorithm = KeyAlgorithm::create(m_realm);
  1796. // 6. Set the name attribute of algorithm to "HKDF".
  1797. algorithm->set_name("HKDF"_string);
  1798. // 7. Set the [[algorithm]] internal slot of key to algorithm.
  1799. key->set_algorithm(algorithm);
  1800. // 8. Return key.
  1801. return key;
  1802. }
  1803. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> SHA::digest(AlgorithmParams const& algorithm, ByteBuffer const& data)
  1804. {
  1805. auto& algorithm_name = algorithm.name;
  1806. ::Crypto::Hash::HashKind hash_kind;
  1807. if (algorithm_name.equals_ignoring_ascii_case("SHA-1"sv)) {
  1808. hash_kind = ::Crypto::Hash::HashKind::SHA1;
  1809. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-256"sv)) {
  1810. hash_kind = ::Crypto::Hash::HashKind::SHA256;
  1811. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-384"sv)) {
  1812. hash_kind = ::Crypto::Hash::HashKind::SHA384;
  1813. } else if (algorithm_name.equals_ignoring_ascii_case("SHA-512"sv)) {
  1814. hash_kind = ::Crypto::Hash::HashKind::SHA512;
  1815. } else {
  1816. return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", algorithm_name)));
  1817. }
  1818. ::Crypto::Hash::Manager hash { hash_kind };
  1819. hash.update(data);
  1820. auto digest = hash.digest();
  1821. auto result_buffer = ByteBuffer::copy(digest.immutable_data(), hash.digest_size());
  1822. if (result_buffer.is_error())
  1823. return WebIDL::OperationError::create(m_realm, "Failed to create result buffer"_string);
  1824. return JS::ArrayBuffer::create(m_realm, result_buffer.release_value());
  1825. }
  1826. // https://w3c.github.io/webcrypto/#ecdsa-operations
  1827. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ECDSA::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  1828. {
  1829. // 1. If usages contains a value which is not one of "sign" or "verify", then throw a SyntaxError.
  1830. for (auto const& usage : key_usages) {
  1831. if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify) {
  1832. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  1833. }
  1834. }
  1835. auto const& normalized_algorithm = static_cast<EcKeyGenParams const&>(params);
  1836. // 2. If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
  1837. // Generate an Elliptic Curve key pair, as defined in [RFC6090]
  1838. // with domain parameters for the curve identified by the namedCurve member of normalizedAlgorithm.
  1839. Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
  1840. if (normalized_algorithm.named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
  1841. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-256"sv))
  1842. curve = ::Crypto::Curves::SECP256r1 {};
  1843. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-384"sv))
  1844. curve = ::Crypto::Curves::SECP384r1 {};
  1845. // FIXME: Support P-521
  1846. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-521"sv))
  1847. return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
  1848. } else {
  1849. // If the namedCurve member of normalizedAlgorithm is a value specified in an applicable specification:
  1850. // Perform the ECDSA generation steps specified in that specification,
  1851. // passing in normalizedAlgorithm and resulting in an elliptic curve key pair.
  1852. // Otherwise: throw a NotSupportedError
  1853. return WebIDL::NotSupportedError::create(m_realm, "Only 'P-256', 'P-384' and 'P-521' is supported"_string);
  1854. }
  1855. // NOTE: Spec jumps to 6 here for some reason
  1856. // 6. If performing the key generation operation results in an error, then throw an OperationError.
  1857. auto maybe_private_key_data = curve.visit(
  1858. [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
  1859. [](auto instance) { return instance.generate_private_key(); });
  1860. if (maybe_private_key_data.is_error())
  1861. return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
  1862. auto private_key_data = maybe_private_key_data.release_value();
  1863. auto maybe_public_key_data = curve.visit(
  1864. [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
  1865. [&](auto instance) { return instance.generate_public_key(private_key_data); });
  1866. if (maybe_public_key_data.is_error())
  1867. return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
  1868. auto public_key_data = maybe_public_key_data.release_value();
  1869. // 7. Let algorithm be a new EcKeyAlgorithm object.
  1870. auto algorithm = EcKeyAlgorithm::create(m_realm);
  1871. // 8. Set the name attribute of algorithm to "ECDSA".
  1872. algorithm->set_name("ECDSA"_string);
  1873. // 9. Set the namedCurve attribute of algorithm to equal the namedCurve member of normalizedAlgorithm.
  1874. algorithm->set_named_curve(normalized_algorithm.named_curve);
  1875. // 10. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
  1876. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
  1877. // 11. Set the [[type]] internal slot of publicKey to "public"
  1878. public_key->set_type(Bindings::KeyType::Public);
  1879. // 12. Set the [[algorithm]] internal slot of publicKey to algorithm.
  1880. public_key->set_algorithm(algorithm);
  1881. // 13. Set the [[extractable]] internal slot of publicKey to true.
  1882. public_key->set_extractable(true);
  1883. // 14. Set the [[usages]] internal slot of publicKey to be the usage intersection of usages and [ "verify" ].
  1884. public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Verify } }));
  1885. // 15. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
  1886. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
  1887. // 16. Set the [[type]] internal slot of privateKey to "private"
  1888. private_key->set_type(Bindings::KeyType::Private);
  1889. // 17. Set the [[algorithm]] internal slot of privateKey to algorithm.
  1890. private_key->set_algorithm(algorithm);
  1891. // 18. Set the [[extractable]] internal slot of privateKey to extractable.
  1892. private_key->set_extractable(extractable);
  1893. // 19. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "sign" ].
  1894. private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Sign } }));
  1895. // 20. Let result be a new CryptoKeyPair dictionary.
  1896. // 21. Set the publicKey attribute of result to be publicKey.
  1897. // 22. Set the privateKey attribute of result to be privateKey.
  1898. // 23. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  1899. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
  1900. }
  1901. // https://w3c.github.io/webcrypto/#ecdsa-operations
  1902. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> ECDSA::sign(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& message)
  1903. {
  1904. auto& realm = *m_realm;
  1905. auto& vm = realm.vm();
  1906. auto const& normalized_algorithm = static_cast<EcdsaParams const&>(params);
  1907. (void)vm;
  1908. (void)message;
  1909. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  1910. if (key->type() != Bindings::KeyType::Private)
  1911. return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_string);
  1912. // 2. Let hashAlgorithm be the hash member of normalizedAlgorithm.
  1913. [[maybe_unused]] auto const& hash_algorithm = normalized_algorithm.hash;
  1914. // NOTE: We dont have sign() on the SECPxxxr1 curves, so we can't implement this yet
  1915. // FIXME: 3. Let M be the result of performing the digest operation specified by hashAlgorithm using message.
  1916. // FIXME: 4. Let d be the ECDSA private key associated with key.
  1917. // FIXME: 5. Let params be the EC domain parameters associated with key.
  1918. // FIXME: 6. If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256", "P-384" or "P-521":
  1919. // FIXME: 1. Perform the ECDSA signing process, as specified in [RFC6090], Section 5.4, with M as the message, using params as the EC domain parameters, and with d as the private key.
  1920. // FIXME: 2. Let r and s be the pair of integers resulting from performing the ECDSA signing process.
  1921. // FIXME: 3. Let result be an empty byte sequence.
  1922. // FIXME: 4. Let n be the smallest integer such that n * 8 is greater than the logarithm to base 2 of the order of the base point of the elliptic curve identified by params.
  1923. // FIXME: 5. Convert r to an octet string of length n and append this sequence of bytes to result.
  1924. // FIXME: 6. Convert s to an octet string of length n and append this sequence of bytes to result.
  1925. // FIXME: Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value specified in an applicable specification:
  1926. // FIXME: Perform the ECDSA signature steps specified in that specification, passing in M, params and d and resulting in result.
  1927. // NOTE: The spec jumps to 9 here for some reason
  1928. // FIXME: 9. Return the result of creating an ArrayBuffer containing result.
  1929. return WebIDL::NotSupportedError::create(realm, "ECDSA signing is not supported yet"_string);
  1930. }
  1931. // https://w3c.github.io/webcrypto/#ecdsa-operations
  1932. WebIDL::ExceptionOr<JS::Value> ECDSA::verify(AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& signature, ByteBuffer const& message)
  1933. {
  1934. auto& realm = *m_realm;
  1935. auto const& normalized_algorithm = static_cast<EcdsaParams const&>(params);
  1936. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  1937. if (key->type() != Bindings::KeyType::Public)
  1938. return WebIDL::InvalidAccessError::create(realm, "Key is not a public key"_string);
  1939. // 2. Let hashAlgorithm be the hash member of normalizedAlgorithm.
  1940. [[maybe_unused]] auto const& hash_algorithm = TRY(normalized_algorithm.hash.name(realm.vm()));
  1941. // 3. Let M be the result of performing the digest operation specified by hashAlgorithm using message.
  1942. ::Crypto::Hash::HashKind hash_kind;
  1943. if (hash_algorithm.equals_ignoring_ascii_case("SHA-1"sv)) {
  1944. hash_kind = ::Crypto::Hash::HashKind::SHA1;
  1945. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-256"sv)) {
  1946. hash_kind = ::Crypto::Hash::HashKind::SHA256;
  1947. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-384"sv)) {
  1948. hash_kind = ::Crypto::Hash::HashKind::SHA384;
  1949. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-512"sv)) {
  1950. hash_kind = ::Crypto::Hash::HashKind::SHA512;
  1951. } else {
  1952. return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", hash_algorithm)));
  1953. }
  1954. ::Crypto::Hash::Manager hash { hash_kind };
  1955. hash.update(message);
  1956. auto digest = hash.digest();
  1957. auto result_buffer = ByteBuffer::copy(digest.immutable_data(), hash.digest_size());
  1958. if (result_buffer.is_error())
  1959. return WebIDL::OperationError::create(m_realm, "Failed to create result buffer"_string);
  1960. auto M = result_buffer.release_value();
  1961. // 4. Let Q be the ECDSA public key associated with key.
  1962. auto Q = key->handle().get<ByteBuffer>();
  1963. // FIXME: 5. Let params be the EC domain parameters associated with key.
  1964. // 6. If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256", "P-384" or "P-521":
  1965. auto const& internal_algorithm = static_cast<EcKeyAlgorithm const&>(*key->algorithm());
  1966. auto const& named_curve = internal_algorithm.named_curve();
  1967. auto result = false;
  1968. Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
  1969. if (named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
  1970. if (named_curve.equals_ignoring_ascii_case("P-256"sv))
  1971. curve = ::Crypto::Curves::SECP256r1 {};
  1972. if (named_curve.equals_ignoring_ascii_case("P-384"sv))
  1973. curve = ::Crypto::Curves::SECP384r1 {};
  1974. // FIXME: Support P-521
  1975. if (named_curve.equals_ignoring_ascii_case("P-521"sv))
  1976. return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
  1977. // Perform the ECDSA verifying process, as specified in [RFC6090], Section 5.3,
  1978. // with M as the received message,
  1979. // signature as the received signature
  1980. // and using params as the EC domain parameters,
  1981. // and Q as the public key.
  1982. // NOTE: verify() takes the signature in X.509 format but JS uses IEEE P1363 format, so we need to convert it
  1983. // FIXME: Dont construct an ASN1 object here just to pass it to verify
  1984. auto half_size = signature.size() / 2;
  1985. auto r = ::Crypto::UnsignedBigInteger::import_data(signature.data(), half_size);
  1986. auto s = ::Crypto::UnsignedBigInteger::import_data(signature.data() + half_size, half_size);
  1987. ::Crypto::ASN1::Encoder encoder;
  1988. (void)encoder.write_constructed(::Crypto::ASN1::Class::Universal, ::Crypto::ASN1::Kind::Sequence, [&] {
  1989. (void)encoder.write(r);
  1990. (void)encoder.write(s);
  1991. });
  1992. auto encoded_signature = encoder.finish();
  1993. auto maybe_result = curve.visit(
  1994. [](Empty const&) -> ErrorOr<bool> { return Error::from_string_literal("Failed to create valid crypto instance"); },
  1995. [&](auto instance) { return instance.verify(M, Q, encoded_signature); });
  1996. if (maybe_result.is_error()) {
  1997. auto error_message = MUST(String::from_utf8(maybe_result.error().string_literal()));
  1998. return WebIDL::OperationError::create(m_realm, error_message);
  1999. }
  2000. result = maybe_result.release_value();
  2001. } else {
  2002. // FIXME: Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value specified in an applicable specification:
  2003. // FIXME: Perform the ECDSA verification steps specified in that specification passing in M, signature, params and Q and resulting in an indication of whether or not the purported signature is valid.
  2004. }
  2005. // 9. Let result be a boolean with the value true if the signature is valid and the value false otherwise.
  2006. // 10. Return result.
  2007. return JS::Value(result);
  2008. }
  2009. // https://w3c.github.io/webcrypto/#ecdh-operations
  2010. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ECDH::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  2011. {
  2012. // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  2013. for (auto const& usage : key_usages) {
  2014. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  2015. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2016. }
  2017. }
  2018. auto const& normalized_algorithm = static_cast<EcKeyGenParams const&>(params);
  2019. // 2. If the namedCurve member of normalizedAlgorithm is "P-256", "P-384" or "P-521":
  2020. // Generate an Elliptic Curve key pair, as defined in [RFC6090]
  2021. // with domain parameters for the curve identified by the namedCurve member of normalizedAlgorithm.
  2022. Variant<Empty, ::Crypto::Curves::SECP256r1, ::Crypto::Curves::SECP384r1> curve;
  2023. if (normalized_algorithm.named_curve.is_one_of("P-256"sv, "P-384"sv, "P-521"sv)) {
  2024. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-256"sv))
  2025. curve = ::Crypto::Curves::SECP256r1 {};
  2026. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-384"sv))
  2027. curve = ::Crypto::Curves::SECP384r1 {};
  2028. // FIXME: Support P-521
  2029. if (normalized_algorithm.named_curve.equals_ignoring_ascii_case("P-521"sv))
  2030. return WebIDL::NotSupportedError::create(m_realm, "'P-521' is not supported yet"_string);
  2031. } else {
  2032. // If the namedCurve member of normalizedAlgorithm is a value specified in an applicable specification
  2033. // that specifies the use of that value with ECDH:
  2034. // Perform the ECDH generation steps specified in that specification,
  2035. // passing in normalizedAlgorithm and resulting in an elliptic curve key pair.
  2036. // Otherwise: throw a NotSupportedError
  2037. return WebIDL::NotSupportedError::create(m_realm, "Only 'P-256', 'P-384' and 'P-521' is supported"_string);
  2038. }
  2039. // 3. If performing the operation results in an error, then throw a OperationError.
  2040. auto maybe_private_key_data = curve.visit(
  2041. [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
  2042. [](auto instance) { return instance.generate_private_key(); });
  2043. if (maybe_private_key_data.is_error())
  2044. return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
  2045. auto private_key_data = maybe_private_key_data.release_value();
  2046. auto maybe_public_key_data = curve.visit(
  2047. [](Empty const&) -> ErrorOr<ByteBuffer> { return Error::from_string_literal("noop error"); },
  2048. [&](auto instance) { return instance.generate_public_key(private_key_data); });
  2049. if (maybe_public_key_data.is_error())
  2050. return WebIDL::OperationError::create(m_realm, "Failed to create valid crypto instance"_string);
  2051. auto public_key_data = maybe_public_key_data.release_value();
  2052. // 4. Let algorithm be a new EcKeyAlgorithm object.
  2053. auto algorithm = EcKeyAlgorithm::create(m_realm);
  2054. // 5. Set the name attribute of algorithm to "ECDH".
  2055. algorithm->set_name("ECDH"_string);
  2056. // 6. Set the namedCurve attribute of algorithm to equal the namedCurve member of normalizedAlgorithm.
  2057. algorithm->set_named_curve(normalized_algorithm.named_curve);
  2058. // 7. Let publicKey be a new CryptoKey representing the public key of the generated key pair.
  2059. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
  2060. // 8. Set the [[type]] internal slot of publicKey to "public"
  2061. public_key->set_type(Bindings::KeyType::Public);
  2062. // 9. Set the [[algorithm]] internal slot of publicKey to algorithm.
  2063. public_key->set_algorithm(algorithm);
  2064. // 10. Set the [[extractable]] internal slot of publicKey to true.
  2065. public_key->set_extractable(true);
  2066. // 11. Set the [[usages]] internal slot of publicKey to be the empty list.
  2067. public_key->set_usages({});
  2068. // 12. Let privateKey be a new CryptoKey representing the private key of the generated key pair.
  2069. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
  2070. // 13. Set the [[type]] internal slot of privateKey to "private"
  2071. private_key->set_type(Bindings::KeyType::Private);
  2072. // 14. Set the [[algorithm]] internal slot of privateKey to algorithm.
  2073. private_key->set_algorithm(algorithm);
  2074. // 15. Set the [[extractable]] internal slot of privateKey to extractable.
  2075. private_key->set_extractable(extractable);
  2076. // 16. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
  2077. private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
  2078. // 17. Let result be a new CryptoKeyPair dictionary.
  2079. // 18. Set the publicKey attribute of result to be publicKey.
  2080. // 19. Set the privateKey attribute of result to be privateKey.
  2081. // 20. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  2082. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
  2083. }
  2084. // https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
  2085. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> ED25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  2086. {
  2087. // 1. If usages contains a value which is not one of "sign" or "verify", then throw a SyntaxError.
  2088. for (auto const& usage : key_usages) {
  2089. if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify) {
  2090. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2091. }
  2092. }
  2093. // 2. Generate an Ed25519 key pair, as defined in [RFC8032], section 5.1.5.
  2094. ::Crypto::Curves::Ed25519 curve;
  2095. auto maybe_private_key = curve.generate_private_key();
  2096. if (maybe_private_key.is_error())
  2097. return WebIDL::OperationError::create(m_realm, "Failed to generate private key"_string);
  2098. auto private_key_data = maybe_private_key.release_value();
  2099. auto maybe_public_key = curve.generate_public_key(private_key_data);
  2100. if (maybe_public_key.is_error())
  2101. return WebIDL::OperationError::create(m_realm, "Failed to generate public key"_string);
  2102. auto public_key_data = maybe_public_key.release_value();
  2103. // 3. Let algorithm be a new KeyAlgorithm object.
  2104. auto algorithm = KeyAlgorithm::create(m_realm);
  2105. // 4. Set the name attribute of algorithm to "Ed25519".
  2106. algorithm->set_name("Ed25519"_string);
  2107. // 5. Let publicKey be a new CryptoKey associated with the relevant global object of this [HTML],
  2108. // and representing the public key of the generated key pair.
  2109. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
  2110. // 6. Set the [[type]] internal slot of publicKey to "public"
  2111. public_key->set_type(Bindings::KeyType::Public);
  2112. // 7. Set the [[algorithm]] internal slot of publicKey to algorithm.
  2113. public_key->set_algorithm(algorithm);
  2114. // 8. Set the [[extractable]] internal slot of publicKey to true.
  2115. public_key->set_extractable(true);
  2116. // 9. Set the [[usages]] internal slot of publicKey to be the usage intersection of usages and [ "verify" ].
  2117. public_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Verify } }));
  2118. // 10. Let privateKey be a new CryptoKey associated with the relevant global object of this [HTML],
  2119. // and representing the private key of the generated key pair.
  2120. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
  2121. // 11. Set the [[type]] internal slot of privateKey to "private"
  2122. private_key->set_type(Bindings::KeyType::Private);
  2123. // 12. Set the [[algorithm]] internal slot of privateKey to algorithm.
  2124. private_key->set_algorithm(algorithm);
  2125. // 13. Set the [[extractable]] internal slot of privateKey to extractable.
  2126. private_key->set_extractable(extractable);
  2127. // 14. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "sign" ].
  2128. private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Sign } }));
  2129. // 15. Let result be a new CryptoKeyPair dictionary.
  2130. // 16. Set the publicKey attribute of result to be publicKey.
  2131. // 17. Set the privateKey attribute of result to be privateKey.
  2132. // 18. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  2133. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
  2134. }
  2135. // https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
  2136. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED25519::import_key(
  2137. [[maybe_unused]] Web::Crypto::AlgorithmParams const& params,
  2138. Bindings::KeyFormat format,
  2139. CryptoKey::InternalKeyData key_data,
  2140. bool extractable,
  2141. Vector<Bindings::KeyUsage> const& usages)
  2142. {
  2143. GC::Ptr<CryptoKey> key = nullptr;
  2144. // 1. Let keyData be the key data to be imported.
  2145. // 2. If format is "spki":
  2146. if (format == Bindings::KeyFormat::Spki) {
  2147. // 1. If usages contains a value which is not "verify" then throw a SyntaxError.
  2148. for (auto const& usage : usages) {
  2149. if (usage != Bindings::KeyUsage::Verify) {
  2150. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2151. }
  2152. }
  2153. // 2. Let spki be the result of running the parse a subjectPublicKeyInfo algorithm over keyData.
  2154. // 3. If an error occurred while parsing, then throw a DataError.
  2155. auto spki = TRY(parse_a_subject_public_key_info(m_realm, key_data.get<ByteBuffer>()));
  2156. // 4. If the algorithm object identifier field of the algorithm AlgorithmIdentifier field of spki
  2157. // is not equal to the id-Ed25519 object identifier defined in [RFC8410], then throw a DataError.
  2158. if (spki.algorithm.identifier != ::Crypto::Certificate::ed25519_oid)
  2159. return WebIDL::DataError::create(m_realm, "Invalid algorithm identifier"_string);
  2160. // 5. If the parameters field of the algorithm AlgorithmIdentifier field of spki is present, then throw a DataError.
  2161. if (spki.algorithm.ec_parameters.has_value())
  2162. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  2163. // 6. Let publicKey be the Ed25519 public key identified by the subjectPublicKey field of spki.
  2164. auto const& public_key = spki.raw_key;
  2165. // 7. Let key be a new CryptoKey associated with the relevant global object of this [HTML],
  2166. // and that represents publicKey.
  2167. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  2168. // 8. Set the [[type]] internal slot of key to "public"
  2169. key->set_type(Bindings::KeyType::Public);
  2170. // 9. Let algorithm be a new KeyAlgorithm.
  2171. auto algorithm = KeyAlgorithm::create(m_realm);
  2172. // 10. Set the name attribute of algorithm to "Ed25519".
  2173. algorithm->set_name("Ed25519"_string);
  2174. // 11. Set the [[algorithm]] internal slot of key to algorithm.
  2175. key->set_algorithm(algorithm);
  2176. }
  2177. // 2. If format is "pkcs8":
  2178. else if (format == Bindings::KeyFormat::Pkcs8) {
  2179. // 1. If usages contains a value which is not "sign" then throw a SyntaxError.
  2180. for (auto const& usage : usages) {
  2181. if (usage != Bindings::KeyUsage::Sign) {
  2182. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2183. }
  2184. }
  2185. // 2. Let privateKeyInfo be the result of running the parse a privateKeyInfo algorithm over keyData.
  2186. // 3. If an error occurs while parsing, then throw a DataError.
  2187. auto private_key_info = TRY(parse_a_private_key_info(m_realm, key_data.get<ByteBuffer>()));
  2188. // 4. If the algorithm object identifier field of the privateKeyAlgorithm PrivateKeyAlgorithm field
  2189. // of privateKeyInfo is not equal to the id-Ed25519 object identifier defined in [RFC8410], then throw a DataError.
  2190. if (private_key_info.algorithm.identifier != ::Crypto::Certificate::ed25519_oid)
  2191. return WebIDL::DataError::create(m_realm, "Invalid algorithm identifier"_string);
  2192. // 5. If the parameters field of the privateKeyAlgorithm PrivateKeyAlgorithmIdentifier field of privateKeyInfo is present,
  2193. // then throw a DataError.
  2194. if (private_key_info.algorithm.ec_parameters.has_value())
  2195. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  2196. // 6. Let curvePrivateKey be the result of performing the parse an ASN.1 structure algorithm,
  2197. // with data as the privateKey field of privateKeyInfo, structure as the ASN.1 CurvePrivateKey structure
  2198. // specified in Section 7 of [RFC8410], and exactData set to true.
  2199. // 7. If an error occurred while parsing, then throw a DataError.
  2200. auto curve_private_key = TRY(parse_an_ASN1_structure<StringView>(m_realm, private_key_info.raw_key, true));
  2201. auto curve_private_key_bytes = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::copy(curve_private_key.bytes()));
  2202. // 8. Let key be a new CryptoKey associated with the relevant global object of this [HTML],
  2203. // and that represents the Ed25519 private key identified by curvePrivateKey.
  2204. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { curve_private_key_bytes });
  2205. // 9. Set the [[type]] internal slot of key to "private"
  2206. key->set_type(Bindings::KeyType::Private);
  2207. // 10. Let algorithm be a new KeyAlgorithm.
  2208. auto algorithm = KeyAlgorithm::create(m_realm);
  2209. // 11. Set the name attribute of algorithm to "Ed25519".
  2210. algorithm->set_name("Ed25519"_string);
  2211. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  2212. key->set_algorithm(algorithm);
  2213. }
  2214. // 2. If format is "jwk":
  2215. else if (format == Bindings::KeyFormat::Jwk) {
  2216. // 1. If keyData is a JsonWebKey dictionary: Let jwk equal keyData.
  2217. // Otherwise: Throw a DataError.
  2218. if (!key_data.has<Bindings::JsonWebKey>())
  2219. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  2220. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  2221. // 2. If the d field is present and usages contains a value which is not "sign",
  2222. // or, if the d field is not present and usages contains a value which is not "verify" then throw a SyntaxError.
  2223. if (jwk.d.has_value()) {
  2224. for (auto const& usage : usages) {
  2225. if (usage != Bindings::KeyUsage::Sign) {
  2226. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2227. }
  2228. }
  2229. } else {
  2230. for (auto const& usage : usages) {
  2231. if (usage != Bindings::KeyUsage::Verify) {
  2232. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2233. }
  2234. }
  2235. }
  2236. // 3. If the kty field of jwk is not "OKP", then throw a DataError.
  2237. if (jwk.kty != "OKP"sv)
  2238. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2239. // 4. If the crv field of jwk is not "Ed25519", then throw a DataError.
  2240. if (jwk.crv != "Ed25519"sv)
  2241. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2242. // 5. If usages is non-empty and the use field of jwk is present and is not "sig", then throw a DataError.
  2243. if (!usages.is_empty() && jwk.use.has_value() && jwk.use.value() != "sig")
  2244. return WebIDL::DataError::create(m_realm, "Invalid key usage"_string);
  2245. // 6. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK],
  2246. // or it does not contain all of the specified usages values, then throw a DataError.
  2247. TRY(validate_jwk_key_ops(m_realm, jwk, usages));
  2248. // 7. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  2249. if (jwk.ext.has_value() && !jwk.ext.value() && extractable)
  2250. return WebIDL::DataError::create(m_realm, "Invalid extractable"_string);
  2251. // 8. If the d field is present:
  2252. if (jwk.d.has_value()) {
  2253. // 1. If jwk does not meet the requirements of the JWK private key format described in Section 2 of [RFC8037],
  2254. // then throw a DataError.
  2255. // o The parameter "kty" MUST be "OKP".
  2256. if (jwk.kty != "OKP"sv)
  2257. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2258. // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  2259. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  2260. if (jwk.crv != "Ed25519"sv)
  2261. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2262. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  2263. if (!jwk.x.has_value())
  2264. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  2265. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  2266. // This parameter MUST NOT be present for public keys.
  2267. if (!jwk.d.has_value())
  2268. return WebIDL::DataError::create(m_realm, "Present d field"_string);
  2269. // 2. Let key be a new CryptoKey object that represents the Ed25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
  2270. auto private_key_base_64 = jwk.d.value();
  2271. auto private_key_or_error = decode_base64url(private_key_base_64);
  2272. if (private_key_or_error.is_error()) {
  2273. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  2274. }
  2275. auto private_key = private_key_or_error.release_value();
  2276. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
  2277. // 3. Set the [[type]] internal slot of Key to "private".
  2278. key->set_type(Bindings::KeyType::Private);
  2279. }
  2280. // Otherwise:
  2281. else {
  2282. // 1. If jwk does not meet the requirements of the JWK public key format described in Section 2 of [RFC8037], then throw a DataError.
  2283. // o The parameter "kty" MUST be "OKP".
  2284. if (jwk.kty != "OKP"sv)
  2285. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2286. // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  2287. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  2288. if (jwk.crv != "Ed25519"sv)
  2289. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2290. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  2291. if (!jwk.x.has_value())
  2292. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  2293. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  2294. // This parameter MUST NOT be present for public keys.
  2295. if (jwk.d.has_value())
  2296. return WebIDL::DataError::create(m_realm, "Present d field"_string);
  2297. // 2. Let key be a new CryptoKey object that represents the Ed25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
  2298. auto public_key_base_64 = jwk.x.value();
  2299. auto public_key_or_error = decode_base64url(public_key_base_64);
  2300. if (public_key_or_error.is_error()) {
  2301. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  2302. }
  2303. auto public_key = public_key_or_error.release_value();
  2304. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  2305. // 3. Set the [[type]] internal slot of Key to "public".
  2306. key->set_type(Bindings::KeyType::Public);
  2307. }
  2308. // 9. Let algorithm be a new instance of a KeyAlgorithm object.
  2309. auto algorithm = KeyAlgorithm::create(m_realm);
  2310. // 10. Set the name attribute of algorithm to "Ed25519".
  2311. algorithm->set_name("Ed25519"_string);
  2312. // 11. Set the [[algorithm]] internal slot of key to algorithm.
  2313. key->set_algorithm(algorithm);
  2314. }
  2315. // 2. If format is "raw":
  2316. else if (format == Bindings::KeyFormat::Raw) {
  2317. // 1. If usages contains a value which is not "verify" then throw a SyntaxError.
  2318. for (auto const& usage : usages) {
  2319. if (usage != Bindings::KeyUsage::Verify) {
  2320. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2321. }
  2322. }
  2323. // 2. Let algorithm be a new KeyAlgorithm object.
  2324. auto algorithm = KeyAlgorithm::create(m_realm);
  2325. // 3. Set the name attribute of algorithm to "Ed25519".
  2326. algorithm->set_name("Ed25519"_string);
  2327. // 4. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and representing the key data provided in keyData.
  2328. key = CryptoKey::create(m_realm, key_data);
  2329. // 5. Set the [[type]] internal slot of key to "public"
  2330. key->set_type(Bindings::KeyType::Public);
  2331. // 6. Set the [[algorithm]] internal slot of key to algorithm.
  2332. key->set_algorithm(algorithm);
  2333. }
  2334. // 2. Otherwise:
  2335. else {
  2336. // throw a NotSupportedError.
  2337. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  2338. }
  2339. return GC::Ref { *key };
  2340. }
  2341. WebIDL::ExceptionOr<GC::Ref<JS::Object>> ED25519::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  2342. {
  2343. auto& vm = m_realm->vm();
  2344. // 1. Let key be the CryptoKey to be exported.
  2345. // 2. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  2346. // Note: In our impl this is always accessible
  2347. auto const& key_data = key->handle().get<ByteBuffer>();
  2348. // 3. If format is "spki":
  2349. if (format == Bindings::KeyFormat::Spki) {
  2350. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  2351. if (key->type() != Bindings::KeyType::Public)
  2352. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  2353. // 2. Let data be an instance of the subjectPublicKeyInfo ASN.1 structure defined in [RFC5280] with the following properties:
  2354. // * Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the following properties:
  2355. // * Set the algorithm object identifier to the id-Ed25519 OID defined in [RFC8410].
  2356. // * Set the subjectPublicKey field to keyData.
  2357. auto ed25519_oid = ::Crypto::Certificate::ed25519_oid;
  2358. auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(key_data, ed25519_oid, nullptr));
  2359. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2360. return JS::ArrayBuffer::create(m_realm, move(data));
  2361. }
  2362. // 3. If format is "pkcs8":
  2363. if (format == Bindings::KeyFormat::Pkcs8) {
  2364. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  2365. if (key->type() != Bindings::KeyType::Private)
  2366. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a private key"_string);
  2367. // 2. Let data be an instance of the privateKeyInfo ASN.1 structure defined in [RFC5208] with the following properties:
  2368. // * Set the version field to 0.
  2369. // * Set the privateKeyAlgorithm field to a PrivateKeyAlgorithmIdentifier ASN.1 type with the following properties:
  2370. // * Set the algorithm object identifier to the id-Ed25519 OID defined in [RFC8410].
  2371. // * Set the privateKey field to the result of DER-encoding a CurvePrivateKey ASN.1 type, as defined in Section 7 of [RFC8410], that represents the Ed25519 private key represented by the [[handle]] internal slot of key
  2372. auto ed25519_oid = ::Crypto::Certificate::ed25519_oid;
  2373. auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(key_data, ed25519_oid, nullptr));
  2374. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2375. return JS::ArrayBuffer::create(m_realm, move(data));
  2376. }
  2377. // 2. If format is "jwk":
  2378. if (format == Bindings::KeyFormat::Jwk) {
  2379. // 1. Let jwk be a new JsonWebKey dictionary.
  2380. Bindings::JsonWebKey jwk;
  2381. // 2. Set the kty attribute of jwk to "OKP".
  2382. jwk.kty = "OKP"_string;
  2383. // 3. Set the crv attribute of jwk to "Ed25519".
  2384. jwk.crv = "Ed25519"_string;
  2385. // 4. Set the x attribute of jwk according to the definition in Section 2 of [RFC8037].
  2386. if (key->type() == Bindings::KeyType::Public) {
  2387. jwk.x = TRY_OR_THROW_OOM(vm, encode_base64url(key_data));
  2388. } else {
  2389. // The "x" parameter of the "epk" field is set as follows:
  2390. // Apply the appropriate ECDH function to the ephemeral private key (as scalar input)
  2391. // and the standard base point (as u-coordinate input).
  2392. // The base64url encoding of the output is the value for the "x" parameter of the "epk" field.
  2393. ::Crypto::Curves::Ed25519 curve;
  2394. auto public_key = TRY_OR_THROW_OOM(vm, curve.generate_public_key(key_data));
  2395. jwk.x = TRY_OR_THROW_OOM(vm, encode_base64url(key_data));
  2396. }
  2397. // 5. If the [[type]] internal slot of key is "private"
  2398. if (key->type() == Bindings::KeyType::Private) {
  2399. // 1. Set the d attribute of jwk according to the definition in Section 2 of [RFC8037].
  2400. jwk.d = TRY_OR_THROW_OOM(vm, encode_base64url(key_data));
  2401. }
  2402. // 6. Set the key_ops attribute of jwk to the usages attribute of key.
  2403. jwk.key_ops = Vector<String> {};
  2404. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  2405. for (auto const& usage : key->internal_usages())
  2406. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  2407. // 7. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
  2408. jwk.ext = key->extractable();
  2409. // 8. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  2410. return TRY(jwk.to_object(m_realm));
  2411. }
  2412. // 2. If format is "raw":
  2413. if (format == Bindings::KeyFormat::Raw) {
  2414. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  2415. if (key->type() != Bindings::KeyType::Public)
  2416. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  2417. // 2. Let data be an octet string representing the Ed25519 public key represented by the [[handle]] internal slot of key.
  2418. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2419. return JS::ArrayBuffer::create(m_realm, key_data);
  2420. }
  2421. // 2. Otherwise:
  2422. // throw a NotSupportedError.
  2423. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  2424. }
  2425. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> ED25519::sign([[maybe_unused]] AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& message)
  2426. {
  2427. auto& realm = *m_realm;
  2428. auto& vm = realm.vm();
  2429. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  2430. if (key->type() != Bindings::KeyType::Private)
  2431. return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_string);
  2432. // 2. Perform the Ed25519 signing process, as specified in [RFC8032], Section 5.1.6,
  2433. // with message as M, using the Ed25519 private key associated with key.
  2434. auto private_key = key->handle().get<ByteBuffer>();
  2435. ::Crypto::Curves::Ed25519 curve;
  2436. auto maybe_public_key = curve.generate_public_key(private_key);
  2437. if (maybe_public_key.is_error())
  2438. return WebIDL::OperationError::create(realm, "Failed to generate public key"_string);
  2439. auto public_key = maybe_public_key.release_value();
  2440. auto maybe_signature = curve.sign(public_key, private_key, message);
  2441. if (maybe_signature.is_error())
  2442. return WebIDL::OperationError::create(realm, "Failed to sign message"_string);
  2443. auto signature = maybe_signature.release_value();
  2444. // 3. Return a new ArrayBuffer associated with the relevant global object of this [HTML],
  2445. // and containing the bytes of the signature resulting from performing the Ed25519 signing process.
  2446. auto result = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(signature));
  2447. return JS::ArrayBuffer::create(realm, move(result));
  2448. }
  2449. WebIDL::ExceptionOr<JS::Value> ED25519::verify([[maybe_unused]] AlgorithmParams const& params, GC::Ref<CryptoKey> key, ByteBuffer const& signature, ByteBuffer const& message)
  2450. {
  2451. auto& realm = *m_realm;
  2452. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  2453. if (key->type() != Bindings::KeyType::Public)
  2454. return WebIDL::InvalidAccessError::create(realm, "Key is not a public key"_string);
  2455. // NOTE: this is checked by ED25519::verify()
  2456. // 2. If the key data of key represents an invalid point or a small-order element on the Elliptic Curve of Ed25519, return false.
  2457. // 3. If the point R, encoded in the first half of signature, represents an invalid point or a small-order element on the Elliptic Curve of Ed25519, return false.
  2458. // 4. Perform the Ed25519 verification steps, as specified in [RFC8032], Section 5.1.7,
  2459. // using the cofactorless (unbatched) equation, [S]B = R + [k]A', on the signature,
  2460. // with message as M, using the Ed25519 public key associated with key.
  2461. auto public_key = key->handle().get<ByteBuffer>();
  2462. // 9. Let result be a boolean with the value true if the signature is valid and the value false otherwise.
  2463. ::Crypto::Curves::Ed25519 curve;
  2464. auto result = curve.verify(public_key, signature, message);
  2465. // 10. Return result.
  2466. return JS::Value(result);
  2467. }
  2468. // https://w3c.github.io/webcrypto/#hkdf-operations
  2469. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> HKDF::derive_bits(AlgorithmParams const& params, GC::Ref<CryptoKey> key, Optional<u32> length_optional)
  2470. {
  2471. auto& realm = *m_realm;
  2472. auto const& normalized_algorithm = static_cast<HKDFParams const&>(params);
  2473. // 1. If length is null or zero, or is not a multiple of 8, then throw an OperationError.
  2474. auto length = length_optional.value_or(0);
  2475. if (length == 0 || length % 8 != 0)
  2476. return WebIDL::OperationError::create(realm, "Length must be greater than 0 and divisible by 8"_string);
  2477. // 2. Let keyDerivationKey be the secret represented by [[handle]] internal slot of key as the message.
  2478. auto key_derivation_key = key->handle().get<ByteBuffer>();
  2479. // 3. Let result be the result of performing the HKDF extract and then the HKDF expand step described in Section 2 of [RFC5869] using:
  2480. // * the hash member of normalizedAlgorithm as Hash,
  2481. // * keyDerivationKey as the input keying material, IKM,
  2482. // * the contents of the salt member of normalizedAlgorithm as salt,
  2483. // * the contents of the info member of normalizedAlgorithm as info,
  2484. // * length divided by 8 as the value of L,
  2485. // Note: Although HKDF technically supports absent salt (treating it as hashLen many NUL bytes),
  2486. // all major browsers instead raise a TypeError, for example:
  2487. // "Failed to execute 'deriveBits' on 'SubtleCrypto': HkdfParams: salt: Not a BufferSource"
  2488. // Because we are forced by neither peer pressure nor the spec, we don't support it either.
  2489. auto const& hash_algorithm = TRY(normalized_algorithm.hash.name(realm.vm()));
  2490. ErrorOr<ByteBuffer> result = Error::from_string_literal("noop error");
  2491. if (hash_algorithm.equals_ignoring_ascii_case("SHA-1"sv)) {
  2492. result = ::Crypto::Hash::HKDF<::Crypto::Hash::SHA1>::derive_key(Optional<ReadonlyBytes>(normalized_algorithm.salt), key_derivation_key, normalized_algorithm.info, length / 8);
  2493. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-256"sv)) {
  2494. result = ::Crypto::Hash::HKDF<::Crypto::Hash::SHA256>::derive_key(Optional<ReadonlyBytes>(normalized_algorithm.salt), key_derivation_key, normalized_algorithm.info, length / 8);
  2495. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-384"sv)) {
  2496. result = ::Crypto::Hash::HKDF<::Crypto::Hash::SHA384>::derive_key(Optional<ReadonlyBytes>(normalized_algorithm.salt), key_derivation_key, normalized_algorithm.info, length / 8);
  2497. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-512"sv)) {
  2498. result = ::Crypto::Hash::HKDF<::Crypto::Hash::SHA512>::derive_key(Optional<ReadonlyBytes>(normalized_algorithm.salt), key_derivation_key, normalized_algorithm.info, length / 8);
  2499. } else {
  2500. return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", hash_algorithm)));
  2501. }
  2502. // 4. If the key derivation operation fails, then throw an OperationError.
  2503. if (result.is_error())
  2504. return WebIDL::OperationError::create(realm, "Failed to derive key"_string);
  2505. // 5. Return result
  2506. return JS::ArrayBuffer::create(realm, result.release_value());
  2507. }
  2508. WebIDL::ExceptionOr<JS::Value> HKDF::get_key_length(AlgorithmParams const&)
  2509. {
  2510. // 1. Return null.
  2511. return JS::js_null();
  2512. }
  2513. // https://w3c.github.io/webcrypto/#pbkdf2-operations
  2514. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> PBKDF2::derive_bits(AlgorithmParams const& params, GC::Ref<CryptoKey> key, Optional<u32> length_optional)
  2515. {
  2516. auto& realm = *m_realm;
  2517. auto const& normalized_algorithm = static_cast<PBKDF2Params const&>(params);
  2518. // 1. If length is null or zero, or is not a multiple of 8, then throw an OperationError.
  2519. auto length = length_optional.value_or(0);
  2520. if (length == 0 || length % 8 != 0)
  2521. return WebIDL::OperationError::create(realm, "Length must be greater than 0 and divisible by 8"_string);
  2522. // 2. If the iterations member of normalizedAlgorithm is zero, then throw an OperationError.
  2523. if (normalized_algorithm.iterations == 0)
  2524. return WebIDL::OperationError::create(realm, "Iterations must be greater than 0"_string);
  2525. // 3. Let prf be the MAC Generation function described in Section 4 of [FIPS-198-1] using the hash function described by the hash member of normalizedAlgorithm.
  2526. auto const& hash_algorithm = TRY(normalized_algorithm.hash.name(realm.vm()));
  2527. // 4. Let result be the result of performing the PBKDF2 operation defined in Section 5.2 of [RFC8018]
  2528. // using prf as the pseudo-random function, PRF,
  2529. // the password represented by [[handle]] internal slot of key as the password, P,
  2530. // the contents of the salt attribute of normalizedAlgorithm as the salt, S,
  2531. // the value of the iterations attribute of normalizedAlgorithm as the iteration count, c,
  2532. // and length divided by 8 as the intended key length, dkLen.
  2533. ErrorOr<ByteBuffer> result = Error::from_string_literal("noop error");
  2534. auto password = key->handle().get<ByteBuffer>();
  2535. auto salt = normalized_algorithm.salt;
  2536. auto iterations = normalized_algorithm.iterations;
  2537. auto derived_key_length_bytes = length / 8;
  2538. if (hash_algorithm.equals_ignoring_ascii_case("SHA-1"sv)) {
  2539. result = ::Crypto::Hash::PBKDF2::derive_key<::Crypto::Authentication::HMAC<::Crypto::Hash::SHA1>>(password, salt, iterations, derived_key_length_bytes);
  2540. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-256"sv)) {
  2541. result = ::Crypto::Hash::PBKDF2::derive_key<::Crypto::Authentication::HMAC<::Crypto::Hash::SHA256>>(password, salt, iterations, derived_key_length_bytes);
  2542. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-384"sv)) {
  2543. result = ::Crypto::Hash::PBKDF2::derive_key<::Crypto::Authentication::HMAC<::Crypto::Hash::SHA384>>(password, salt, iterations, derived_key_length_bytes);
  2544. } else if (hash_algorithm.equals_ignoring_ascii_case("SHA-512"sv)) {
  2545. result = ::Crypto::Hash::PBKDF2::derive_key<::Crypto::Authentication::HMAC<::Crypto::Hash::SHA512>>(password, salt, iterations, derived_key_length_bytes);
  2546. } else {
  2547. return WebIDL::NotSupportedError::create(m_realm, MUST(String::formatted("Invalid hash function '{}'", hash_algorithm)));
  2548. }
  2549. // 5. If the key derivation operation fails, then throw an OperationError.
  2550. if (result.is_error())
  2551. return WebIDL::OperationError::create(realm, "Failed to derive key"_string);
  2552. // 6. Return result
  2553. return JS::ArrayBuffer::create(realm, result.release_value());
  2554. }
  2555. // https://w3c.github.io/webcrypto/#pbkdf2-operations
  2556. WebIDL::ExceptionOr<JS::Value> PBKDF2::get_key_length(AlgorithmParams const&)
  2557. {
  2558. // 1. Return null.
  2559. return JS::js_null();
  2560. }
  2561. // https://w3c.github.io/webcrypto/#pbkdf2-operations
  2562. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> PBKDF2::import_key(AlgorithmParams const&, Bindings::KeyFormat format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  2563. {
  2564. // 1. If format is not "raw", throw a NotSupportedError
  2565. if (format != Bindings::KeyFormat::Raw)
  2566. return WebIDL::NotSupportedError::create(m_realm, "Only raw format is supported"_string);
  2567. // 2. If usages contains a value that is not "deriveKey" or "deriveBits", then throw a SyntaxError.
  2568. for (auto& usage : key_usages) {
  2569. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits)
  2570. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2571. }
  2572. // 3. If extractable is not false, then throw a SyntaxError.
  2573. if (extractable)
  2574. return WebIDL::SyntaxError::create(m_realm, "extractable must be false"_string);
  2575. // 4. Let key be a new CryptoKey representing keyData.
  2576. auto key = CryptoKey::create(m_realm, move(key_data));
  2577. // 5. Set the [[type]] internal slot of key to "secret".
  2578. key->set_type(Bindings::KeyType::Secret);
  2579. // 6. Let algorithm be a new KeyAlgorithm object.
  2580. auto algorithm = KeyAlgorithm::create(m_realm);
  2581. // 7. Set the name attribute of algorithm to "PBKDF2".
  2582. algorithm->set_name("PBKDF2"_string);
  2583. // 8. Set the [[algorithm]] internal slot of key to algorithm.
  2584. key->set_algorithm(algorithm);
  2585. // 9. Return key.
  2586. return key;
  2587. }
  2588. // https://wicg.github.io/webcrypto-secure-curves/#x25519-operations
  2589. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> X25519::derive_bits(AlgorithmParams const& params, GC::Ref<CryptoKey> key, Optional<u32> length_optional)
  2590. {
  2591. auto& realm = *m_realm;
  2592. auto const& normalized_algorithm = static_cast<EcdhKeyDerivePrams const&>(params);
  2593. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  2594. if (key->type() != Bindings::KeyType::Private)
  2595. return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_string);
  2596. // 2. Let publicKey be the public member of normalizedAlgorithm.
  2597. auto& public_key = normalized_algorithm.public_key;
  2598. // 3. If the [[type]] internal slot of publicKey is not "public", then throw an InvalidAccessError.
  2599. if (public_key->type() != Bindings::KeyType::Public)
  2600. return WebIDL::InvalidAccessError::create(realm, "Public key is not a public key"_string);
  2601. // 4. If the name attribute of the [[algorithm]] internal slot of publicKey is not equal to
  2602. // the name property of the [[algorithm]] internal slot of key, then throw an InvalidAccessError.
  2603. auto& internal_algorithm = static_cast<KeyAlgorithm const&>(*key->algorithm());
  2604. auto& public_internal_algorithm = static_cast<KeyAlgorithm const&>(*public_key->algorithm());
  2605. if (internal_algorithm.name() != public_internal_algorithm.name())
  2606. return WebIDL::InvalidAccessError::create(realm, "Algorithm mismatch"_string);
  2607. // 5. Let secret be the result of performing the X25519 function specified in [RFC7748] Section 5 with
  2608. // key as the X25519 private key k and
  2609. // the X25519 public key represented by the [[handle]] internal slot of publicKey as the X25519 public key u.
  2610. auto private_key = key->handle().get<ByteBuffer>();
  2611. auto public_key_data = public_key->handle().get<ByteBuffer>();
  2612. ::Crypto::Curves::X25519 curve;
  2613. auto maybe_secret = curve.compute_coordinate(private_key, public_key_data);
  2614. if (maybe_secret.is_error())
  2615. return WebIDL::OperationError::create(realm, "Failed to compute secret"_string);
  2616. auto secret = maybe_secret.release_value();
  2617. // 6. If secret is the all-zero value, then throw a OperationError.
  2618. // This check must be performed in constant-time, as per [RFC7748] Section 6.1.
  2619. // NOTE: The check may be performed by ORing all the bytes together and checking whether the result is zero,
  2620. // as this eliminates standard side-channels in software implementations.
  2621. auto or_bytes = 0;
  2622. for (auto byte : secret.bytes()) {
  2623. or_bytes |= byte;
  2624. }
  2625. if (or_bytes == 0)
  2626. return WebIDL::OperationError::create(realm, "Secret is the all-zero value"_string);
  2627. // 7. If length is null: Return secret
  2628. if (!length_optional.has_value()) {
  2629. auto result = TRY_OR_THROW_OOM(realm.vm(), ByteBuffer::copy(secret));
  2630. return JS::ArrayBuffer::create(realm, move(result));
  2631. }
  2632. // Otherwise: If the length of secret in bits is less than length: throw an OperationError.
  2633. auto length = length_optional.value();
  2634. if (secret.size() * 8 < length)
  2635. return WebIDL::OperationError::create(realm, "Secret is too short"_string);
  2636. // Otherwise: Return an octet string containing the first length bits of secret.
  2637. auto slice = TRY_OR_THROW_OOM(realm.vm(), secret.slice(0, length / 8));
  2638. return JS::ArrayBuffer::create(realm, move(slice));
  2639. }
  2640. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> X25519::generate_key([[maybe_unused]] AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& key_usages)
  2641. {
  2642. // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  2643. for (auto const& usage : key_usages) {
  2644. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  2645. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2646. }
  2647. }
  2648. // 2. Generate an X25519 key pair, with the private key being 32 random bytes,
  2649. // and the public key being X25519(a, 9), as defined in [RFC7748], section 6.1.
  2650. ::Crypto::Curves::X25519 curve;
  2651. auto maybe_private_key = curve.generate_private_key();
  2652. if (maybe_private_key.is_error())
  2653. return WebIDL::OperationError::create(m_realm, "Failed to generate private key"_string);
  2654. auto private_key_data = maybe_private_key.release_value();
  2655. auto maybe_public_key = curve.generate_public_key(private_key_data);
  2656. if (maybe_public_key.is_error())
  2657. return WebIDL::OperationError::create(m_realm, "Failed to generate public key"_string);
  2658. auto public_key_data = maybe_public_key.release_value();
  2659. // 3. Let algorithm be a new KeyAlgorithm object.
  2660. auto algorithm = KeyAlgorithm::create(m_realm);
  2661. // 4. Set the name attribute of algorithm to "X25519".
  2662. algorithm->set_name("X25519"_string);
  2663. // 5. Let publicKey be a new CryptoKey associated with the relevant global object of this [HTML],
  2664. // and representing the public key of the generated key pair.
  2665. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
  2666. // 6. Set the [[type]] internal slot of publicKey to "public"
  2667. public_key->set_type(Bindings::KeyType::Public);
  2668. // 7. Set the [[algorithm]] internal slot of publicKey to algorithm.
  2669. public_key->set_algorithm(algorithm);
  2670. // 8. Set the [[extractable]] internal slot of publicKey to true.
  2671. public_key->set_extractable(true);
  2672. // 9. Set the [[usages]] internal slot of publicKey to be the empty list.
  2673. public_key->set_usages({});
  2674. // 10. Let privateKey be a new CryptoKey associated with the relevant global object of this [HTML],
  2675. // and representing the private key of the generated key pair.
  2676. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
  2677. // 11. Set the [[type]] internal slot of privateKey to "private"
  2678. private_key->set_type(Bindings::KeyType::Private);
  2679. // 12. Set the [[algorithm]] internal slot of privateKey to algorithm.
  2680. private_key->set_algorithm(algorithm);
  2681. // 13. Set the [[extractable]] internal slot of privateKey to extractable.
  2682. private_key->set_extractable(extractable);
  2683. // 14. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
  2684. private_key->set_usages(usage_intersection(key_usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
  2685. // 15. Let result be a new CryptoKeyPair dictionary.
  2686. // 16. Set the publicKey attribute of result to be publicKey.
  2687. // 17. Set the privateKey attribute of result to be privateKey.
  2688. // 18. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  2689. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
  2690. }
  2691. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X25519::import_key([[maybe_unused]] Web::Crypto::AlgorithmParams const& params, Bindings::KeyFormat key_format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& usages)
  2692. {
  2693. // NOTE: This is a parameter to the function
  2694. // 1. Let keyData be the key data to be imported.
  2695. auto& vm = m_realm->vm();
  2696. GC::Ptr<CryptoKey> key = nullptr;
  2697. // 2. If format is "spki":
  2698. if (key_format == Bindings::KeyFormat::Spki) {
  2699. // 1. If usages is not empty then throw a SyntaxError.
  2700. if (!usages.is_empty())
  2701. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty"_string);
  2702. // 2. Let spki be the result of running the parse a subjectPublicKeyInfo algorithm over keyData.
  2703. // 3. If an error occurred while parsing, then throw a DataError.
  2704. auto spki = TRY(parse_a_subject_public_key_info(m_realm, key_data.get<ByteBuffer>()));
  2705. // 4. If the algorithm object identifier field of the algorithm AlgorithmIdentifier field of spki
  2706. // is not equal to the id-X25519 object identifier defined in [RFC8410], then throw a DataError.
  2707. if (spki.algorithm.identifier != ::Crypto::Certificate::x25519_oid)
  2708. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  2709. // 5. If the parameters field of the algorithm AlgorithmIdentifier field of spki is present, then throw a DataError.
  2710. if (spki.algorithm.ec_parameters.has_value())
  2711. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  2712. // 6. Let publicKey be the X25519 public key identified by the subjectPublicKey field of spki.
  2713. auto public_key = spki.raw_key;
  2714. // 7. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and that represents publicKey.
  2715. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  2716. // 8. Set the [[type]] internal slot of key to "public"
  2717. key->set_type(Bindings::KeyType::Public);
  2718. // 9. Let algorithm be a new KeyAlgorithm.
  2719. auto algorithm = KeyAlgorithm::create(m_realm);
  2720. // 10. Set the name attribute of algorithm to "X25519".
  2721. algorithm->set_name("X25519"_string);
  2722. // 11. Set the [[algorithm]] internal slot of key to algorithm.
  2723. key->set_algorithm(algorithm);
  2724. }
  2725. // 2. If format is "pkcs8":
  2726. else if (key_format == Bindings::KeyFormat::Pkcs8) {
  2727. // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  2728. for (auto const& usage : usages) {
  2729. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  2730. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2731. }
  2732. }
  2733. // 2. Let privateKeyInfo be the result of running the parse a privateKeyInfo algorithm over keyData.
  2734. // 3. If an error occurred while parsing, then throw a DataError.
  2735. auto private_key_info = TRY(parse_a_private_key_info(m_realm, key_data.get<ByteBuffer>()));
  2736. // 4. If the algorithm object identifier field of the privateKeyAlgorithm PrivateKeyAlgorithm field of privateKeyInfo
  2737. // is not equal to the id-X25519 object identifier defined in [RFC8410], then throw a DataError.
  2738. if (private_key_info.algorithm.identifier != ::Crypto::Certificate::x25519_oid)
  2739. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  2740. // 5. If the parameters field of the privateKeyAlgorithm PrivateKeyAlgorithmIdentifier field of privateKeyInfo is present, then throw a DataError.
  2741. if (private_key_info.algorithm.ec_parameters.has_value())
  2742. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  2743. // 6. Let curvePrivateKey be the result of performing the parse an ASN.1 structure algorithm,
  2744. // with data as the privateKey field of privateKeyInfo,
  2745. // structure as the ASN.1 CurvePrivateKey structure specified in Section 7 of [RFC8410], and
  2746. // exactData set to true.
  2747. // 7. If an error occurred while parsing, then throw a DataError.
  2748. auto curve_private_key = TRY(parse_an_ASN1_structure<StringView>(m_realm, private_key_info.raw_key, true));
  2749. auto curve_private_key_bytes = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(curve_private_key.bytes()));
  2750. // 8. Let key be a new CryptoKey associated with the relevant global object of this [HTML],
  2751. // and that represents the X25519 private key identified by curvePrivateKey.
  2752. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { curve_private_key_bytes });
  2753. // 9. Set the [[type]] internal slot of key to "private"
  2754. key->set_type(Bindings::KeyType::Private);
  2755. // 10. Let algorithm be a new KeyAlgorithm.
  2756. auto algorithm = KeyAlgorithm::create(m_realm);
  2757. // 11. Set the name attribute of algorithm to "X25519".
  2758. algorithm->set_name("X25519"_string);
  2759. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  2760. key->set_algorithm(algorithm);
  2761. }
  2762. // 2. If format is "jwk":
  2763. else if (key_format == Bindings::KeyFormat::Jwk) {
  2764. // 1. If keyData is a JsonWebKey dictionary: Let jwk equal keyData.
  2765. // Otherwise: Throw a DataError.
  2766. if (!key_data.has<Bindings::JsonWebKey>())
  2767. return WebIDL::DataError::create(m_realm, "keyData is not a JsonWebKey dictionary"_string);
  2768. auto& jwk = key_data.get<Bindings::JsonWebKey>();
  2769. // 2. If the d field is present and if usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  2770. if (jwk.d.has_value() && !usages.is_empty()) {
  2771. for (auto const& usage : usages) {
  2772. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  2773. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  2774. }
  2775. }
  2776. }
  2777. // 3. If the d field is not present and if usages is not empty then throw a SyntaxError.
  2778. if (!jwk.d.has_value() && !usages.is_empty())
  2779. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty if d is missing"_string);
  2780. // 4. If the kty field of jwk is not "OKP", then throw a DataError.
  2781. if (jwk.kty != "OKP"sv)
  2782. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2783. // 5. If the crv field of jwk is not "X25519", then throw a DataError.
  2784. if (jwk.crv != "X25519"sv)
  2785. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2786. // 6. If usages is non-empty and the use field of jwk is present and is not equal to "enc" then throw a DataError.
  2787. if (!usages.is_empty() && jwk.use.has_value() && jwk.use.value() != "enc"sv)
  2788. return WebIDL::DataError::create(m_realm, "Invalid use"_string);
  2789. // 7. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK],
  2790. // or it does not contain all of the specified usages values, then throw a DataError.
  2791. TRY(validate_jwk_key_ops(m_realm, jwk, usages));
  2792. // 8. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  2793. if (jwk.ext.has_value() && !jwk.ext.value() && extractable)
  2794. return WebIDL::DataError::create(m_realm, "Invalid extractable"_string);
  2795. // 9. If the d field is present:
  2796. if (jwk.d.has_value()) {
  2797. // 1. If jwk does not meet the requirements of the JWK private key format described in Section 2 of [RFC8037], then throw a DataError.
  2798. // o The parameter "kty" MUST be "OKP".
  2799. if (jwk.kty != "OKP"sv)
  2800. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2801. // // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  2802. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  2803. if (jwk.crv != "X25519"sv)
  2804. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2805. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  2806. if (!jwk.x.has_value())
  2807. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  2808. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  2809. // This parameter MUST NOT be present for public keys.
  2810. if (!jwk.d.has_value())
  2811. return WebIDL::DataError::create(m_realm, "Missing d field"_string);
  2812. // 2. Let key be a new CryptoKey object that represents the X25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
  2813. auto private_key_base_64 = jwk.d.value();
  2814. auto private_key_or_error = decode_base64url(private_key_base_64);
  2815. if (private_key_or_error.is_error()) {
  2816. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  2817. }
  2818. auto private_key = private_key_or_error.release_value();
  2819. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
  2820. // 3. Set the [[type]] internal slot of Key to "private".
  2821. key->set_type(Bindings::KeyType::Private);
  2822. }
  2823. // 9. Otherwise:
  2824. else {
  2825. // 1. If jwk does not meet the requirements of the JWK public key format described in Section 2 of [RFC8037], then throw a DataError.
  2826. // o The parameter "kty" MUST be "OKP".
  2827. if (jwk.kty != "OKP"sv)
  2828. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  2829. // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  2830. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  2831. if (jwk.crv != "X25519"sv)
  2832. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  2833. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  2834. if (!jwk.x.has_value())
  2835. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  2836. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  2837. // This parameter MUST NOT be present for public keys.
  2838. if (jwk.d.has_value())
  2839. return WebIDL::DataError::create(m_realm, "Present d field"_string);
  2840. // 2. Let key be a new CryptoKey object that represents the X25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
  2841. auto public_key_base_64 = jwk.x.value();
  2842. auto public_key_or_error = decode_base64url(public_key_base_64);
  2843. if (public_key_or_error.is_error()) {
  2844. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  2845. }
  2846. auto public_key = public_key_or_error.release_value();
  2847. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  2848. // 3. Set the [[type]] internal slot of Key to "public".
  2849. key->set_type(Bindings::KeyType::Public);
  2850. }
  2851. // 10. Let algorithm be a new instance of a KeyAlgorithm object.
  2852. auto algorithm = KeyAlgorithm::create(m_realm);
  2853. // 11. Set the name attribute of algorithm to "X25519".
  2854. algorithm->set_name("X25519"_string);
  2855. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  2856. key->set_algorithm(algorithm);
  2857. }
  2858. // 2. If format is "raw":
  2859. else if (key_format == Bindings::KeyFormat::Raw) {
  2860. // 1. If usages is not empty then throw a SyntaxError.
  2861. if (!usages.is_empty())
  2862. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty"_string);
  2863. // 2. Let algorithm be a new KeyAlgorithm object.
  2864. auto algorithm = KeyAlgorithm::create(m_realm);
  2865. // 3. Set the name attribute of algorithm to "X25519".
  2866. algorithm->set_name("X25519"_string);
  2867. // 4. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and representing the key data provided in keyData.
  2868. key = CryptoKey::create(m_realm, key_data);
  2869. // 5. Set the [[type]] internal slot of key to "public"
  2870. key->set_type(Bindings::KeyType::Public);
  2871. // 6. Set the [[algorithm]] internal slot of key to algorithm.
  2872. key->set_algorithm(algorithm);
  2873. }
  2874. // 2. Otherwise: throw a NotSupportedError.
  2875. else {
  2876. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  2877. }
  2878. // 3. Return key
  2879. return GC::Ref { *key };
  2880. }
  2881. WebIDL::ExceptionOr<GC::Ref<JS::Object>> X25519::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  2882. {
  2883. auto& vm = m_realm->vm();
  2884. // NOTE: This is a parameter to the function
  2885. // 1. Let key be the CryptoKey to be exported.
  2886. // 2. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  2887. // Note: In our impl this is always accessible
  2888. auto const& handle = key->handle();
  2889. GC::Ptr<JS::Object> result = nullptr;
  2890. // 3. If format is "spki":
  2891. if (format == Bindings::KeyFormat::Spki) {
  2892. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  2893. if (key->type() != Bindings::KeyType::Public)
  2894. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  2895. // 2. Let data be an instance of the subjectPublicKeyInfo ASN.1 structure defined in [RFC5280] with the following properties:
  2896. // Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the following properties:
  2897. // Set the algorithm object identifier to the id-X25519 OID defined in [RFC8410].
  2898. // Set the subjectPublicKey field to keyData.
  2899. auto public_key = handle.get<ByteBuffer>();
  2900. auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(public_key, Array { ::Crypto::Certificate::x25519_oid }, nullptr));
  2901. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2902. result = JS::ArrayBuffer::create(m_realm, data);
  2903. }
  2904. // 3. If format is "pkcs8":
  2905. else if (format == Bindings::KeyFormat::Pkcs8) {
  2906. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  2907. if (key->type() != Bindings::KeyType::Private)
  2908. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a private key"_string);
  2909. // 2. Let data be an instance of the privateKeyInfo ASN.1 structure defined in [RFC5208] with the following properties:
  2910. // Set the version field to 0.
  2911. // Set the privateKeyAlgorithm field to a PrivateKeyAlgorithmIdentifier ASN.1 type with the following properties:
  2912. // Set the algorithm object identifier to the id-X25519 OID defined in [RFC8410].
  2913. // Set the privateKey field to the result of DER-encoding a CurvePrivateKey ASN.1 type, as defined in Section 7 of [RFC8410],
  2914. // that represents the X25519 private key represented by the [[handle]] internal slot of key
  2915. auto private_key = handle.get<ByteBuffer>();
  2916. auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(private_key, Array { ::Crypto::Certificate::x25519_oid }, nullptr));
  2917. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2918. result = JS::ArrayBuffer::create(m_realm, data);
  2919. }
  2920. // 3. If format is "jwt":
  2921. else if (format == Bindings::KeyFormat::Jwk) {
  2922. // 1. Let jwk be a new JsonWebKey dictionar1y.
  2923. Bindings::JsonWebKey jwk = {};
  2924. // 2. Set the kty attribute of jwk to "OKP".
  2925. jwk.kty = "OKP"_string;
  2926. // 3. Set the crv attribute of jwk to "X25519".
  2927. jwk.crv = "X25519"_string;
  2928. // 4. Set the x attribute of jwk according to the definition in Section 2 of [RFC8037].
  2929. if (key->type() == Bindings::KeyType::Public) {
  2930. auto public_key = handle.get<ByteBuffer>();
  2931. jwk.x = TRY_OR_THROW_OOM(vm, encode_base64url(public_key));
  2932. } else {
  2933. // The "x" parameter of the "epk" field is set as follows:
  2934. // Apply the appropriate ECDH function to the ephemeral private key (as scalar input)
  2935. // and the standard base point (as u-coordinate input).
  2936. // The base64url encoding of the output is the value for the "x" parameter of the "epk" field.
  2937. ::Crypto::Curves::X25519 curve;
  2938. auto public_key = TRY_OR_THROW_OOM(vm, curve.generate_public_key(handle.get<ByteBuffer>()));
  2939. jwk.x = TRY_OR_THROW_OOM(vm, encode_base64url(public_key));
  2940. }
  2941. // 5. If the [[type]] internal slot of key is "private"
  2942. if (key->type() == Bindings::KeyType::Private) {
  2943. // 1. Set the d attribute of jwk according to the definition in Section 2 of [RFC8037].
  2944. auto private_key = handle.get<ByteBuffer>();
  2945. jwk.d = TRY_OR_THROW_OOM(vm, encode_base64url(private_key));
  2946. }
  2947. // 6. Set the key_ops attribute of jwk to the usages attribute of key.
  2948. jwk.key_ops = Vector<String> {};
  2949. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  2950. for (auto const& usage : key->internal_usages())
  2951. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  2952. // 7. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
  2953. jwk.ext = key->extractable();
  2954. // 8. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  2955. result = TRY(jwk.to_object(m_realm));
  2956. }
  2957. // 3. If format is "raw":
  2958. else if (format == Bindings::KeyFormat::Raw) {
  2959. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  2960. if (key->type() != Bindings::KeyType::Public)
  2961. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  2962. // 2. Let data be an octet string representing the X25519 public key represented by the [[handle]] internal slot of key.
  2963. auto public_key = handle.get<ByteBuffer>();
  2964. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  2965. result = JS::ArrayBuffer::create(m_realm, public_key);
  2966. }
  2967. // 3. Otherwise:
  2968. else {
  2969. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  2970. }
  2971. // 4. Return result.
  2972. return GC::Ref { *result };
  2973. }
  2974. // https://wicg.github.io/webcrypto-secure-curves/#x448-operations
  2975. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> X448::derive_bits(
  2976. AlgorithmParams const& params,
  2977. GC::Ref<CryptoKey> key,
  2978. Optional<u32> length_optional)
  2979. {
  2980. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  2981. if (key->type() != Bindings::KeyType::Private)
  2982. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a private key"_string);
  2983. // 2. Let publicKey be the public member of normalizedAlgorithm.
  2984. auto& public_key = static_cast<EcdhKeyDerivePrams const&>(params).public_key;
  2985. // 3. If the [[type]] internal slot of publicKey is not "public", then throw an InvalidAccessError.
  2986. if (public_key->type() != Bindings::KeyType::Public)
  2987. return WebIDL::InvalidAccessError::create(m_realm, "Public key is not a public key"_string);
  2988. // 4. If the name attribute of the [[algorithm]] internal slot of publicKey is not equal to
  2989. // the name property of the [[algorithm]] internal slot of key, then throw an InvalidAccessError.
  2990. auto& internal_algorithm = static_cast<KeyAlgorithm const&>(*key->algorithm());
  2991. auto& public_internal_algorithm = static_cast<KeyAlgorithm const&>(*public_key->algorithm());
  2992. if (internal_algorithm.name() != public_internal_algorithm.name())
  2993. return WebIDL::InvalidAccessError::create(m_realm, "Algorithm mismatch"_string);
  2994. // 5. Let secret be the result of performing the X448 function specified in [RFC7748] Section 5
  2995. // with key as the X448 private key k and the X448 public key represented by the [[handle]]
  2996. // internal slot of publicKey as the X448 public key u.
  2997. auto private_key = key->handle().get<ByteBuffer>();
  2998. auto public_key_data = public_key->handle().get<ByteBuffer>();
  2999. ::Crypto::Curves::X448 curve;
  3000. auto maybe_secret = curve.compute_coordinate(private_key, public_key_data);
  3001. if (maybe_secret.is_error())
  3002. return WebIDL::OperationError::create(m_realm, "Failed to compute secret"_string);
  3003. auto secret = maybe_secret.release_value();
  3004. // 6. If secret is the all-zero value, then throw a OperationError. This check must be performed in constant-time, as per [RFC7748] Section 6.2.
  3005. // NOTE: The check may be performed by ORing all the bytes together and checking whether the result is zero,
  3006. // as this eliminates standard side-channels in software implementations.
  3007. auto or_bytes = 0;
  3008. for (auto byte : secret.bytes()) {
  3009. or_bytes |= byte;
  3010. }
  3011. if (or_bytes == 0)
  3012. return WebIDL::OperationError::create(m_realm, "Secret is the all-zero value"_string);
  3013. // 7. If length is null: Return secret
  3014. if (!length_optional.has_value()) {
  3015. auto result = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::copy(secret));
  3016. return JS::ArrayBuffer::create(m_realm, move(result));
  3017. }
  3018. // Otherwise: Return an octet string containing the first length bits of secret.
  3019. auto length = length_optional.value();
  3020. if (secret.size() * 8 < length)
  3021. return WebIDL::OperationError::create(m_realm, "Secret is too short"_string);
  3022. auto slice = TRY_OR_THROW_OOM(m_realm->vm(), secret.slice(0, length / 8));
  3023. return JS::ArrayBuffer::create(m_realm, move(slice));
  3024. }
  3025. // https://wicg.github.io/webcrypto-secure-curves/#x448-operations
  3026. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> X448::generate_key(
  3027. AlgorithmParams const&,
  3028. bool extractable,
  3029. Vector<Bindings::KeyUsage> const& usages)
  3030. {
  3031. // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  3032. for (auto const& usage : usages) {
  3033. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  3034. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  3035. }
  3036. }
  3037. // 2. Generate an X448 key pair, with the private key being 56 random bytes, and the public key being X448(a, 5), as defined in [RFC7748], section 6.2.
  3038. ::Crypto::Curves::X448 curve;
  3039. auto maybe_private_key = curve.generate_private_key();
  3040. if (maybe_private_key.is_error())
  3041. return WebIDL::OperationError::create(m_realm, "Failed to generate private key"_string);
  3042. auto private_key_data = maybe_private_key.release_value();
  3043. auto maybe_public_key = curve.generate_public_key(private_key_data);
  3044. if (maybe_public_key.is_error())
  3045. return WebIDL::OperationError::create(m_realm, "Failed to generate public key"_string);
  3046. auto public_key_data = maybe_public_key.release_value();
  3047. // 3. Let algorithm be a new KeyAlgorithm object.
  3048. auto algorithm = KeyAlgorithm::create(m_realm);
  3049. // 4. Set the name attribute of algorithm to "X448".
  3050. algorithm->set_name("X448"_string);
  3051. // 5. Let publicKey be a new CryptoKey associated with the relevant global object of this [HTML], and representing the public key of the generated key pair.
  3052. auto public_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key_data });
  3053. // 6. Set the [[type]] internal slot of publicKey to "public"
  3054. public_key->set_type(Bindings::KeyType::Public);
  3055. // 7. Set the [[algorithm]] internal slot of publicKey to algorithm.
  3056. public_key->set_algorithm(algorithm);
  3057. // 8. Set the [[extractable]] internal slot of publicKey to true.
  3058. public_key->set_extractable(true);
  3059. // 9. Set the [[usages]] internal slot of publicKey to be the empty list.
  3060. public_key->set_usages({});
  3061. // 10. Let privateKey be a new CryptoKey associated with the relevant global object of this [HTML], and representing the private key of the generated key pair.
  3062. auto private_key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key_data });
  3063. // 11. Set the [[type]] internal slot of privateKey to "private"
  3064. private_key->set_type(Bindings::KeyType::Private);
  3065. // 12. Set the [[algorithm]] internal slot of privateKey to algorithm.
  3066. private_key->set_algorithm(algorithm);
  3067. // 13. Set the [[extractable]] internal slot of privateKey to extractable.
  3068. private_key->set_extractable(extractable);
  3069. // 14. Set the [[usages]] internal slot of privateKey to be the usage intersection of usages and [ "deriveKey", "deriveBits" ].
  3070. private_key->set_usages(usage_intersection(usages, { { Bindings::KeyUsage::Derivekey, Bindings::KeyUsage::Derivebits } }));
  3071. // 15. Let result be a new CryptoKeyPair dictionary.
  3072. // 16. Set the publicKey attribute of result to be publicKey.
  3073. // 17. Set the privateKey attribute of result to be privateKey.
  3074. auto result = CryptoKeyPair::create(m_realm, public_key, private_key);
  3075. // 18. Return the result of converting result to an ECMAScript Object, as defined by [WebIDL].
  3076. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { result };
  3077. }
  3078. // https://wicg.github.io/webcrypto-secure-curves/#x448-operations
  3079. WebIDL::ExceptionOr<GC::Ref<JS::Object>> X448::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  3080. {
  3081. // 1. Let key be the CryptoKey to be exported.
  3082. // 2. If the underlying cryptographic key material represented by the [[handle]] internal slot of key cannot be accessed, then throw an OperationError.
  3083. // Note: In our impl this is always accessible
  3084. auto const& key_data = key->handle().get<ByteBuffer>();
  3085. // 3. If format is "spki":
  3086. if (format == Bindings::KeyFormat::Spki) {
  3087. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  3088. if (key->type() != Bindings::KeyType::Public)
  3089. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  3090. // 2. Let data be an instance of the subjectPublicKeyInfo ASN.1 structure defined in [RFC5280] with the following properties:
  3091. // * Set the algorithm field to an AlgorithmIdentifier ASN.1 type with the following properties:
  3092. // * Set the algorithm object identifier to the id-X448 OID defined in [RFC8410].
  3093. // * Set the subjectPublicKey field to keyData.
  3094. auto x448_oid = ::Crypto::Certificate::x448_oid;
  3095. auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_subject_public_key_info(key_data, x448_oid, nullptr));
  3096. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  3097. return JS::ArrayBuffer::create(m_realm, data);
  3098. }
  3099. // 3. If format is "pkcs8":
  3100. if (format == Bindings::KeyFormat::Pkcs8) {
  3101. // 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
  3102. if (key->type() != Bindings::KeyType::Private)
  3103. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a private key"_string);
  3104. // 2. Let data be an instance of the privateKeyInfo ASN.1 structure defined in [RFC5208] with the following properties:
  3105. // * Set the version field to 0.
  3106. // * Set the privateKeyAlgorithm field to a PrivateKeyAlgorithmIdentifier ASN.1 type with the following properties:
  3107. // * Set the algorithm object identifier to the id-X448 OID defined in [RFC8410].
  3108. // * Set the privateKey field to the result of DER-encoding a CurvePrivateKey ASN.1 type, as defined in Section 7 of [RFC8410], that represents the X448 private key represented by the [[handle]] internal slot of key
  3109. auto x448_oid = ::Crypto::Certificate::x448_oid;
  3110. auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_private_key_info(key_data, x448_oid, nullptr));
  3111. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  3112. return JS::ArrayBuffer::create(m_realm, data);
  3113. }
  3114. // 3. If format is "jwk":
  3115. if (format == Bindings::KeyFormat::Jwk) {
  3116. // 1. Let jwk be a new JsonWebKey dictionary.
  3117. Bindings::JsonWebKey jwk = {};
  3118. // 2. Set the kty attribute of jwk to "OKP".
  3119. jwk.kty = "OKP"_string;
  3120. // 3. Set the crv attribute of jwk to "X448".
  3121. jwk.crv = "X448"_string;
  3122. // 4. Set the x attribute of jwk according to the definition in Section 2 of [RFC8037].
  3123. jwk.x = TRY_OR_THROW_OOM(m_realm->vm(), encode_base64url(key_data));
  3124. // 5. If the [[type]] internal slot of key is "private"
  3125. if (key->type() == Bindings::KeyType::Private) {
  3126. // 1. Set the d attribute of jwk according to the definition in Section 2 of [RFC8037].
  3127. jwk.d = TRY_OR_THROW_OOM(m_realm->vm(), encode_base64url(key_data));
  3128. }
  3129. // 6. Set the key_ops attribute of jwk to the usages attribute of key.
  3130. jwk.key_ops = Vector<String> {};
  3131. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  3132. for (auto const& usage : key->internal_usages())
  3133. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  3134. // 7. Set the ext attribute of jwk to the [[extractable]] internal slot of key.
  3135. jwk.ext = key->extractable();
  3136. // 8. Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  3137. auto result = TRY(jwk.to_object(m_realm));
  3138. return GC::Ref { *result };
  3139. }
  3140. // 3. If format is "raw":
  3141. if (format == Bindings::KeyFormat::Raw) {
  3142. // 1. If the [[type]] internal slot of key is not "public", then throw an InvalidAccessError.
  3143. if (key->type() != Bindings::KeyType::Public)
  3144. return WebIDL::InvalidAccessError::create(m_realm, "Key is not a public key"_string);
  3145. // 2. Let data be an octet string representing the X448 public key represented by the [[handle]] internal slot of key.
  3146. // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data.
  3147. return JS::ArrayBuffer::create(m_realm, key_data);
  3148. }
  3149. // 3. Otherwise:
  3150. // throw a NotSupportedError.
  3151. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  3152. }
  3153. // https://wicg.github.io/webcrypto-secure-curves/#x448-operations
  3154. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X448::import_key(
  3155. AlgorithmParams const&,
  3156. Bindings::KeyFormat format,
  3157. CryptoKey::InternalKeyData key_data,
  3158. bool extractable,
  3159. Vector<Bindings::KeyUsage> const& usages)
  3160. {
  3161. // 1. Let keyData be the key data to be imported.
  3162. // 2. If format is "spki":
  3163. if (format == Bindings::KeyFormat::Spki) {
  3164. // 1. If usages is not empty then throw a SyntaxError.
  3165. if (!usages.is_empty())
  3166. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty"_string);
  3167. // 2. Let spki be the result of running the parse a subjectPublicKeyInfo algorithm over keyData.
  3168. // 3. If an error occurred while parsing, then throw a DataError.
  3169. auto spki = TRY(parse_a_subject_public_key_info(m_realm, key_data.get<ByteBuffer>()));
  3170. // 4. If the algorithm object identifier field of the algorithm AlgorithmIdentifier field of spki is not equal to the id-X448 object identifier defined in [RFC8410], then throw a DataError.
  3171. if (spki.algorithm.identifier != ::Crypto::Certificate::x448_oid)
  3172. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3173. // 5. If the parameters field of the algorithm AlgorithmIdentifier field of spki is present, then throw a DataError.
  3174. if (spki.algorithm.ec_parameters.has_value())
  3175. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  3176. // 6. Let publicKey be the X448 public key identified by the subjectPublicKey field of spki.
  3177. auto const& public_key = spki.raw_key;
  3178. // 7. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and that represents publicKey.
  3179. auto key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  3180. // 8. Set the [[type]] internal slot of key to "public"
  3181. key->set_type(Bindings::KeyType::Public);
  3182. // 9. Let algorithm be a new KeyAlgorithm.
  3183. auto algorithm = KeyAlgorithm::create(m_realm);
  3184. // 10. Set the name attribute of algorithm to "X448".
  3185. algorithm->set_name("X448"_string);
  3186. // 11. Set the [[algorithm]] internal slot of key to algorithm.
  3187. key->set_algorithm(algorithm);
  3188. return key;
  3189. }
  3190. // 3. If format is "pkcs8":
  3191. if (format == Bindings::KeyFormat::Pkcs8) {
  3192. // 1. If usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  3193. for (auto const& usage : usages) {
  3194. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  3195. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  3196. }
  3197. }
  3198. // 2. Let privateKeyInfo be the result of running the parse a privateKeyInfo algorithm over keyData.
  3199. // 3. If an error occurred while parsing, then throw a DataError.
  3200. auto private_key_info = TRY(parse_a_private_key_info(m_realm, key_data.get<ByteBuffer>()));
  3201. auto private_key = private_key_info.raw_key;
  3202. // 4. If the algorithm object identifier field of the privateKeyAlgorithm PrivateKeyAlgorithm field of privateKeyInfo is not equal to the id-X448 object identifier defined in [RFC8410], then throw a DataError.
  3203. if (private_key_info.algorithm.identifier != ::Crypto::Certificate::x448_oid)
  3204. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3205. // 5. If the parameters field of the privateKeyAlgorithm PrivateKeyAlgorithmIdentifier field of privateKeyInfo is present, then throw a DataError.
  3206. if (private_key_info.algorithm.ec_parameters.has_value())
  3207. return WebIDL::DataError::create(m_realm, "Invalid algorithm parameters"_string);
  3208. // 6. Let curvePrivateKey be the result of performing the parse an ASN.1 structure algorithm,
  3209. // with data as the privateKey field of privateKeyInfo, structure as the ASN.1 CurvePrivateKey
  3210. // structure specified in Section 7 of [RFC8410], and exactData set to true.
  3211. // 7. If an error occurred while parsing, then throw a DataError.
  3212. auto curve_private_key = TRY(parse_an_ASN1_structure<StringView>(m_realm, private_key_info.raw_key, true));
  3213. auto curve_private_key_bytes = TRY_OR_THROW_OOM(m_realm->vm(), ByteBuffer::copy(curve_private_key.bytes()));
  3214. // 8. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and that represents the X448 private key identified by curvePrivateKey.
  3215. auto key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { curve_private_key_bytes });
  3216. // 9. Set the [[type]] internal slot of key to "private"
  3217. key->set_type(Bindings::KeyType::Private);
  3218. // 10. Let algorithm be a new KeyAlgorithm.
  3219. auto algorithm = KeyAlgorithm::create(m_realm);
  3220. // 11. Set the name attribute of algorithm to "X448".
  3221. algorithm->set_name("X448"_string);
  3222. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  3223. key->set_algorithm(algorithm);
  3224. return key;
  3225. }
  3226. // 3. If format is "jwk":
  3227. if (format == Bindings::KeyFormat::Jwk) {
  3228. // 1. If keyData is a JsonWebKey dictionary:
  3229. // Let jwk equal keyData.
  3230. // Otherwise:
  3231. // Throw a DataError.
  3232. if (!key_data.has<Bindings::JsonWebKey>())
  3233. return WebIDL::DataError::create(m_realm, "Data is not a JsonWebKey dictionary"_string);
  3234. auto jwk = key_data.get<Bindings::JsonWebKey>();
  3235. // 2. If the d field is present and if usages contains an entry which is not "deriveKey" or "deriveBits" then throw a SyntaxError.
  3236. if (jwk.d.has_value()) {
  3237. for (auto const& usage : usages) {
  3238. if (usage != Bindings::KeyUsage::Derivekey && usage != Bindings::KeyUsage::Derivebits) {
  3239. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  3240. }
  3241. }
  3242. }
  3243. // 3. If the d field is not present and if usages is not empty then throw a SyntaxError.
  3244. if (!jwk.d.has_value() && !usages.is_empty())
  3245. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty"_string);
  3246. // 4. If the kty field of jwk is not "OKP", then throw a DataError.
  3247. if (jwk.kty != "OKP"sv)
  3248. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  3249. // 5. If the crv field of jwk is not "X448", then throw a DataError.
  3250. if (jwk.crv != "X448"sv)
  3251. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  3252. // 6. If usages is non-empty and the use field of jwk is present and is not equal to "enc" then throw a DataError.
  3253. if (!usages.is_empty() && jwk.use.has_value() && jwk.use.value() != "enc"sv)
  3254. return WebIDL::DataError::create(m_realm, "Invalid use"_string);
  3255. // 7. If the key_ops field of jwk is present, and is invalid according to the requirements of JSON Web Key [JWK],
  3256. // or it does not contain all of the specified usages values, then throw a DataError.
  3257. TRY(validate_jwk_key_ops(m_realm, jwk, usages));
  3258. // 8. If the ext field of jwk is present and has the value false and extractable is true, then throw a DataError.
  3259. if (jwk.ext.has_value() && !jwk.ext.value() && extractable)
  3260. return WebIDL::DataError::create(m_realm, "Invalid extractable"_string);
  3261. GC::Ptr<CryptoKey> key = nullptr;
  3262. // 9. If the d field is present:
  3263. if (jwk.d.has_value()) {
  3264. // 1. If jwk does not meet the requirements of the JWK private key format described in Section 2 of [RFC8037], then throw a DataError.
  3265. // o The parameter "kty" MUST be "OKP".
  3266. if (jwk.kty != "OKP"sv)
  3267. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  3268. // // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  3269. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  3270. if (jwk.crv != "X448"sv)
  3271. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  3272. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  3273. if (!jwk.x.has_value())
  3274. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  3275. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  3276. // This parameter MUST NOT be present for public keys.
  3277. if (!jwk.d.has_value())
  3278. return WebIDL::DataError::create(m_realm, "Missing d field"_string);
  3279. // 2. Let key be a new CryptoKey object that represents the X25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
  3280. auto private_key_base_64 = jwk.d.value();
  3281. auto private_key_or_error = decode_base64url(private_key_base_64);
  3282. if (private_key_or_error.is_error()) {
  3283. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  3284. }
  3285. auto private_key = private_key_or_error.release_value();
  3286. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
  3287. // 3. Set the [[type]] internal slot of Key to "private".
  3288. key->set_type(Bindings::KeyType::Private);
  3289. }
  3290. // Otherwise:
  3291. else {
  3292. // 1. If jwk does not meet the requirements of the JWK public key format described in Section 2 of [RFC8037], then throw a DataError.
  3293. // o The parameter "kty" MUST be "OKP".
  3294. if (jwk.kty != "OKP"sv)
  3295. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  3296. // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
  3297. // o The parameter "crv" MUST be present and contain the subtype of the key (from the "JSON Web Elliptic Curve" registry).
  3298. if (jwk.crv != "X448"sv)
  3299. return WebIDL::DataError::create(m_realm, "Invalid curve"_string);
  3300. // o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
  3301. if (!jwk.x.has_value())
  3302. return WebIDL::DataError::create(m_realm, "Missing x field"_string);
  3303. // o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
  3304. // This parameter MUST NOT be present for public keys.
  3305. if (jwk.d.has_value())
  3306. return WebIDL::DataError::create(m_realm, "Present d field"_string);
  3307. // 2. Let key be a new CryptoKey object that represents the Ed25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
  3308. auto public_key_base_64 = jwk.x.value();
  3309. auto public_key_or_error = decode_base64url(public_key_base_64);
  3310. if (public_key_or_error.is_error()) {
  3311. return WebIDL::DataError::create(m_realm, "Failed to decode base64"_string);
  3312. }
  3313. auto public_key = public_key_or_error.release_value();
  3314. key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
  3315. // 3. Set the [[type]] internal slot of Key to "public".
  3316. key->set_type(Bindings::KeyType::Public);
  3317. }
  3318. // 10. Let algorithm be a new instance of a KeyAlgorithm object.
  3319. auto algorithm = KeyAlgorithm::create(m_realm);
  3320. // 11. Set the name attribute of algorithm to "X448".
  3321. algorithm->set_name("X448"_string);
  3322. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  3323. key->set_algorithm(algorithm);
  3324. return GC::Ref { *key };
  3325. }
  3326. // 3. If format is "raw":
  3327. if (format == Bindings::KeyFormat::Raw) {
  3328. // 1. If usages is not empty then throw a SyntaxError.
  3329. if (!usages.is_empty())
  3330. return WebIDL::SyntaxError::create(m_realm, "Usages must be empty"_string);
  3331. // 2. Let algorithm be a new KeyAlgorithm object.
  3332. auto algorithm = KeyAlgorithm::create(m_realm);
  3333. // 3. Set the name attribute of algorithm to "X448".
  3334. algorithm->set_name("X448"_string);
  3335. // 4. Let key be a new CryptoKey associated with the relevant global object of this [HTML], and representing the key data provided in keyData.
  3336. auto key = CryptoKey::create(m_realm, key_data);
  3337. // 5. Set the [[type]] internal slot of key to "public"
  3338. key->set_type(Bindings::KeyType::Public);
  3339. // 6. Set the [[algorithm]] internal slot of key to algorithm.
  3340. key->set_algorithm(algorithm);
  3341. return key;
  3342. }
  3343. (void)extractable;
  3344. // 3. Otherwise:
  3345. // throw a NotSupportedError.
  3346. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  3347. }
  3348. static WebIDL::ExceptionOr<ByteBuffer> hmac_calculate_message_digest(JS::Realm& realm, GC::Ptr<KeyAlgorithm> hash, ReadonlyBytes key, ReadonlyBytes message)
  3349. {
  3350. auto calculate_digest = [&]<typename T>() -> ByteBuffer {
  3351. ::Crypto::Authentication::HMAC<T> hmac(key);
  3352. auto digest = hmac.process(message);
  3353. return MUST(ByteBuffer::copy(digest.bytes()));
  3354. };
  3355. auto hash_name = hash->name();
  3356. if (hash_name.equals_ignoring_ascii_case("SHA-1"sv))
  3357. return calculate_digest.operator()<::Crypto::Hash::SHA1>();
  3358. if (hash_name.equals_ignoring_ascii_case("SHA-256"sv))
  3359. return calculate_digest.operator()<::Crypto::Hash::SHA256>();
  3360. if (hash_name.equals_ignoring_ascii_case("SHA-384"sv))
  3361. return calculate_digest.operator()<::Crypto::Hash::SHA384>();
  3362. if (hash_name.equals_ignoring_ascii_case("SHA-512"sv))
  3363. return calculate_digest.operator()<::Crypto::Hash::SHA512>();
  3364. return WebIDL::NotSupportedError::create(realm, "Invalid algorithm"_string);
  3365. }
  3366. static WebIDL::ExceptionOr<WebIDL::UnsignedLong> hmac_hash_block_size(JS::Realm& realm, HashAlgorithmIdentifier hash)
  3367. {
  3368. auto hash_name = TRY(hash.name(realm.vm()));
  3369. if (hash_name.equals_ignoring_ascii_case("SHA-1"sv))
  3370. return ::Crypto::Hash::SHA1::digest_size();
  3371. if (hash_name.equals_ignoring_ascii_case("SHA-256"sv))
  3372. return ::Crypto::Hash::SHA256::digest_size();
  3373. if (hash_name.equals_ignoring_ascii_case("SHA-384"sv))
  3374. return ::Crypto::Hash::SHA384::digest_size();
  3375. if (hash_name.equals_ignoring_ascii_case("SHA-512"sv))
  3376. return ::Crypto::Hash::SHA512::digest_size();
  3377. return WebIDL::NotSupportedError::create(realm, MUST(String::formatted("Invalid hash function '{}'", hash_name)));
  3378. }
  3379. // https://w3c.github.io/webcrypto/#hmac-operations
  3380. WebIDL::ExceptionOr<GC::Ref<JS::ArrayBuffer>> HMAC::sign(AlgorithmParams const&, GC::Ref<CryptoKey> key, ByteBuffer const& message)
  3381. {
  3382. // 1. Let mac be the result of performing the MAC Generation operation described in Section 4 of
  3383. // [FIPS-198-1] using the key represented by [[handle]] internal slot of key, the hash
  3384. // function identified by the hash attribute of the [[algorithm]] internal slot of key and
  3385. // message as the input data text.
  3386. auto const& key_data = key->handle().get<ByteBuffer>();
  3387. auto const& algorithm = verify_cast<HmacKeyAlgorithm>(*key->algorithm());
  3388. auto mac = TRY(hmac_calculate_message_digest(m_realm, algorithm.hash(), key_data.bytes(), message.bytes()));
  3389. // 2. Return the result of creating an ArrayBuffer containing mac.
  3390. return JS::ArrayBuffer::create(m_realm, move(mac));
  3391. }
  3392. // https://w3c.github.io/webcrypto/#hmac-operations
  3393. WebIDL::ExceptionOr<JS::Value> HMAC::verify(AlgorithmParams const&, GC::Ref<CryptoKey> key, ByteBuffer const& signature, ByteBuffer const& message)
  3394. {
  3395. // 1. Let mac be the result of performing the MAC Generation operation described in Section 4 of
  3396. // [FIPS-198-1] using the key represented by [[handle]] internal slot of key, the hash
  3397. // function identified by the hash attribute of the [[algorithm]] internal slot of key and
  3398. // message as the input data text.
  3399. auto const& key_data = key->handle().get<ByteBuffer>();
  3400. auto const& algorithm = verify_cast<HmacKeyAlgorithm>(*key->algorithm());
  3401. auto mac = TRY(hmac_calculate_message_digest(m_realm, algorithm.hash(), key_data.bytes(), message.bytes()));
  3402. // 2. Return true if mac is equal to signature and false otherwise.
  3403. return mac == signature;
  3404. }
  3405. // https://w3c.github.io/webcrypto/#hmac-operations
  3406. WebIDL::ExceptionOr<Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>>> HMAC::generate_key(AlgorithmParams const& params, bool extractable, Vector<Bindings::KeyUsage> const& usages)
  3407. {
  3408. // 1. If usages contains any entry which is not "sign" or "verify", then throw a SyntaxError.
  3409. for (auto const& usage : usages) {
  3410. if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify)
  3411. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  3412. }
  3413. // 2. If the length member of normalizedAlgorithm is not present:
  3414. auto const& normalized_algorithm = static_cast<HmacKeyGenParams const&>(params);
  3415. WebIDL::UnsignedLong length;
  3416. if (!normalized_algorithm.length.has_value()) {
  3417. // Let length be the block size in bits of the hash function identified by the hash member
  3418. // of normalizedAlgorithm.
  3419. length = TRY(hmac_hash_block_size(m_realm, normalized_algorithm.hash));
  3420. }
  3421. // Otherwise, if the length member of normalizedAlgorithm is non-zero:
  3422. else if (normalized_algorithm.length.value() != 0) {
  3423. // Let length be equal to the length member of normalizedAlgorithm.
  3424. length = normalized_algorithm.length.value();
  3425. }
  3426. // Otherwise:
  3427. else {
  3428. // throw an OperationError.
  3429. return WebIDL::OperationError::create(m_realm, "Invalid length"_string);
  3430. }
  3431. // 3. Generate a key of length length bits.
  3432. auto key_data = MUST(generate_random_key(m_realm->vm(), length));
  3433. // 4. If the key generation step fails, then throw an OperationError.
  3434. // NOTE: Currently key generation must succeed
  3435. // 5. Let key be a new CryptoKey object representing the generated key.
  3436. auto key = CryptoKey::create(m_realm, move(key_data));
  3437. // 6. Let algorithm be a new HmacKeyAlgorithm.
  3438. auto algorithm = HmacKeyAlgorithm::create(m_realm);
  3439. // 7. Set the name attribute of algorithm to "HMAC".
  3440. algorithm->set_name("HMAC"_string);
  3441. // 8. Let hash be a new KeyAlgorithm.
  3442. auto hash = KeyAlgorithm::create(m_realm);
  3443. // 9. Set the name attribute of hash to equal the name member of the hash member of normalizedAlgorithm.
  3444. hash->set_name(TRY(normalized_algorithm.hash.name(m_realm->vm())));
  3445. // 10. Set the hash attribute of algorithm to hash.
  3446. algorithm->set_hash(hash);
  3447. // 11. Set the [[type]] internal slot of key to "secret".
  3448. key->set_type(Bindings::KeyType::Secret);
  3449. // 12. Set the [[algorithm]] internal slot of key to algorithm.
  3450. key->set_algorithm(algorithm);
  3451. // 13. Set the [[extractable]] internal slot of key to be extractable.
  3452. key->set_extractable(extractable);
  3453. // 14. Set the [[usages]] internal slot of key to be usages.
  3454. key->set_usages(usages);
  3455. // 15. Return key.
  3456. return Variant<GC::Ref<CryptoKey>, GC::Ref<CryptoKeyPair>> { key };
  3457. }
  3458. // https://w3c.github.io/webcrypto/#hmac-operations
  3459. WebIDL::ExceptionOr<GC::Ref<CryptoKey>> HMAC::import_key(Web::Crypto::AlgorithmParams const& params, Bindings::KeyFormat key_format, CryptoKey::InternalKeyData key_data, bool extractable, Vector<Bindings::KeyUsage> const& usages)
  3460. {
  3461. auto& vm = m_realm->vm();
  3462. auto const& normalized_algorithm = static_cast<HmacImportParams const&>(params);
  3463. // 1. Let keyData be the key data to be imported.
  3464. // 2. If usages contains an entry which is not "sign" or "verify", then throw a SyntaxError.
  3465. for (auto const& usage : usages) {
  3466. if (usage != Bindings::KeyUsage::Sign && usage != Bindings::KeyUsage::Verify)
  3467. return WebIDL::SyntaxError::create(m_realm, MUST(String::formatted("Invalid key usage '{}'", idl_enum_to_string(usage))));
  3468. }
  3469. // 3. Let hash be a new KeyAlgorithm.
  3470. auto hash = KeyAlgorithm::create(m_realm);
  3471. // 4. If format is "raw":
  3472. AK::ByteBuffer data;
  3473. if (key_format == Bindings::KeyFormat::Raw) {
  3474. // 4.1. Let data be the octet string contained in keyData.
  3475. data = key_data.get<ByteBuffer>();
  3476. // 4.2. Set hash to equal the hash member of normalizedAlgorithm.
  3477. hash->set_name(TRY(normalized_algorithm.hash.name(vm)));
  3478. }
  3479. // If format is "jwk":
  3480. else if (key_format == Bindings::KeyFormat::Jwk) {
  3481. // 1. If keyData is a JsonWebKey dictionary:
  3482. // Let jwk equal keyData.
  3483. // Otherwise:
  3484. // Throw a DataError.
  3485. if (!key_data.has<Bindings::JsonWebKey>())
  3486. return WebIDL::DataError::create(m_realm, "Data is not a JsonWebKey dictionary"_string);
  3487. auto jwk = key_data.get<Bindings::JsonWebKey>();
  3488. // 2. If the kty field of jwk is not "oct", then throw a DataError.
  3489. if (jwk.kty != "oct"sv)
  3490. return WebIDL::DataError::create(m_realm, "Invalid key type"_string);
  3491. // 3. If jwk does not meet the requirements of Section 6.4 of JSON Web Algorithms [JWA],
  3492. // then throw a DataError.
  3493. // 4. Let data be the octet string obtained by decoding the k field of jwk.
  3494. data = TRY(parse_jwk_symmetric_key(m_realm, jwk));
  3495. // 5. Set the hash to equal the hash member of normalizedAlgorithm.
  3496. hash->set_name(TRY(normalized_algorithm.hash.name(vm)));
  3497. // 6. If the name attribute of hash is "SHA-1":
  3498. auto hash_name = hash->name();
  3499. if (hash_name.equals_ignoring_ascii_case("SHA-1"sv)) {
  3500. // If the alg field of jwk is present and is not "HS1", then throw a DataError.
  3501. if (jwk.alg.has_value() && jwk.alg != "HS1"sv)
  3502. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3503. }
  3504. // If the name attribute of hash is "SHA-256":
  3505. else if (hash_name.equals_ignoring_ascii_case("SHA-256"sv)) {
  3506. // If the alg field of jwk is present and is not "HS256", then throw a DataError.
  3507. if (jwk.alg.has_value() && jwk.alg != "HS256"sv)
  3508. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3509. }
  3510. // If the name attribute of hash is "SHA-384":
  3511. else if (hash_name.equals_ignoring_ascii_case("SHA-384"sv)) {
  3512. // If the alg field of jwk is present and is not "HS384", then throw a DataError.
  3513. if (jwk.alg.has_value() && jwk.alg != "HS384"sv)
  3514. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3515. }
  3516. // If the name attribute of hash is "SHA-512":
  3517. else if (hash_name.equals_ignoring_ascii_case("SHA-512"sv)) {
  3518. // If the alg field of jwk is present and is not "HS512", then throw a DataError.
  3519. if (jwk.alg.has_value() && jwk.alg != "HS512"sv)
  3520. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3521. }
  3522. // FIXME: Otherwise, if the name attribute of hash is defined in another applicable specification:
  3523. else {
  3524. // FIXME: Perform any key import steps defined by other applicable specifications, passing format,
  3525. // jwk and hash and obtaining hash.
  3526. dbgln("Hash algorithm '{}' not supported", hash_name);
  3527. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3528. }
  3529. // 7. If usages is non-empty and the use field of jwk is present and is not "sign", then
  3530. // throw a DataError.
  3531. if (!usages.is_empty() && jwk.use.has_value() && jwk.use != "sign"sv)
  3532. return WebIDL::DataError::create(m_realm, "Invalid use in JsonWebKey"_string);
  3533. // 8. If the key_ops field of jwk is present, and is invalid according to the requirements
  3534. // of JSON Web Key [JWK] or does not contain all of the specified usages values, then
  3535. // throw a DataError.
  3536. TRY(validate_jwk_key_ops(m_realm, jwk, usages));
  3537. // 9. If the ext field of jwk is present and has the value false and extractable is true,
  3538. // then throw a DataError.
  3539. if (jwk.ext.has_value() && !*jwk.ext && extractable)
  3540. return WebIDL::DataError::create(m_realm, "Invalid ext field"_string);
  3541. }
  3542. // Otherwise:
  3543. else {
  3544. // throw a NotSupportedError.
  3545. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  3546. }
  3547. // 5. Let length be equivalent to the length, in octets, of data, multiplied by 8.
  3548. auto length = data.size() * 8;
  3549. // 6. If length is zero then throw a DataError.
  3550. if (length == 0)
  3551. return WebIDL::DataError::create(m_realm, "No data provided"_string);
  3552. // 7. If the length member of normalizedAlgorithm is present:
  3553. if (normalized_algorithm.length.has_value()) {
  3554. // If the length member of normalizedAlgorithm is greater than length:
  3555. auto normalized_algorithm_length = normalized_algorithm.length.value();
  3556. if (normalized_algorithm_length > length) {
  3557. // throw a DataError.
  3558. return WebIDL::DataError::create(m_realm, "Invalid data size"_string);
  3559. }
  3560. // If the length member of normalizedAlgorithm, is less than or equal to length minus eight:
  3561. if (normalized_algorithm_length <= length - 8) {
  3562. // throw a DataError.
  3563. return WebIDL::DataError::create(m_realm, "Invalid data size"_string);
  3564. }
  3565. // Otherwise:
  3566. // Set length equal to the length member of normalizedAlgorithm.
  3567. length = normalized_algorithm_length;
  3568. }
  3569. // 8. Let key be a new CryptoKey object representing an HMAC key with the first length bits of data.
  3570. auto length_in_bytes = length / 8;
  3571. if (data.size() > length_in_bytes)
  3572. data = MUST(data.slice(0, length_in_bytes));
  3573. auto key = CryptoKey::create(m_realm, move(data));
  3574. // 9. Set the [[type]] internal slot of key to "secret".
  3575. key->set_type(Bindings::KeyType::Secret);
  3576. // 10. Let algorithm be a new HmacKeyAlgorithm.
  3577. auto algorithm = HmacKeyAlgorithm::create(m_realm);
  3578. // 11. Set the name attribute of algorithm to "HMAC".
  3579. algorithm->set_name("HMAC"_string);
  3580. // 12. Set the length attribute of algorithm to length.
  3581. algorithm->set_length(length);
  3582. // 13. Set the hash attribute of algorithm to hash.
  3583. algorithm->set_hash(hash);
  3584. // 14. Set the [[algorithm]] internal slot of key to algorithm.
  3585. key->set_algorithm(algorithm);
  3586. // 15. Return key.
  3587. return key;
  3588. }
  3589. // https://w3c.github.io/webcrypto/#hmac-operations
  3590. WebIDL::ExceptionOr<GC::Ref<JS::Object>> HMAC::export_key(Bindings::KeyFormat format, GC::Ref<CryptoKey> key)
  3591. {
  3592. // 1. If the underlying cryptographic key material represented by the [[handle]] internal slot
  3593. // of key cannot be accessed, then throw an OperationError.
  3594. // NOTE: In our impl this is always accessible
  3595. // 2. Let bits be the raw bits of the key represented by [[handle]] internal slot of key.
  3596. // 3. Let data be an octet string containing bits.
  3597. auto data = key->handle().get<ByteBuffer>();
  3598. // 4. If format is "raw":
  3599. GC::Ptr<JS::Object> result;
  3600. if (format == Bindings::KeyFormat::Raw) {
  3601. // Let result be the result of creating an ArrayBuffer containing data.
  3602. result = JS::ArrayBuffer::create(m_realm, data);
  3603. }
  3604. // If format is "jwk":
  3605. else if (format == Bindings::KeyFormat::Jwk) {
  3606. // Let jwk be a new JsonWebKey dictionary.
  3607. Bindings::JsonWebKey jwk {};
  3608. // Set the kty attribute of jwk to the string "oct".
  3609. jwk.kty = "oct"_string;
  3610. // Set the k attribute of jwk to be a string containing data, encoded according to Section
  3611. // 6.4 of JSON Web Algorithms [JWA].
  3612. jwk.k = MUST(encode_base64url(data, AK::OmitPadding::Yes));
  3613. // Let algorithm be the [[algorithm]] internal slot of key.
  3614. auto const& algorithm = verify_cast<HmacKeyAlgorithm>(*key->algorithm());
  3615. // Let hash be the hash attribute of algorithm.
  3616. auto hash = algorithm.hash();
  3617. // If the name attribute of hash is "SHA-1":
  3618. auto hash_name = hash->name();
  3619. if (hash_name.equals_ignoring_ascii_case("SHA-1"sv)) {
  3620. // Set the alg attribute of jwk to the string "HS1".
  3621. jwk.alg = "HS1"_string;
  3622. }
  3623. // If the name attribute of hash is "SHA-256":
  3624. else if (hash_name.equals_ignoring_ascii_case("SHA-256"sv)) {
  3625. // Set the alg attribute of jwk to the string "HS256".
  3626. jwk.alg = "HS256"_string;
  3627. }
  3628. // If the name attribute of hash is "SHA-384":
  3629. else if (hash_name.equals_ignoring_ascii_case("SHA-384"sv)) {
  3630. // Set the alg attribute of jwk to the string "HS384".
  3631. jwk.alg = "HS384"_string;
  3632. }
  3633. // If the name attribute of hash is "SHA-512":
  3634. else if (hash_name.equals_ignoring_ascii_case("SHA-512"sv)) {
  3635. // Set the alg attribute of jwk to the string "HS512".
  3636. jwk.alg = "HS512"_string;
  3637. }
  3638. // FIXME: Otherwise, the name attribute of hash is defined in another applicable
  3639. // specification:
  3640. else {
  3641. // FIXME: Perform any key export steps defined by other applicable specifications,
  3642. // passing format and key and obtaining alg.
  3643. // FIXME: Set the alg attribute of jwk to alg.
  3644. dbgln("Hash algorithm '{}' not supported", hash_name);
  3645. return WebIDL::DataError::create(m_realm, "Invalid algorithm"_string);
  3646. }
  3647. // Set the key_ops attribute of jwk to equal the usages attribute of key.
  3648. jwk.key_ops = Vector<String> {};
  3649. jwk.key_ops->ensure_capacity(key->internal_usages().size());
  3650. for (auto const& usage : key->internal_usages()) {
  3651. jwk.key_ops->append(Bindings::idl_enum_to_string(usage));
  3652. }
  3653. // Set the ext attribute of jwk to equal the [[extractable]] internal slot of key.
  3654. jwk.ext = key->extractable();
  3655. // Let result be the result of converting jwk to an ECMAScript Object, as defined by [WebIDL].
  3656. result = TRY(jwk.to_object(m_realm));
  3657. }
  3658. // Otherwise:
  3659. else {
  3660. // throw a NotSupportedError.
  3661. return WebIDL::NotSupportedError::create(m_realm, "Invalid key format"_string);
  3662. }
  3663. // 5. Return result.
  3664. return GC::Ref { *result };
  3665. }
  3666. // https://w3c.github.io/webcrypto/#hmac-operations
  3667. WebIDL::ExceptionOr<JS::Value> HMAC::get_key_length(AlgorithmParams const& params)
  3668. {
  3669. auto const& normalized_derived_key_algorithm = static_cast<HmacImportParams const&>(params);
  3670. WebIDL::UnsignedLong length;
  3671. // 1. If the length member of normalizedDerivedKeyAlgorithm is not present:
  3672. if (!normalized_derived_key_algorithm.length.has_value()) {
  3673. // Let length be the block size in bits of the hash function identified by the hash member of
  3674. // normalizedDerivedKeyAlgorithm.
  3675. length = TRY(hmac_hash_block_size(m_realm, normalized_derived_key_algorithm.hash));
  3676. }
  3677. // Otherwise, if the length member of normalizedDerivedKeyAlgorithm is non-zero:
  3678. else if (normalized_derived_key_algorithm.length.value() > 0) {
  3679. // Let length be equal to the length member of normalizedDerivedKeyAlgorithm.
  3680. length = normalized_derived_key_algorithm.length.value();
  3681. }
  3682. // Otherwise:
  3683. else {
  3684. // throw a TypeError.
  3685. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid key length"sv };
  3686. }
  3687. // 2. Return length.
  3688. return JS::Value(length);
  3689. }
  3690. }