123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880 |
- /* dtls13.c
- *
- * Copyright (C) 2006-2023 wolfSSL Inc.
- *
- * This file is part of wolfSSL.
- *
- * wolfSSL is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * wolfSSL is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <wolfssl/wolfcrypt/settings.h>
- #ifdef WOLFSSL_DTLS13
- #include <wolfssl/error-ssl.h>
- #include <wolfssl/internal.h>
- #include <wolfssl/ssl.h>
- #include <wolfssl/wolfcrypt/aes.h>
- #include <wolfssl/wolfcrypt/error-crypt.h>
- #include <wolfssl/wolfcrypt/kdf.h>
- #include <wolfssl/wolfcrypt/logging.h>
- #include <wolfssl/wolfcrypt/types.h>
- #ifdef NO_INLINE
- #include <wolfssl/wolfcrypt/misc.h>
- #else
- #define WOLFSSL_MISC_INCLUDED
- #include <wolfcrypt/src/misc.c>
- #endif
- /**
- * enum rnDirection - distinguish between RecordNumber Enc/Dec
- * PROTECT: encrypt the Record Number
- * DEPROTECT: decrypt the Record Number
- */
- enum rnDirection {
- PROTECT = 0,
- DEPROTECT,
- };
- /**
- * struct Dtls13HandshakeHeader: represent DTLS Handshake header
- * @msg_type: type of message (client_hello,server_hello,etc)
- * @length: length of the message
- * @messageSeq: message sequence number (used for reordering and retransmission)
- * @fragmentOffset: this is the offset of the data in the complete message. For
- * an unfragmented message this is always zero
- * @fragmentLength: length of this fragment (if not fragmented @fragmentLength
- * is always equal to @length)
- */
- typedef struct Dtls13HandshakeHeader {
- byte msg_type;
- byte length[3];
- byte messageSeq[2];
- byte fragmentOffset[3];
- byte fragmentLength[3];
- } Dtls13HandshakeHeader;
- /**
- * struct Dtls13Recordplaintextheader: represent header of unprotected DTLSv1.3
- * record
- * @contentType: content type of the record (handshake, applicationData, etc)
- * @legacyversionrecord: legacy version field
- * @epoch: epoch number (lower 16 bits)
- * @sequenceNumber: sequence number (lower 16 bits)
- * @length: length of the record
- */
- typedef struct Dtls13RecordPlaintextHeader {
- byte contentType;
- ProtocolVersion legacyVersionRecord;
- byte epoch[2];
- byte sequenceNumber[6];
- byte length[2];
- } Dtls13RecordPlaintextHeader;
- /* size of the len field in the unified header */
- #define DTLS13_LEN_SIZE 2
- /* size of the flags in the unified header */
- #define DTLS13_HDR_FLAGS_SIZE 1
- /* size of the sequence number where SEQ_LEN_BIT is present */
- #define DTLS13_SEQ_16_LEN 2
- /* size of the sequence number where SEQ_LEN_BIT is not present */
- #define DTLS13_SEQ_8_LEN 1
- /* fixed bits mask to detect unified header */
- #define DTLS13_FIXED_BITS_MASK (0x111 << 5)
- /* fixed bits value to detect unified header */
- #define DTLS13_FIXED_BITS (0x1 << 5)
- /* ConnectionID present bit in the unified header flags */
- #define DTLS13_CID_BIT (0x1 << 4)
- /* Sequence number is 16 bits if this bit is into unified header flags */
- #define DTLS13_SEQ_LEN_BIT (0x1 << 3)
- /* Length field is present if this bit is into unified header flags */
- #define DTLS13_LEN_BIT (0x1 << 2)
- /* For now, the size of the outgoing DTLSv1.3 record header is fixed to 5 bytes
- (8 bit header flags + 16bit record number + 16 bit length). In the future, we
- can dynamically choose to remove the length from the header to save
- space. Also it will need to account for client connection ID when
- supported. */
- #define DTLS13_UNIFIED_HEADER_SIZE 5
- #define DTLS13_MIN_CIPHERTEXT 16
- #define DTLS13_MIN_RTX_INTERVAL 1
- #ifndef NO_WOLFSSL_CLIENT
- WOLFSSL_METHOD* wolfDTLSv1_3_client_method_ex(void* heap)
- {
- WOLFSSL_METHOD* method;
- WOLFSSL_ENTER("DTLSv1_3_client_method_ex");
- (void)heap;
- method = (WOLFSSL_METHOD*)XMALLOC(sizeof(WOLFSSL_METHOD), heap,
- DYNAMIC_TYPE_METHOD);
- if (method)
- InitSSL_Method(method, MakeDTLSv1_3());
- return method;
- }
- WOLFSSL_METHOD* wolfDTLSv1_3_client_method(void)
- {
- return wolfDTLSv1_3_client_method_ex(NULL);
- }
- #endif /* !NO_WOLFSSL_CLIENT */
- #ifndef NO_WOLFSSL_SERVER
- WOLFSSL_METHOD* wolfDTLSv1_3_server_method_ex(void* heap)
- {
- WOLFSSL_METHOD* method;
- WOLFSSL_ENTER("DTLSv1_3_server_method_ex");
- (void)heap;
- method = (WOLFSSL_METHOD*)XMALLOC(sizeof(WOLFSSL_METHOD), heap,
- DYNAMIC_TYPE_METHOD);
- if (method) {
- InitSSL_Method(method, MakeDTLSv1_3());
- method->side = WOLFSSL_SERVER_END;
- }
- return method;
- }
- WOLFSSL_METHOD* wolfDTLSv1_3_server_method(void)
- {
- return wolfDTLSv1_3_server_method_ex(NULL);
- }
- #endif /* !NO_WOLFSSL_SERVER */
- int Dtls13RlAddPlaintextHeader(WOLFSSL* ssl, byte* out,
- enum ContentType content_type, word16 length)
- {
- Dtls13RecordPlaintextHeader* hdr;
- word32 seq[2];
- int ret;
- hdr = (Dtls13RecordPlaintextHeader*)out;
- hdr->contentType = content_type;
- hdr->legacyVersionRecord.major = DTLS_MAJOR;
- hdr->legacyVersionRecord.minor = DTLSv1_2_MINOR;
- ret = Dtls13GetSeq(ssl, CUR_ORDER, seq, 1);
- if (ret != 0)
- return ret;
- /* seq[0] combines the epoch and 16 MSB of sequence number. We write on the
- epoch field and will overflow to the first two bytes of the sequence
- number */
- c32toa(seq[0], hdr->epoch);
- c32toa(seq[1], &hdr->sequenceNumber[2]);
- c16toa(length, hdr->length);
- return 0;
- }
- static int Dtls13HandshakeAddHeaderFrag(WOLFSSL* ssl, byte* output,
- enum HandShakeType msg_type, word32 frag_offset, word32 frag_length,
- word32 msg_length)
- {
- Dtls13HandshakeHeader* hdr;
- hdr = (Dtls13HandshakeHeader*)output;
- hdr->msg_type = msg_type;
- c32to24((word32)msg_length, hdr->length);
- c16toa(ssl->keys.dtls_handshake_number, hdr->messageSeq);
- c32to24(frag_offset, hdr->fragmentOffset);
- c32to24(frag_length, hdr->fragmentLength);
- return 0;
- }
- static byte Dtls13TypeIsEncrypted(enum HandShakeType hs_type)
- {
- byte ret = 0;
- switch (hs_type) {
- case hello_request:
- case hello_verify_request:
- case client_hello:
- case hello_retry_request:
- case server_hello:
- break;
- case encrypted_extensions:
- case session_ticket:
- case end_of_early_data:
- case certificate:
- case server_key_exchange:
- case certificate_request:
- case server_hello_done:
- case certificate_verify:
- case client_key_exchange:
- case finished:
- case certificate_status:
- case key_update:
- case change_cipher_hs:
- case message_hash:
- case no_shake:
- ret = 1;
- }
- return ret;
- }
- static int Dtls13GetRnMask(WOLFSSL* ssl, const byte* ciphertext, byte* mask,
- enum rnDirection dir)
- {
- RecordNumberCiphers* c;
- if (dir == PROTECT)
- c = &ssl->dtlsRecordNumberEncrypt;
- else
- c = &ssl->dtlsRecordNumberDecrypt;
- #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm ||
- ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm) {
- if (c->aes == NULL)
- return BAD_STATE_E;
- #if !defined(HAVE_SELFTEST) && \
- (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3)))
- return wc_AesEncryptDirect(c->aes, mask, ciphertext);
- #else
- wc_AesEncryptDirect(c->aes, mask, ciphertext);
- return 0;
- #endif
- }
- #endif /* HAVE_AESGCM || HAVE_AESCCM */
- #ifdef HAVE_CHACHA
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_chacha) {
- word32 counter;
- int ret;
- if (c->chacha == NULL)
- return BAD_STATE_E;
- /* assuming CIPHER[0..3] should be interpreted as little endian 32-bits
- integer. The draft rfc isn't really clear on that. See sec 4.2.3 of
- the draft. See also Section 2.3 of the Chacha RFC. */
- ato32le(ciphertext, &counter);
- ret = wc_Chacha_SetIV(c->chacha, &ciphertext[4], counter);
- if (ret != 0)
- return ret;
- XMEMSET(mask, 0, DTLS13_RN_MASK_SIZE);
- return wc_Chacha_Process(c->chacha, mask, mask, DTLS13_RN_MASK_SIZE);
- }
- #endif /* HAVE_CHACHA */
- return NOT_COMPILED_IN;
- }
- static int Dtls13EncryptDecryptRecordNumber(WOLFSSL* ssl, byte* seq,
- int SeqLength, const byte* ciphertext, enum rnDirection dir)
- {
- byte mask[DTLS13_RN_MASK_SIZE];
- int ret;
- #ifdef HAVE_NULL_CIPHER
- /* Do not encrypt record numbers with null cipher. See RFC 9150 Sec 9 */
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_cipher_null)
- return 0;
- #endif /*HAVE_NULL_CIPHER */
- ret = Dtls13GetRnMask(ssl, ciphertext, mask, dir);
- if (ret != 0)
- return ret;
- xorbuf(seq, mask, SeqLength);
- return 0;
- }
- static byte Dtls13RtxMsgNeedsAck(WOLFSSL* ssl, enum HandShakeType hs)
- {
- #ifndef NO_WOLFSSL_SERVER
- /* we send an ACK when processing the finished message. In this case either
- we already sent an ACK for client's Certificate/CertificateVerify or they
- are in our list of seen records and will be included in the ACK
- message */
- if (ssl->options.side == WOLFSSL_SERVER_END && (hs == finished))
- return 1;
- #else
- (void)ssl;
- #endif /* NO_WOLFSSL_SERVER */
- if (hs == session_ticket || hs == key_update)
- return 1;
- return 0;
- }
- static void Dtls13MsgWasProcessed(WOLFSSL* ssl, enum HandShakeType hs)
- {
- if (ssl->options.dtlsStateful)
- ssl->keys.dtls_expected_peer_handshake_number++;
- /* we need to send ACKs on the last message of a flight that needs explicit
- acknowledgment */
- ssl->dtls13Rtx.sendAcks = Dtls13RtxMsgNeedsAck(ssl, hs);
- }
- int Dtls13ProcessBufferedMessages(WOLFSSL* ssl)
- {
- DtlsMsg* msg = ssl->dtls_rx_msg_list;
- word32 idx = 0;
- int ret = 0;
- WOLFSSL_ENTER("Dtls13ProcessBufferedMessages");
- while (msg != NULL) {
- int downgraded = 0;
- idx = 0;
- /* message not in order */
- if (ssl->keys.dtls_expected_peer_handshake_number != msg->seq)
- break;
- /* message not complete */
- if (!msg->ready)
- break;
- #ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
- ret = MsgCheckEncryption(ssl, msg->type, msg->encrypted);
- if (ret != 0) {
- SendAlert(ssl, alert_fatal, unexpected_message);
- break;
- }
- #endif
- /* We may have DTLS <=1.2 msgs stored from before we knew which version
- * we were going to use. Interpret correctly. */
- if (IsAtLeastTLSv1_3(ssl->version)) {
- ret = DoTls13HandShakeMsgType(ssl, msg->fullMsg, &idx, msg->type,
- msg->sz, msg->sz);
- if (!IsAtLeastTLSv1_3(ssl->version))
- downgraded = 1;
- }
- else {
- #if !defined(WOLFSSL_NO_TLS12)
- ret = DoHandShakeMsgType(ssl, msg->fullMsg, &idx, msg->type,
- msg->sz, msg->sz);
- #else
- WOLFSSL_MSG("DTLS1.2 disabled with WOLFSSL_NO_TLS12");
- WOLFSSL_ERROR_VERBOSE(NOT_COMPILED_IN);
- ret = NOT_COMPILED_IN;
- #endif
- }
- /* processing certificate_request triggers a connect. The error came
- * from there, the message can be considered processed successfully.
- * WANT_WRITE means that we are done with processing the msg and we are
- * waiting to flush the output buffer. */
- if ((ret == 0 || ret == WANT_WRITE) || (msg->type == certificate_request &&
- ssl->options.handShakeDone && ret == WC_PENDING_E)) {
- if (IsAtLeastTLSv1_3(ssl->version))
- Dtls13MsgWasProcessed(ssl, (enum HandShakeType)msg->type);
- else if (downgraded)
- /* DoHandShakeMsgType normally handles the hs number but if
- * DoTls13HandShakeMsgType processed 1.2 msgs then this wasn't
- * incremented. */
- ssl->keys.dtls_expected_peer_handshake_number++;
- ssl->dtls_rx_msg_list = msg->next;
- DtlsMsgDelete(msg, ssl->heap);
- msg = ssl->dtls_rx_msg_list;
- ssl->dtls_rx_msg_list_sz--;
- }
- if (ret != 0)
- break;
- }
- WOLFSSL_LEAVE("dtls13_process_buffered_messages()", ret);
- return ret;
- }
- static int Dtls13NextMessageComplete(WOLFSSL* ssl)
- {
- return ssl->dtls_rx_msg_list != NULL &&
- ssl->dtls_rx_msg_list->ready &&
- ssl->dtls_rx_msg_list->seq ==
- ssl->keys.dtls_expected_peer_handshake_number;
- }
- static WC_INLINE int FragIsInOutputBuffer(WOLFSSL* ssl, const byte* frag)
- {
- const byte* OutputBuffer = ssl->buffers.outputBuffer.buffer;
- word32 OutputBufferSize = ssl->buffers.outputBuffer.bufferSize;
- return frag >= OutputBuffer && frag < OutputBuffer + OutputBufferSize;
- }
- static int Dtls13SendFragFromBuffer(WOLFSSL* ssl, byte* output, word16 length)
- {
- byte* buf;
- int ret;
- if (FragIsInOutputBuffer(ssl, output))
- return BAD_FUNC_ARG;
- ret = CheckAvailableSize(ssl, length);
- if (ret != 0)
- return ret;
- buf = GetOutputBuffer(ssl);
- XMEMCPY(buf, output, length);
- ssl->buffers.outputBuffer.length += length;
- return SendBuffered(ssl);
- }
- static int Dtls13SendNow(WOLFSSL* ssl, enum HandShakeType handshakeType)
- {
- if (!ssl->options.groupMessages || ssl->dtls13SendingFragments)
- return 1;
- if (handshakeType == client_hello || handshakeType == hello_retry_request ||
- handshakeType == finished || handshakeType == session_ticket ||
- handshakeType == session_ticket || handshakeType == key_update ||
- (handshakeType == certificate_request &&
- ssl->options.handShakeState == HANDSHAKE_DONE))
- return 1;
- return 0;
- }
- /* Handshake header DTLS only fields are not included in the transcript hash.
- * body points to the body of the DTLSHandshake message. */
- int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash, int* hashSz,
- const byte* body, word32 length, CipherSpecs* specs)
- {
- /* msg_type(1) + length (3) */
- byte header[OPAQUE32_LEN];
- int ret;
- wc_HashAlg hashCtx;
- int type = wolfSSL_GetHmacType_ex(specs);
- header[0] = (byte)client_hello;
- c32to24(length, header + 1);
- ret = wc_HashInit_ex(&hashCtx, type, ssl->heap, ssl->devId);
- if (ret == 0) {
- ret = wc_HashUpdate(&hashCtx, type, header, OPAQUE32_LEN);
- if (ret == 0)
- ret = wc_HashUpdate(&hashCtx, type, body, length);
- if (ret == 0)
- ret = wc_HashFinal(&hashCtx, type, hash);
- if (ret == 0) {
- *hashSz = wc_HashGetDigestSize(type);
- if (*hashSz < 0)
- ret = *hashSz;
- }
- wc_HashFree(&hashCtx, type);
- }
- return ret;
- }
- /* Handshake header DTLS only fields are not included in the transcript hash */
- int Dtls13HashHandshake(WOLFSSL* ssl, const byte* input, word16 length)
- {
- int ret;
- if (length < DTLS_HANDSHAKE_HEADER_SZ)
- return BAD_FUNC_ARG;
- /* msg_type(1) + length (3) */
- ret = HashRaw(ssl, input, OPAQUE32_LEN);
- if (ret != 0)
- return ret;
- input += OPAQUE32_LEN;
- length -= OPAQUE32_LEN;
- /* message_seq(2) + fragment_offset(3) + fragment_length(3) */
- input += OPAQUE64_LEN;
- length -= OPAQUE64_LEN;
- return HashRaw(ssl, input, length);
- }
- static int Dtls13SendFragment(WOLFSSL* ssl, byte* output, word16 output_size,
- word16 length, enum HandShakeType handshakeType, int hashOutput,
- int sendImmediately)
- {
- word16 recordHeaderLength;
- word16 recordLength;
- byte isProtected;
- int sendLength;
- byte* msg;
- int ret;
- if (output_size < length)
- return BUFFER_ERROR;
- isProtected = Dtls13TypeIsEncrypted(handshakeType);
- recordHeaderLength = Dtls13GetRlHeaderLength(ssl, isProtected);
- if (length <= recordHeaderLength)
- return BUFFER_ERROR;
- recordLength = length - recordHeaderLength;
- if (!isProtected) {
- ret = Dtls13RlAddPlaintextHeader(ssl, output, handshake, recordLength);
- if (ret != 0)
- return ret;
- }
- else {
- msg = output + recordHeaderLength;
- if (length <= recordHeaderLength)
- return BUFFER_ERROR;
- if (hashOutput) {
- ret = Dtls13HashHandshake(ssl, msg, recordLength);
- if (ret != 0)
- return ret;
- }
- sendLength = BuildTls13Message(ssl, output, output_size, msg,
- recordLength, handshake, 0, 0, 0);
- if (sendLength < 0)
- return sendLength;
- length = (word16)sendLength;
- }
- if (!FragIsInOutputBuffer(ssl, output))
- return Dtls13SendFragFromBuffer(ssl, output, length);
- ssl->buffers.outputBuffer.length += length;
- ret = 0;
- if (sendImmediately)
- ret = SendBuffered(ssl);
- return ret;
- }
- static void Dtls13FreeFragmentsBuffer(WOLFSSL* ssl)
- {
- XFREE(ssl->dtls13FragmentsBuffer.buffer, ssl->heap,
- DYNAMIC_TYPE_TMP_BUFFER);
- ssl->dtls13FragmentsBuffer.buffer = NULL;
- ssl->dtls13SendingFragments = 0;
- ssl->dtls13MessageLength = ssl->dtls13FragOffset = 0;
- }
- static WC_INLINE void Dtls13FreeRtxBufferRecord(WOLFSSL* ssl,
- Dtls13RtxRecord* r)
- {
- (void)ssl;
- XFREE(r->data, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- XFREE(r, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- }
- static Dtls13RtxRecord* Dtls13RtxNewRecord(WOLFSSL* ssl, byte* data,
- word16 length, enum HandShakeType handshakeType, w64wrapper seq)
- {
- w64wrapper epochNumber;
- Dtls13RtxRecord* r;
- WOLFSSL_ENTER("Dtls13RtxNewRecord");
- if (ssl->dtls13EncryptEpoch == NULL)
- return NULL;
- epochNumber = ssl->dtls13EncryptEpoch->epochNumber;
- r = (Dtls13RtxRecord*)XMALLOC(sizeof(*r), ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- if (r == NULL)
- return NULL;
- r->data = (byte*)XMALLOC(length, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- if (r->data == NULL) {
- XFREE(r, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- return NULL;
- }
- XMEMCPY(r->data, data, length);
- r->epoch = epochNumber;
- r->length = length;
- r->next = NULL;
- r->handshakeType = handshakeType;
- r->seq[0] = seq;
- r->rnIdx = 1;
- return r;
- }
- static void Dtls13RtxAddRecord(Dtls13Rtx* fsm, Dtls13RtxRecord* r)
- {
- WOLFSSL_ENTER("Dtls13RtxAddRecord");
- *fsm->rtxRecordTailPtr = r;
- fsm->rtxRecordTailPtr = &r->next;
- r->next = NULL;
- }
- static void Dtls13RtxRecordUnlink(WOLFSSL* ssl, Dtls13RtxRecord** prevNext,
- Dtls13RtxRecord* r)
- {
- /* if r was at the tail of the list, update the tail pointer */
- if (r->next == NULL)
- ssl->dtls13Rtx.rtxRecordTailPtr = prevNext;
- /* unlink */
- *prevNext = r->next;
- }
- void Dtls13RtxFlushBuffered(WOLFSSL* ssl, byte keepNewSessionTicket)
- {
- Dtls13RtxRecord *r, **prevNext;
- WOLFSSL_ENTER("Dtls13RtxFlushBuffered");
- prevNext = &ssl->dtls13Rtx.rtxRecords;
- r = ssl->dtls13Rtx.rtxRecords;
- /* we process the head at the end */
- while (r != NULL) {
- if (keepNewSessionTicket && r->handshakeType == session_ticket) {
- prevNext = &r->next;
- r = r->next;
- continue;
- }
- *prevNext = r->next;
- Dtls13FreeRtxBufferRecord(ssl, r);
- r = *prevNext;
- }
- ssl->dtls13Rtx.rtxRecordTailPtr = prevNext;
- }
- static Dtls13RecordNumber* Dtls13NewRecordNumber(w64wrapper epoch,
- w64wrapper seq, void* heap)
- {
- Dtls13RecordNumber* rn;
- (void)heap;
- rn = (Dtls13RecordNumber*)XMALLOC(sizeof(*rn), heap,
- DYNAMIC_TYPE_DTLS_MSG);
- if (rn == NULL)
- return NULL;
- rn->next = NULL;
- rn->epoch = epoch;
- rn->seq = seq;
- return rn;
- }
- static int Dtls13RtxAddAck(WOLFSSL* ssl, w64wrapper epoch, w64wrapper seq)
- {
- Dtls13RecordNumber* rn;
- WOLFSSL_ENTER("Dtls13RtxAddAck");
- rn = Dtls13NewRecordNumber(epoch, seq, ssl->heap);
- if (rn == NULL)
- return MEMORY_E;
- rn->next = ssl->dtls13Rtx.seenRecords;
- ssl->dtls13Rtx.seenRecords = rn;
- return 0;
- }
- static void Dtls13RtxFlushAcks(WOLFSSL* ssl)
- {
- Dtls13RecordNumber *list, *rn;
- (void)ssl;
- WOLFSSL_ENTER("Dtls13RtxFlushAcks");
- list = ssl->dtls13Rtx.seenRecords;
- while (list != NULL) {
- rn = list;
- list = rn->next;
- XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- }
- ssl->dtls13Rtx.seenRecords = NULL;
- }
- static int Dtls13DetectDisruption(WOLFSSL* ssl, word32 fragOffset)
- {
- /* retransmission. The other peer may have lost our flight or our ACKs. We
- don't account this as a disruption */
- if (ssl->keys.dtls_peer_handshake_number <
- ssl->keys.dtls_expected_peer_handshake_number)
- return 0;
- /* out of order message */
- if (ssl->keys.dtls_peer_handshake_number >
- ssl->keys.dtls_expected_peer_handshake_number) {
- return 1;
- }
- /* first fragment of in-order message */
- if (fragOffset == 0)
- return 0;
- /* is not the next fragment in the message (the check is not 100% perfect,
- in the worst case, we don't detect the disruption and wait for the other
- peer retransmission) */
- if (ssl->dtls_rx_msg_list != NULL) {
- DtlsFragBucket* last = ssl->dtls_rx_msg_list->fragBucketList;
- while (last != NULL && last->m.m.next != NULL)
- last = last->m.m.next;
- /* Does this fragment start right after the last fragment we
- * have stored? */
- if (last != NULL && (last->m.m.offset + last->m.m.sz) != fragOffset)
- return 1;
- }
- else {
- /* ssl->dtls_rx_msg_list is NULL and fragOffset != 0 so this is not in
- * order */
- return 1;
- }
- return 0;
- }
- static void Dtls13RtxRemoveCurAck(WOLFSSL* ssl)
- {
- Dtls13RecordNumber *rn, **prevNext;
- prevNext = &ssl->dtls13Rtx.seenRecords;
- rn = ssl->dtls13Rtx.seenRecords;
- while (rn != NULL) {
- if (w64Equal(rn->epoch, ssl->keys.curEpoch64) &&
- w64Equal(rn->seq, ssl->keys.curSeq)) {
- *prevNext = rn->next;
- XFREE(rn, ssl->heap, DYNAMIC_TYPE_DTLS_MSG);
- return;
- }
- prevNext = &rn->next;
- rn = rn->next;
- }
- }
- static void Dtls13MaybeSaveClientHello(WOLFSSL* ssl)
- {
- Dtls13RtxRecord *r, **prev_next;
- r = ssl->dtls13Rtx.rtxRecords;
- prev_next = &ssl->dtls13Rtx.rtxRecords;
- if (ssl->options.side == WOLFSSL_CLIENT_END &&
- ssl->options.connectState >= CLIENT_HELLO_SENT &&
- ssl->options.connectState <= HELLO_AGAIN_REPLY &&
- ssl->options.downgrade && ssl->options.minDowngrade >= DTLSv1_2_MINOR) {
- while (r != NULL) {
- if (r->handshakeType == client_hello) {
- Dtls13RtxRecordUnlink(ssl, prev_next, r);
- if (ssl->dtls13ClientHello != NULL)
- XFREE(ssl->dtls13ClientHello, ssl->heap,
- DYNAMIC_TYPE_DTLS_MSG);
- ssl->dtls13ClientHello = r->data;
- ssl->dtls13ClientHelloSz = r->length;
- r->data = NULL;
- Dtls13FreeRtxBufferRecord(ssl, r);
- return;
- }
- prev_next = &r->next;
- r = r->next;
- }
- }
- }
- static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
- word32 fragOffset)
- {
- WOLFSSL_ENTER("Dtls13RtxMsgRecvd");
- if (!ssl->options.handShakeDone &&
- ssl->keys.dtls_peer_handshake_number >=
- ssl->keys.dtls_expected_peer_handshake_number) {
- if (hs == server_hello)
- Dtls13MaybeSaveClientHello(ssl);
- /* In the handshake, receiving part of the next flight, acknowledge the
- * sent flight. */
- /* On the server side, receiving the last client flight does not ACK any
- * sent new_session_ticket messages. */
- /* We don't want to clear the buffer until we have done version
- * negotiation in the SH or have received a unified header in the
- * DTLS record. */
- if (ssl->options.serverState >= SERVER_HELLO_COMPLETE ||
- ssl->options.seenUnifiedHdr)
- /* Use 1.2 API to clear 1.2 buffers too */
- DtlsMsgPoolReset(ssl);
- }
- if (ssl->keys.dtls_peer_handshake_number <
- ssl->keys.dtls_expected_peer_handshake_number) {
- /* retransmission detected. */
- ssl->dtls13Rtx.retransmit = 1;
- /* the other peer may have retransmitted because an ACK for a flight
- that needs explicit ACK was lost.*/
- if (ssl->dtls13Rtx.seenRecords != NULL)
- ssl->dtls13Rtx.sendAcks = (byte)ssl->options.dtls13SendMoreAcks;
- }
- if (ssl->keys.dtls_peer_handshake_number ==
- ssl->keys.dtls_expected_peer_handshake_number &&
- ssl->options.handShakeDone && hs == certificate_request) {
- /* the current record, containing a post-handshake certificate request,
- is implicitly acknowledged by the
- certificate/certificate_verify/finished flight we are about to
- send. Please note that if the certificate request came out-of-order
- and we didn't send an ACK (sendMoreAcks == 0 and the missing
- packet(s) arrive before that fast timeout expired), then we will send
- both the ACK and the flight. While unnecessary this it's harmless, it
- should be rare and simplifies the code. Otherwise, it would be
- necessary to track which record number contained a CertificateRequest
- with a particular context id */
- Dtls13RtxRemoveCurAck(ssl);
- }
- if (ssl->options.dtls13SendMoreAcks &&
- Dtls13DetectDisruption(ssl, fragOffset)) {
- WOLFSSL_MSG("Disruption detected");
- ssl->dtls13Rtx.sendAcks = 1;
- }
- return 0;
- }
- void Dtls13FreeFsmResources(WOLFSSL* ssl)
- {
- Dtls13RtxFlushAcks(ssl);
- /* Use 1.2 API to clear 1.2 buffers too */
- DtlsMsgPoolReset(ssl);
- Dtls13RtxFlushBuffered(ssl, 0);
- }
- static int Dtls13SendOneFragmentRtx(WOLFSSL* ssl,
- enum HandShakeType handshakeType, word16 outputSize, byte* message,
- word32 length, int hashOutput)
- {
- Dtls13RtxRecord* rtxRecord = NULL;
- word16 recordHeaderLength;
- byte isProtected;
- int ret;
- isProtected = Dtls13TypeIsEncrypted(handshakeType);
- recordHeaderLength = Dtls13GetRlHeaderLength(ssl, isProtected);
- if (handshakeType != hello_retry_request) {
- rtxRecord = Dtls13RtxNewRecord(ssl, message + recordHeaderLength,
- (word16)(length - recordHeaderLength), handshakeType,
- ssl->dtls13EncryptEpoch->nextSeqNumber);
- if (rtxRecord == NULL)
- return MEMORY_E;
- }
- ret = Dtls13SendFragment(ssl, message, outputSize, (word16)length,
- handshakeType, hashOutput, Dtls13SendNow(ssl, handshakeType));
- if (rtxRecord != NULL) {
- if (ret == 0 || ret == WANT_WRITE)
- Dtls13RtxAddRecord(&ssl->dtls13Rtx, rtxRecord);
- else
- Dtls13FreeRtxBufferRecord(ssl, rtxRecord);
- }
- return ret;
- }
- static int Dtls13SendFragmentedInternal(WOLFSSL* ssl)
- {
- int fragLength, rlHeaderLength;
- int remainingSize, maxFragment;
- int recordLength;
- byte isEncrypted;
- byte* output;
- int ret;
- isEncrypted = Dtls13TypeIsEncrypted(
- (enum HandShakeType)ssl->dtls13FragHandshakeType);
- rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
- maxFragment = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
- remainingSize = ssl->dtls13MessageLength - ssl->dtls13FragOffset;
- while (remainingSize > 0) {
- fragLength = maxFragment - rlHeaderLength - DTLS_HANDSHAKE_HEADER_SZ;
- recordLength = maxFragment;
- if (fragLength > remainingSize) {
- fragLength = remainingSize;
- recordLength =
- fragLength + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ;
- }
- ret = CheckAvailableSize(ssl, recordLength + MAX_MSG_EXTRA);
- if (ret != 0) {
- Dtls13FreeFragmentsBuffer(ssl);
- return ret;
- }
- output = GetOutputBuffer(ssl);
- ret = Dtls13HandshakeAddHeaderFrag(ssl, output + rlHeaderLength,
- (enum HandShakeType)ssl->dtls13FragHandshakeType,
- ssl->dtls13FragOffset, fragLength, ssl->dtls13MessageLength);
- if (ret != 0) {
- Dtls13FreeFragmentsBuffer(ssl);
- return ret;
- }
- XMEMCPY(output + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ,
- ssl->dtls13FragmentsBuffer.buffer + ssl->dtls13FragOffset,
- fragLength);
- ret = Dtls13SendOneFragmentRtx(ssl,
- (enum HandShakeType)ssl->dtls13FragHandshakeType,
- (word16)recordLength + MAX_MSG_EXTRA, output, (word32)recordLength, 0);
- if (ret == WANT_WRITE) {
- ssl->dtls13FragOffset += fragLength;
- return ret;
- }
- if (ret != 0) {
- Dtls13FreeFragmentsBuffer(ssl);
- return ret;
- }
- ssl->dtls13FragOffset += fragLength;
- remainingSize -= fragLength;
- }
- /* we sent all fragments */
- Dtls13FreeFragmentsBuffer(ssl);
- return 0;
- }
- static int Dtls13SendFragmented(WOLFSSL* ssl, byte* message, word16 length,
- enum HandShakeType handshake_type, int hash_output)
- {
- int rlHeaderLength;
- byte isEncrypted;
- int messageSize;
- int ret;
- if (ssl->dtls13SendingFragments != 0) {
- WOLFSSL_MSG(
- "dtls13_send_fragmented() invoked while already sending fragments");
- return BAD_STATE_E;
- }
- isEncrypted = Dtls13TypeIsEncrypted(handshake_type);
- rlHeaderLength = Dtls13GetRlHeaderLength(ssl, isEncrypted);
- if (length < rlHeaderLength)
- return INCOMPLETE_DATA;
- /* DTLSv1.3 do not consider fragmentation for hash transcript. Build the
- hash now pretending fragmentation will not happen */
- if (hash_output) {
- ret = Dtls13HashHandshake(ssl, message + rlHeaderLength,
- length - (word16)rlHeaderLength);
- if (ret != 0)
- return ret;
- }
- messageSize = length - rlHeaderLength - DTLS_HANDSHAKE_HEADER_SZ;
- ssl->dtls13FragmentsBuffer.buffer =
- (byte*)XMALLOC(messageSize, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
- if (ssl->dtls13FragmentsBuffer.buffer == NULL)
- return MEMORY_E;
- XMEMCPY(ssl->dtls13FragmentsBuffer.buffer,
- message + rlHeaderLength + DTLS_HANDSHAKE_HEADER_SZ, messageSize);
- ssl->dtls13MessageLength = messageSize;
- ssl->dtls13FragHandshakeType = handshake_type;
- ssl->dtls13SendingFragments = 1;
- return Dtls13SendFragmentedInternal(ssl);
- }
- static WC_INLINE word8 Dtls13GetEpochBits(w64wrapper epoch)
- {
- return w64GetLow32(epoch) & EE_MASK;
- }
- #ifdef WOLFSSL_DTLS_CID
- static byte Dtls13GetCidTxSize(WOLFSSL* ssl)
- {
- unsigned int cidSz;
- int ret;
- ret = wolfSSL_dtls_cid_get_tx_size(ssl, &cidSz);
- if (ret != WOLFSSL_SUCCESS)
- return 0;
- return (byte)cidSz;
- }
- static byte Dtls13GetCidRxSize(WOLFSSL* ssl)
- {
- unsigned int cidSz;
- int ret;
- ret = wolfSSL_dtls_cid_get_rx_size(ssl, &cidSz);
- if (ret != WOLFSSL_SUCCESS)
- return 0;
- return (byte)cidSz;
- }
- static int Dtls13AddCID(WOLFSSL* ssl, byte* flags, byte* out, word16* idx)
- {
- byte cidSize;
- int ret;
- if (!wolfSSL_dtls_cid_is_enabled(ssl))
- return 0;
- cidSize = Dtls13GetCidTxSize(ssl);
- /* no cid */
- if (cidSize == 0)
- return 0;
- *flags |= DTLS13_CID_BIT;
- /* we know that we have at least cidSize of space */
- ret = wolfSSL_dtls_cid_get_tx(ssl, out + *idx, cidSize);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- *idx += cidSize;
- return 0;
- }
- static int Dtls13UnifiedHeaderParseCID(WOLFSSL* ssl, byte flags,
- const byte* input, word16 inputSize, word16* idx)
- {
- unsigned int _cidSz;
- int ret;
- if (flags & DTLS13_CID_BIT) {
- if (!wolfSSL_dtls_cid_is_enabled(ssl)) {
- WOLFSSL_MSG("CID while no negotiated CID, ignoring");
- return DTLS_CID_ERROR;
- }
- if (!DtlsCIDCheck(ssl, input + *idx, inputSize - *idx)) {
- WOLFSSL_MSG("Not matching or wrong CID, ignoring");
- return DTLS_CID_ERROR;
- }
- ret = wolfSSL_dtls_cid_get_rx_size(ssl, &_cidSz);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- *idx += (word16)_cidSz;
- return 0;
- }
- /* CID not present */
- if (wolfSSL_dtls_cid_is_enabled(ssl)) {
- ret = wolfSSL_dtls_cid_get_rx_size(ssl, &_cidSz);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- if (_cidSz != 0) {
- WOLFSSL_MSG("expecting CID, ignoring");
- return DTLS_CID_ERROR;
- }
- }
- return 0;
- }
- #else
- #define Dtls13AddCID(a, b, c, d) 0
- #define Dtls13GetCidRxSize(a) 0
- #define Dtls13GetCidTxSize(a) 0
- #define Dtls13UnifiedHeaderParseCID(a, b, c, d, e) 0
- #endif /* WOLFSSL_DTLS_CID */
- /**
- * dtls13RlAddCiphertextHeader() - add record layer header in the buffer
- * @ssl: ssl object
- * @out: output buffer where to put the header
- * @length: length of the record
- */
- int Dtls13RlAddCiphertextHeader(WOLFSSL* ssl, byte* out, word16 length)
- {
- word16 seqNumber, idx;
- byte* flags;
- int ret;
- if (out == NULL)
- return BAD_FUNC_ARG;
- if (ssl->dtls13EncryptEpoch == NULL)
- return BAD_STATE_E;
- flags = out;
- /* header fixed bits */
- *flags = DTLS13_FIXED_BITS;
- /* epoch bits */
- *flags |= Dtls13GetEpochBits(ssl->dtls13EncryptEpoch->epochNumber);
- idx = DTLS13_HDR_FLAGS_SIZE;
- ret = Dtls13AddCID(ssl, flags, out, &idx);
- if (ret != 0)
- return ret;
- /* include 16-bit seq */
- *flags |= DTLS13_SEQ_LEN_BIT;
- /* include 16-bit length */
- *flags |= DTLS13_LEN_BIT;
- seqNumber = (word16)w64GetLow32(ssl->dtls13EncryptEpoch->nextSeqNumber);
- c16toa(seqNumber, out + idx);
- idx += OPAQUE16_LEN;
- c16toa(length, out + idx);
- return 0;
- }
- /**
- * Dtls13HandshakeAddHeader() - add handshake layer header
- * @ssl: ssl object
- * @output: output buffer
- * @msg_type: handshake type
- * @length: length of the message
- */
- int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output,
- enum HandShakeType msg_type, word32 length)
- {
- Dtls13HandshakeHeader* hdr;
- hdr = (Dtls13HandshakeHeader*)output;
- hdr->msg_type = msg_type;
- c32to24((word32)length, hdr->length);
- c16toa(ssl->keys.dtls_handshake_number, hdr->messageSeq);
- /* send unfragmented first */
- c32to24(0, hdr->fragmentOffset);
- c32to24((word32)length, hdr->fragmentLength);
- return 0;
- }
- /**
- * Dtls13EncryptRecordNumber() - encrypt record number in the header
- * @ssl: ssl object
- * @hdr: header
- *
- * Further info rfc draft 43 sec 4.2.3
- */
- int Dtls13EncryptRecordNumber(WOLFSSL* ssl, byte* hdr, word16 recordLength)
- {
- int seqLength;
- int hdrLength;
- int cidSz;
- if (ssl == NULL || hdr == NULL)
- return BAD_FUNC_ARG;
- /* we need at least a 16 bytes of ciphertext to encrypt record number see
- 4.2.3*/
- if (recordLength < Dtls13GetRlHeaderLength(ssl, 1) + DTLS13_MIN_CIPHERTEXT)
- return BUFFER_ERROR;
- seqLength = (*hdr & DTLS13_LEN_BIT) ? DTLS13_SEQ_16_LEN : DTLS13_SEQ_8_LEN;
- cidSz = Dtls13GetCidTxSize(ssl);
- /* header flags + seq number + CID size*/
- hdrLength = OPAQUE8_LEN + seqLength + cidSz;
- /* length present */
- if (*hdr & DTLS13_LEN_BIT)
- hdrLength += DTLS13_LEN_SIZE;
- return Dtls13EncryptDecryptRecordNumber(ssl,
- /* seq number offset */
- hdr + OPAQUE8_LEN + cidSz,
- /* seq size */
- seqLength,
- /* cipher text */
- hdr + hdrLength, PROTECT);
- }
- /**
- * Dtls13GetRlHeaderLength() - get record layer header length
- * @ssl: ssl object
- * @isEncrypted: whether the record will be protected or not
- *
- * returns the length of the record layer header in bytes.
- */
- word16 Dtls13GetRlHeaderLength(WOLFSSL* ssl, byte isEncrypted)
- {
- (void)ssl;
- if (!isEncrypted)
- return DTLS_RECORD_HEADER_SZ;
- return DTLS13_UNIFIED_HEADER_SIZE + Dtls13GetCidTxSize(ssl);
- }
- /**
- * Dtls13GetHeadersLength() - return length of record + handshake header
- * @ssl: ssl object
- * @type: type of handshake in the message
- */
- word16 Dtls13GetHeadersLength(WOLFSSL* ssl, enum HandShakeType type)
- {
- byte isEncrypted;
- isEncrypted = Dtls13TypeIsEncrypted(type);
- return Dtls13GetRlHeaderLength(ssl, isEncrypted) + DTLS_HANDSHAKE_HEADER_SZ;
- }
- /**
- * Dtls13IsUnifiedHeader() - check if header is a DTLS unified header
- * @header_flags: first byte of the header
- *
- * Further info: dtls v1.3 draft43 section 4
- */
- int Dtls13IsUnifiedHeader(byte hdrFirstByte)
- {
- if (hdrFirstByte == alert || hdrFirstByte == handshake ||
- hdrFirstByte == ack)
- return 0;
- return ((hdrFirstByte & DTLS13_FIXED_BITS_MASK) == DTLS13_FIXED_BITS);
- }
- int Dtls13ReconstructSeqNumber(WOLFSSL* ssl, Dtls13UnifiedHdrInfo* hdrInfo,
- w64wrapper* out)
- {
- word16 expectedLowBits;
- word16 seqLowBits;
- w64wrapper temp;
- word32 out32;
- word32 shift;
- word16 mask;
- byte wrap = 0;
- if (hdrInfo->seqHiPresent) {
- seqLowBits = (hdrInfo->seqHi << 8) | hdrInfo->seqLo;
- mask = 0xffff;
- shift = (1 << 16);
- }
- else {
- seqLowBits = hdrInfo->seqLo;
- mask = 0xff;
- shift = (1 << 8);
- }
- /* *out = (nextPeerSeqNumber & ~mask) | seqLowbits */
- out32 = w64GetLow32(ssl->dtls13DecryptEpoch->nextPeerSeqNumber);
- expectedLowBits = out32 & mask;
- out32 = (out32 & ~mask) | seqLowBits;
- *out = ssl->dtls13DecryptEpoch->nextPeerSeqNumber;
- w64SetLow32(out, out32);
- if (seqLowBits >= expectedLowBits) {
- if ((word32)(seqLowBits - expectedLowBits) > shift / 2) {
- temp = w64Sub32(*out, shift, &wrap);
- if (!wrap)
- *out = temp;
- return 0;
- }
- }
- else {
- /* seqLowbits < expectedLowBits */
- if ((word32)(expectedLowBits - seqLowBits) > shift / 2) {
- temp = w64Add32(*out, shift, &wrap);
- if (!wrap)
- *out = temp;
- return 0;
- }
- }
- return 0;
- }
- int Dtls13ReconstructEpochNumber(WOLFSSL* ssl, byte epochBits,
- w64wrapper* epoch)
- {
- w64wrapper _epoch;
- Dtls13Epoch* e;
- byte found = 0;
- int i;
- if (Dtls13GetEpochBits(ssl->dtls13PeerEpoch) == epochBits) {
- *epoch = ssl->dtls13PeerEpoch;
- return 0;
- }
- w64Zero(&_epoch);
- for (i = 0; i < DTLS13_EPOCH_SIZE; ++i) {
- e = &ssl->dtls13Epochs[i];
- if (!e->isValid)
- continue;
- if (Dtls13GetEpochBits(e->epochNumber) != epochBits)
- continue;
- if (w64GT(e->epochNumber, _epoch)) {
- found = 1;
- _epoch = e->epochNumber;
- }
- }
- if (found) {
- *epoch = _epoch;
- return 0;
- }
- return SEQUENCE_ERROR;
- }
- int Dtls13GetUnifiedHeaderSize(WOLFSSL* ssl, const byte input, word16* size)
- {
- (void)ssl;
- if (size == NULL)
- return BAD_FUNC_ARG;
- /* flags (1) + CID + seq 8bit (1) */
- *size = OPAQUE8_LEN + Dtls13GetCidRxSize(ssl) + OPAQUE8_LEN;
- if (input & DTLS13_SEQ_LEN_BIT)
- *size += OPAQUE8_LEN;
- if (input & DTLS13_LEN_BIT)
- *size += OPAQUE16_LEN;
- return 0;
- }
- /**
- * Dtls13ParseUnifiedRecordLayer() - parse DTLS unified header
- * @ssl: [in] ssl object
- * @input: [in] buffer where the header is
- * @inputSize: [in] size of the input buffer
- * @hdrInfo: [out] header info struct
- *
- * It parse the header and put the relevant information inside @hdrInfo. Further
- * info: draft43 section 4
- *
- * return 0 on success
- */
- int Dtls13ParseUnifiedRecordLayer(WOLFSSL* ssl, const byte* input,
- word16 inputSize, Dtls13UnifiedHdrInfo* hdrInfo)
- {
- byte seqLen, hasLength;
- byte* seqNum;
- byte flags;
- word16 idx;
- int ret;
- if (input == NULL || inputSize < DTLS13_HDR_FLAGS_SIZE)
- return BAD_FUNC_ARG;
- flags = *input;
- idx = DTLS13_HDR_FLAGS_SIZE;
- ret = Dtls13UnifiedHeaderParseCID(ssl, flags, input, inputSize, &idx);
- if (ret != 0)
- return ret;
- seqNum = (byte*)input + idx;
- seqLen = (flags & DTLS13_SEQ_LEN_BIT) != 0 ? DTLS13_SEQ_16_LEN
- : DTLS13_SEQ_8_LEN;
- hasLength = flags & DTLS13_LEN_BIT;
- hdrInfo->epochBits = flags & EE_MASK;
- idx += seqLen;
- if (inputSize < idx)
- return BUFFER_ERROR;
- if (hasLength) {
- if (inputSize < idx + DTLS13_LEN_SIZE)
- return BUFFER_ERROR;
- ato16(input + idx, &hdrInfo->recordLength);
- idx += DTLS13_LEN_SIZE;
- }
- else {
- /* length not present. The size of the record is the all the remaining
- data received with this datagram */
- hdrInfo->recordLength = inputSize - idx;
- }
- /* minimum size for a dtls1.3 packet is 16 bytes (to have enough ciphertext
- to create record number xor mask). (draft 43 - Sec 4.2.3) */
- if (hdrInfo->recordLength < DTLS13_RN_MASK_SIZE)
- return LENGTH_ERROR;
- if (inputSize < idx + DTLS13_RN_MASK_SIZE)
- return BUFFER_ERROR;
- ret = Dtls13EncryptDecryptRecordNumber(ssl, seqNum, seqLen, input + idx,
- DEPROTECT);
- if (ret != 0)
- return ret;
- if (seqLen == DTLS13_SEQ_16_LEN) {
- hdrInfo->seqHiPresent = 1;
- hdrInfo->seqHi = seqNum[0];
- hdrInfo->seqLo = seqNum[1];
- }
- else {
- hdrInfo->seqHiPresent = 0;
- hdrInfo->seqLo = seqNum[0];
- }
- return 0;
- }
- int Dtls13RecordRecvd(WOLFSSL* ssl)
- {
- int ret;
- if (ssl->curRL.type != handshake)
- return 0;
- if (!ssl->options.dtls13SendMoreAcks)
- ssl->dtls13FastTimeout = 1;
- ret = Dtls13RtxAddAck(ssl, ssl->keys.curEpoch64, ssl->keys.curSeq);
- if (ret != 0)
- WOLFSSL_MSG("can't save ack fragment");
- return ret;
- }
- static void Dtls13RtxMoveToEndOfList(WOLFSSL* ssl, Dtls13RtxRecord** prevNext,
- Dtls13RtxRecord* r)
- {
- /* already at the end */
- if (r->next == NULL)
- return;
- Dtls13RtxRecordUnlink(ssl, prevNext, r);
- /* add to the end */
- Dtls13RtxAddRecord(&ssl->dtls13Rtx, r);
- }
- static int Dtls13RtxSendBuffered(WOLFSSL* ssl)
- {
- word16 headerLength;
- Dtls13RtxRecord *r, **prevNext;
- w64wrapper seq;
- byte* output;
- int isLast;
- int sendSz;
- word32 now;
- int ret;
- WOLFSSL_ENTER("Dtls13RtxSendBuffered");
- now = LowResTimer();
- if (now - ssl->dtls13Rtx.lastRtx < DTLS13_MIN_RTX_INTERVAL) {
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Avoid too fast retransmission");
- #endif /* WOLFSSL_DEBUG_TLS */
- return 0;
- }
- ssl->dtls13Rtx.lastRtx = now;
- r = ssl->dtls13Rtx.rtxRecords;
- prevNext = &ssl->dtls13Rtx.rtxRecords;
- while (r != NULL) {
- isLast = r->next == NULL;
- WOLFSSL_MSG("Dtls13Rtx One Record");
- headerLength = Dtls13GetRlHeaderLength(ssl, !w64IsZero(r->epoch));
- sendSz = r->length + headerLength;
- if (!w64IsZero(r->epoch))
- sendSz += MAX_MSG_EXTRA;
- ret = CheckAvailableSize(ssl, sendSz);
- if (ret != 0)
- return ret;
- output = GetOutputBuffer(ssl);
- XMEMCPY(output + headerLength, r->data, r->length);
- if (!w64Equal(ssl->dtls13EncryptEpoch->epochNumber, r->epoch)) {
- ret = Dtls13SetEpochKeys(ssl, r->epoch, ENCRYPT_SIDE_ONLY);
- if (ret != 0)
- return ret;
- }
- seq = ssl->dtls13EncryptEpoch->nextSeqNumber;
- ret = Dtls13SendFragment(ssl, output, (word16)sendSz, r->length + headerLength,
- (enum HandShakeType)r->handshakeType, 0,
- isLast || !ssl->options.groupMessages);
- if (ret != 0 && ret != WANT_WRITE)
- return ret;
- if (r->rnIdx >= DTLS13_RETRANS_RN_SIZE)
- r->rnIdx = 0;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG_EX("tracking r hs: %d with seq: %ld", r->handshakeType,
- seq);
- #endif /* WOLFSSL_DEBUG_TLS */
- r->seq[r->rnIdx] = seq;
- r->rnIdx++;
- if (ret == WANT_WRITE) {
- /* this fragment will be sent eventually. Move it to the end of the
- list so next time we start with a new one. */
- Dtls13RtxMoveToEndOfList(ssl, prevNext, r);
- return ret;
- }
- prevNext = &r->next;
- r = r->next;
- }
- return 0;
- }
- static int Dtls13AcceptFragmented(WOLFSSL *ssl, enum HandShakeType type)
- {
- if (IsEncryptionOn(ssl, 0))
- return 1;
- if (ssl->options.side == WOLFSSL_CLIENT_END && type == server_hello)
- return 1;
- #ifdef WOLFSSL_DTLS_CH_FRAG
- if (ssl->options.side == WOLFSSL_SERVER_END && type == client_hello &&
- ssl->options.dtls13ChFrag && ssl->options.dtlsStateful)
- return 1;
- #endif
- return 0;
- }
- /**
- * Dtls13HandshakeRecv() - process an handshake message. Deal with
- fragmentation if needed
- * @ssl: [in] ssl object
- * @input: [in] input buffer
- * @size: [in] input buffer size
- * @type: [out] content type
- * @processedSize: [out] amount of byte processed
- *
- * returns 0 on success
- */
- static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
- word32* processedSize)
- {
- word32 fragOff, fragLength;
- byte isComplete, isFirst;
- byte usingAsyncCrypto;
- word32 messageLength;
- byte handshakeType;
- word32 idx;
- int ret;
- idx = 0;
- ret = GetDtlsHandShakeHeader(ssl, input, &idx, &handshakeType,
- &messageLength, &fragOff, &fragLength, size);
- if (ret != 0)
- return PARSE_ERROR;
- /* Need idx + fragLength as we don't advance the inputBuffer idx value */
- ret = EarlySanityCheckMsgReceived(ssl, handshakeType, idx + fragLength);
- if (ret != 0) {
- WOLFSSL_ERROR(ret);
- return ret;
- }
- if (ssl->options.side == WOLFSSL_SERVER_END &&
- ssl->options.acceptState < TLS13_ACCEPT_FIRST_REPLY_DONE) {
- if (handshakeType != client_hello) {
- WOLFSSL_MSG("Ignoring other messages before we verify a ClientHello");
- *processedSize = size;
- return 0;
- }
- /* To be able to operate in stateless mode, we assume the ClientHello
- * is in order and we use its Handshake Message number and Sequence
- * Number for our Tx. */
- ssl->keys.dtls_expected_peer_handshake_number =
- ssl->keys.dtls_handshake_number =
- ssl->keys.dtls_peer_handshake_number;
- ssl->dtls13Epochs[0].nextSeqNumber = ssl->keys.curSeq;
- }
- if (idx + fragLength > size) {
- WOLFSSL_ERROR(INCOMPLETE_DATA);
- return INCOMPLETE_DATA;
- }
- if (fragOff + fragLength > messageLength)
- return BUFFER_ERROR;
- ret = Dtls13RtxMsgRecvd(ssl, (enum HandShakeType)handshakeType, fragOff);
- if (ret != 0)
- return ret;
- if (ssl->keys.dtls_peer_handshake_number <
- ssl->keys.dtls_expected_peer_handshake_number) {
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG(
- "DTLS1.3 retransmission detected - discard and schedule a rtx");
- #endif /* WOLFSSL_DEBUG_TLS */
- /* ignore the message */
- *processedSize = idx + fragLength + ssl->keys.padSz;
- return 0;
- }
- isFirst = fragOff == 0;
- isComplete = isFirst && fragLength == messageLength;
- if (!isComplete && !Dtls13AcceptFragmented(ssl, handshakeType)) {
- #ifdef WOLFSSL_DTLS_CH_FRAG
- byte tls13 = 0;
- /* check if the first CH fragment contains a valid cookie */
- if (ssl->options.dtls13ChFrag && !ssl->options.dtlsStateful &&
- isFirst && handshakeType == client_hello &&
- DoClientHelloStateless(ssl, input + idx, fragLength, 1, &tls13)
- == 0 && tls13) {
- /* We can save this message and continue as stateful. */
- if (ssl->chGoodCb != NULL) {
- int cbret = ssl->chGoodCb(ssl, ssl->chGoodCtx);
- if (cbret < 0) {
- ssl->error = cbret;
- WOLFSSL_MSG("ClientHello Good Cb don't continue error");
- return WOLFSSL_FATAL_ERROR;
- }
- }
- WOLFSSL_MSG("ClientHello fragment verified");
- }
- else
- #endif
- {
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("DTLS1.3 not accepting fragmented plaintext message");
- #endif /* WOLFSSL_DEBUG_TLS */
- /* ignore the message */
- *processedSize = idx + fragLength + ssl->keys.padSz;
- return 0;
- }
- }
- usingAsyncCrypto = ssl->devId != INVALID_DEVID;
- /* store the message if any of the following: (a) incomplete message, (b)
- * out of order message or (c) if using async crypto. In (c) the processing
- * of the message can return WC_PENDING_E, it's easier to handle this error
- * if the message is stored in the buffer.
- */
- if (!isComplete ||
- ssl->keys.dtls_peer_handshake_number >
- ssl->keys.dtls_expected_peer_handshake_number ||
- usingAsyncCrypto) {
- if (ssl->dtls_rx_msg_list_sz < DTLS_POOL_SZ) {
- DtlsMsgStore(ssl, (word16)w64GetLow32(ssl->keys.curEpoch64),
- ssl->keys.dtls_peer_handshake_number,
- input + DTLS_HANDSHAKE_HEADER_SZ, messageLength, handshakeType,
- fragOff, fragLength, ssl->heap);
- }
- else {
- /* DTLS_POOL_SZ outstanding messages is way more than enough for any
- * valid peer */
- return DTLS_TOO_MANY_FRAGMENTS_E;
- }
- *processedSize = idx + fragLength + ssl->keys.padSz;
- if (Dtls13NextMessageComplete(ssl))
- return Dtls13ProcessBufferedMessages(ssl);
- return 0;
- }
- ret = DoTls13HandShakeMsgType(ssl, input, &idx, handshakeType,
- messageLength, size);
- if (ret != 0)
- return ret;
- Dtls13MsgWasProcessed(ssl, (enum HandShakeType)handshakeType);
- *processedSize = idx;
- /* check if we have buffered some message */
- if (Dtls13NextMessageComplete(ssl))
- return Dtls13ProcessBufferedMessages(ssl);
- return 0;
- }
- int Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32* inOutIdx,
- word32 totalSz)
- {
- word32 maxSize, processedSize = 0;
- byte* message;
- int ret;
- message = input + *inOutIdx;
- maxSize = totalSz - *inOutIdx;
- ret = _Dtls13HandshakeRecv(ssl, message, maxSize, &processedSize);
- *inOutIdx += processedSize;
- return ret;
- }
- /**
- * Dtls13FragmentsContinue() - keep sending pending fragments
- * @ssl: ssl object
- */
- int Dtls13FragmentsContinue(WOLFSSL* ssl)
- {
- int ret;
- ret = Dtls13SendFragmentedInternal(ssl);
- if (ret == 0)
- ssl->keys.dtls_handshake_number++;
- return ret;
- }
- /**
- * Dtls13AddHeaders() - setup handshake header
- * @output: output buffer at the start of the record
- * @length: length of the full message, included headers
- * @hsType: handshake type
- * @ssl: ssl object
- *
- * This function add the handshake headers and leaves space for the record
- * layer. The real record layer will be added in dtls_send() for unprotected
- * messages and in BuildTls13message() for protected messages.
- *
- * returns 0 on success, -1 otherwise
- */
- int Dtls13AddHeaders(byte* output, word32 length, enum HandShakeType hsType,
- WOLFSSL* ssl)
- {
- word16 handshakeOffset;
- byte isEncrypted;
- isEncrypted = Dtls13TypeIsEncrypted(hsType);
- handshakeOffset = Dtls13GetRlHeaderLength(ssl, isEncrypted);
- /* The record header is placed by either Dtls13HandshakeSend() or
- BuildTls13Message() */
- return Dtls13HandshakeAddHeader(ssl, output + handshakeOffset, hsType,
- length);
- }
- /**
- * Dtls13HandshakeSend() - send an handshake message. Fragment if necessary.
- *
- * @ssl: ssl object
- * @message: message where the buffer is in. Handshake header already in place.
- * @output_size: size of the @message buffer
- * @length: length of the message including headers
- * @handshakeType: handshake type of the message
- * @hashOutput: if true add the message to the transcript hash
- *
- */
- int Dtls13HandshakeSend(WOLFSSL* ssl, byte* message, word16 outputSize,
- word16 length, enum HandShakeType handshakeType, int hashOutput)
- {
- int maxFrag;
- int maxLen;
- int ret;
- if (ssl->dtls13EncryptEpoch == NULL)
- return BAD_STATE_E;
- /* if we are here, the message is built */
- ssl->options.buildingMsg = 0;
- if (!ssl->options.handShakeDone) {
- /* during the handshake, if we are sending a new flight, we can flush
- our ACK list. When sending client
- [certificate/certificate_verify]/finished flight, we may flush an ACK
- for a newSessionticket message, sent by the server just after sending
- its finished message. This should not be a problem. That message
- arrived out-of-order (before the server finished) so likely an ACK
- was already sent. In the worst case we will ACK the server
- retranmission*/
- if (handshakeType == certificate || handshakeType == finished ||
- handshakeType == server_hello || handshakeType == client_hello)
- Dtls13RtxFlushAcks(ssl);
- }
- /* we want to send always with the highest epoch */
- if (!w64Equal(ssl->dtls13EncryptEpoch->epochNumber, ssl->dtls13Epoch)) {
- ret = Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
- if (ret != 0)
- return ret;
- }
- maxFrag = wolfSSL_GetMaxFragSize(ssl, MAX_RECORD_SIZE);
- maxLen = length;
- if (handshakeType == key_update)
- ssl->dtls13WaitKeyUpdateAck = 1;
- if (maxLen < maxFrag) {
- ret = Dtls13SendOneFragmentRtx(ssl, handshakeType, outputSize, message,
- length, hashOutput);
- if (ret == 0 || ret == WANT_WRITE)
- ssl->keys.dtls_handshake_number++;
- }
- else {
- ret = Dtls13SendFragmented(ssl, message, length, handshakeType,
- hashOutput);
- if (ret == 0)
- ssl->keys.dtls_handshake_number++;
- }
- return ret;
- }
- #define SN_LABEL_SZ 2
- static const byte snLabel[SN_LABEL_SZ + 1] = "sn";
- /**
- * Dtls13DeriveSnKeys() - derive the key used to encrypt the record number
- * @ssl: ssl object
- * @provision: which side (CLIENT or SERVER) to provision
- */
- int Dtls13DeriveSnKeys(WOLFSSL* ssl, int provision)
- {
- byte key_dig[MAX_PRF_DIG];
- int ret = 0;
- if (provision & PROVISION_CLIENT) {
- WOLFSSL_MSG("Derive SN Client key");
- ret = Tls13DeriveKey(ssl, key_dig, ssl->specs.key_size,
- ssl->clientSecret, snLabel, SN_LABEL_SZ, ssl->specs.mac_algorithm,
- 0, WOLFSSL_CLIENT_END);
- if (ret != 0)
- goto end;
- XMEMCPY(ssl->keys.client_sn_key, key_dig, ssl->specs.key_size);
- }
- if (provision & PROVISION_SERVER) {
- WOLFSSL_MSG("Derive SN Server key");
- ret = Tls13DeriveKey(ssl, key_dig, ssl->specs.key_size,
- ssl->serverSecret, snLabel, SN_LABEL_SZ, ssl->specs.mac_algorithm,
- 0, WOLFSSL_SERVER_END);
- if (ret != 0)
- goto end;
- XMEMCPY(ssl->keys.server_sn_key, key_dig, ssl->specs.key_size);
- }
- end:
- ForceZero(key_dig, MAX_PRF_DIG);
- return ret;
- }
- static int Dtls13InitAesCipher(WOLFSSL* ssl, RecordNumberCiphers* cipher,
- const byte* key, word16 keySize)
- {
- int ret;
- if (cipher->aes == NULL) {
- cipher->aes =
- (Aes*)XMALLOC(sizeof(Aes), ssl->heap, DYNAMIC_TYPE_CIPHER);
- if (cipher->aes == NULL)
- return MEMORY_E;
- }
- else {
- wc_AesFree(cipher->aes);
- }
- XMEMSET(cipher->aes, 0, sizeof(*cipher->aes));
- ret = wc_AesInit(cipher->aes, ssl->heap, INVALID_DEVID);
- if (ret != 0)
- return ret;
- return wc_AesSetKey(cipher->aes, key, keySize, NULL, AES_ENCRYPTION);
- }
- #ifdef HAVE_CHACHA
- static int Dtls13InitChaChaCipher(RecordNumberCiphers* c, byte* key,
- word16 keySize, void* heap)
- {
- (void)heap;
- if (c->chacha == NULL) {
- c->chacha = (ChaCha*)XMALLOC(sizeof(ChaCha), heap, DYNAMIC_TYPE_CIPHER);
- if (c->chacha == NULL)
- return MEMORY_E;
- }
- return wc_Chacha_SetKey(c->chacha, key, keySize);
- }
- #endif /* HAVE_CHACHA */
- struct Dtls13Epoch* Dtls13GetEpoch(WOLFSSL* ssl, w64wrapper epochNumber)
- {
- Dtls13Epoch* e;
- int i;
- for (i = 0; i < DTLS13_EPOCH_SIZE; ++i) {
- e = &ssl->dtls13Epochs[i];
- if (w64Equal(e->epochNumber, epochNumber) && e->isValid)
- return e;
- }
- return NULL;
- }
- void Dtls13SetOlderEpochSide(WOLFSSL* ssl, w64wrapper epochNumber,
- int side)
- {
- Dtls13Epoch* e;
- int i;
- for (i = 0; i < DTLS13_EPOCH_SIZE; ++i) {
- e = &ssl->dtls13Epochs[i];
- if (e->isValid && w64LT(e->epochNumber, epochNumber)) {
- e->side = (byte)side;
- }
- }
- }
- static void Dtls13EpochCopyKeys(WOLFSSL* ssl, Dtls13Epoch* e, Keys* k, int side)
- {
- byte clientWrite, serverWrite;
- byte enc, dec;
- WOLFSSL_ENTER("Dtls13SetEpochKeys");
- clientWrite = serverWrite = 0;
- enc = dec = 0;
- switch (side) {
- case ENCRYPT_SIDE_ONLY:
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- clientWrite = 1;
- if (ssl->options.side == WOLFSSL_SERVER_END)
- serverWrite = 1;
- enc = 1;
- break;
- case DECRYPT_SIDE_ONLY:
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- serverWrite = 1;
- if (ssl->options.side == WOLFSSL_SERVER_END)
- clientWrite = 1;
- dec = 1;
- break;
- case ENCRYPT_AND_DECRYPT_SIDE:
- clientWrite = serverWrite = 1;
- enc = dec = 1;
- break;
- }
- if (clientWrite) {
- XMEMCPY(e->client_write_key, k->client_write_key,
- sizeof(e->client_write_key));
- XMEMCPY(e->client_write_IV, k->client_write_IV,
- sizeof(e->client_write_IV));
- XMEMCPY(e->client_sn_key, k->client_sn_key, sizeof(e->client_sn_key));
- }
- if (serverWrite) {
- XMEMCPY(e->server_write_key, k->server_write_key,
- sizeof(e->server_write_key));
- XMEMCPY(e->server_write_IV, k->server_write_IV,
- sizeof(e->server_write_IV));
- XMEMCPY(e->server_sn_key, k->server_sn_key, sizeof(e->server_sn_key));
- }
- if (enc)
- XMEMCPY(e->aead_enc_imp_IV, k->aead_enc_imp_IV,
- sizeof(e->aead_enc_imp_IV));
- if (dec)
- XMEMCPY(e->aead_dec_imp_IV, k->aead_dec_imp_IV,
- sizeof(e->aead_dec_imp_IV));
- }
- /* For storing the sequence number we use a word32[2] array here, instead of
- word64. This is to reuse existing code */
- int Dtls13GetSeq(WOLFSSL* ssl, int order, word32* seq, byte increment)
- {
- w64wrapper* nativeSeq;
- if (order == PEER_ORDER) {
- nativeSeq = &ssl->keys.curSeq;
- /* never increment seq number for current record. In DTLS seq number are
- explicit */
- increment = 0;
- }
- else if (order == CUR_ORDER) {
- if (ssl->dtls13EncryptEpoch == NULL) {
- return BAD_STATE_E;
- }
- nativeSeq = &ssl->dtls13EncryptEpoch->nextSeqNumber;
- }
- else {
- return BAD_FUNC_ARG;
- }
- seq[0] = w64GetHigh32(*nativeSeq);
- seq[1] = w64GetLow32(*nativeSeq);
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG_EX("Dtls13GetSeq(): using seq: %ld", *nativeSeq);
- #endif /* WOLFSSL_DEBUG_TLS */
- if (increment) {
- w64Increment(nativeSeq);
- /* seq number wrapped up */
- if (w64IsZero(*nativeSeq))
- return BAD_STATE_E;
- }
- return 0;
- }
- static Dtls13Epoch* Dtls13NewEpochSlot(WOLFSSL* ssl)
- {
- Dtls13Epoch *e, *oldest = NULL;
- w64wrapper oldestNumber;
- int i;
- /* FIXME: add max function */
- oldestNumber = w64From32((word32)-1, (word32)-1);
- oldest = NULL;
- for (i = 0; i < DTLS13_EPOCH_SIZE; ++i) {
- e = &ssl->dtls13Epochs[i];
- if (!e->isValid)
- return e;
- if (!w64Equal(e->epochNumber, ssl->dtls13Epoch) &&
- !w64Equal(e->epochNumber, ssl->dtls13PeerEpoch) &&
- w64LT(e->epochNumber, oldestNumber))
- oldest = e;
- }
- if (oldest == NULL)
- return NULL;
- e = oldest;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG_EX("Delete epoch: %d", e->epochNumber);
- #endif /* WOLFSSL_DEBUG_TLS */
- XMEMSET(e, 0, sizeof(*e));
- return e;
- }
- int Dtls13NewEpoch(WOLFSSL* ssl, w64wrapper epochNumber, int side)
- {
- Dtls13Epoch* e;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG_EX("New epoch: %d", w64GetLow32(epochNumber));
- #endif /* WOLFSSL_DEBUG_TLS */
- e = Dtls13GetEpoch(ssl, epochNumber);
- if (e == NULL) {
- e = Dtls13NewEpochSlot(ssl);
- if (e == NULL)
- return BAD_STATE_E;
- }
- Dtls13EpochCopyKeys(ssl, e, &ssl->keys, side);
- if (!e->isValid) {
- /* fresh epoch, initialize fields */
- e->epochNumber = epochNumber;
- e->isValid = 1;
- e->side = (byte)side;
- }
- else if (e->side != side) {
- /* epoch used for the other side already. update side */
- e->side = ENCRYPT_AND_DECRYPT_SIDE;
- }
- /* Once handshake is done. Mark epochs older than the last one as encrypt
- * only so that they can't be used for decryption. */
- if (ssl->options.handShakeDone && (e->side == ENCRYPT_AND_DECRYPT_SIDE ||
- e->side == DECRYPT_SIDE_ONLY)) {
- w64Decrement(&epochNumber);
- Dtls13SetOlderEpochSide(ssl, epochNumber, ENCRYPT_SIDE_ONLY);
- }
- return 0;
- }
- int Dtls13SetEpochKeys(WOLFSSL* ssl, w64wrapper epochNumber,
- enum encrypt_side side)
- {
- byte clientWrite, serverWrite;
- Dtls13Epoch* e;
- byte enc, dec;
- WOLFSSL_ENTER("Dtls13SetEpochKeys");
- clientWrite = serverWrite = 0;
- enc = dec = 0;
- switch (side) {
- case ENCRYPT_SIDE_ONLY:
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- clientWrite = 1;
- if (ssl->options.side == WOLFSSL_SERVER_END)
- serverWrite = 1;
- enc = 1;
- break;
- case DECRYPT_SIDE_ONLY:
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- serverWrite = 1;
- if (ssl->options.side == WOLFSSL_SERVER_END)
- clientWrite = 1;
- dec = 1;
- break;
- case ENCRYPT_AND_DECRYPT_SIDE:
- clientWrite = serverWrite = 1;
- enc = dec = 1;
- break;
- }
- e = Dtls13GetEpoch(ssl, epochNumber);
- /* we don't have the requested key */
- if (e == NULL)
- return BAD_STATE_E;
- if (e->side != ENCRYPT_AND_DECRYPT_SIDE && e->side != side)
- return BAD_STATE_E;
- if (enc)
- ssl->dtls13EncryptEpoch = e;
- if (dec)
- ssl->dtls13DecryptEpoch = e;
- /* epoch 0 has no key to copy */
- if (w64IsZero(epochNumber))
- return 0;
- if (clientWrite) {
- XMEMCPY(ssl->keys.client_write_key, e->client_write_key,
- sizeof(ssl->keys.client_write_key));
- XMEMCPY(ssl->keys.client_write_IV, e->client_write_IV,
- sizeof(ssl->keys.client_write_IV));
- XMEMCPY(ssl->keys.client_sn_key, e->client_sn_key,
- sizeof(ssl->keys.client_sn_key));
- }
- if (serverWrite) {
- XMEMCPY(ssl->keys.server_write_key, e->server_write_key,
- sizeof(ssl->keys.server_write_key));
- XMEMCPY(ssl->keys.server_write_IV, e->server_write_IV,
- sizeof(ssl->keys.server_write_IV));
- XMEMCPY(ssl->keys.server_sn_key, e->server_sn_key,
- sizeof(ssl->keys.server_sn_key));
- }
- if (enc)
- XMEMCPY(ssl->keys.aead_enc_imp_IV, e->aead_enc_imp_IV,
- sizeof(ssl->keys.aead_enc_imp_IV));
- if (dec)
- XMEMCPY(ssl->keys.aead_dec_imp_IV, e->aead_dec_imp_IV,
- sizeof(ssl->keys.aead_dec_imp_IV));
- return SetKeysSide(ssl, side);
- }
- int Dtls13SetRecordNumberKeys(WOLFSSL* ssl, enum encrypt_side side)
- {
- RecordNumberCiphers* enc = NULL;
- RecordNumberCiphers* dec = NULL;
- byte *encKey = NULL, *decKey = NULL;
- int ret;
- if (ssl == NULL) {
- return BAD_FUNC_ARG;
- }
- switch (side) {
- case ENCRYPT_SIDE_ONLY:
- enc = &ssl->dtlsRecordNumberEncrypt;
- break;
- case DECRYPT_SIDE_ONLY:
- dec = &ssl->dtlsRecordNumberDecrypt;
- break;
- case ENCRYPT_AND_DECRYPT_SIDE:
- enc = &ssl->dtlsRecordNumberEncrypt;
- dec = &ssl->dtlsRecordNumberDecrypt;
- break;
- }
- if (enc) {
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- encKey = ssl->keys.client_sn_key;
- else
- encKey = ssl->keys.server_sn_key;
- }
- if (dec) {
- if (ssl->options.side == WOLFSSL_CLIENT_END)
- decKey = ssl->keys.server_sn_key;
- else
- decKey = ssl->keys.client_sn_key;
- }
- /* DTLSv1.3 supports only AEAD algorithm. */
- #if defined(BUILD_AESGCM) || defined(HAVE_AESCCM)
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_aes_gcm ||
- ssl->specs.bulk_cipher_algorithm == wolfssl_aes_ccm) {
- if (enc) {
- ret = Dtls13InitAesCipher(ssl, enc, encKey, ssl->specs.key_size);
- if (ret != 0)
- return ret;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Provisioning AES Record Number enc key:");
- WOLFSSL_BUFFER(encKey, ssl->specs.key_size);
- #endif /* WOLFSSL_DEBUG_TLS */
- }
- if (dec) {
- ret = Dtls13InitAesCipher(ssl, dec, decKey, ssl->specs.key_size);
- if (ret != 0)
- return ret;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Provisioning AES Record Number dec key:");
- WOLFSSL_BUFFER(decKey, ssl->specs.key_size);
- #endif /* WOLFSSL_DEBUG_TLS */
- }
- return 0;
- }
- #endif /* BUILD_AESGCM || HAVE_AESCCM */
- #ifdef HAVE_CHACHA
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_chacha) {
- if (enc) {
- ret = Dtls13InitChaChaCipher(enc, encKey, ssl->specs.key_size,
- ssl->heap);
- if (ret != 0)
- return ret;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Provisioning CHACHA Record Number enc key:");
- WOLFSSL_BUFFER(encKey, ssl->specs.key_size);
- #endif /* WOLFSSL_DEBUG_TLS */
- }
- if (dec) {
- ret = Dtls13InitChaChaCipher(dec, decKey, ssl->specs.key_size,
- ssl->heap);
- if (ret != 0)
- return ret;
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Provisioning CHACHA Record Number dec key:");
- WOLFSSL_BUFFER(decKey, ssl->specs.key_size);
- #endif /* WOLFSSL_DEBUG_TLS */
- }
- return 0;
- }
- #endif /* HAVE_CHACHA */
- #ifdef HAVE_NULL_CIPHER
- if (ssl->specs.bulk_cipher_algorithm == wolfssl_cipher_null) {
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("Skipping Record Number key provisioning with null cipher");
- #endif /* WOLFSSL_DEBUG_TLS */
- return 0;
- }
- #endif /* HAVE_NULL_CIPHER */
- return NOT_COMPILED_IN;
- }
- /* 64 bits epoch + 64 bits sequence */
- #define DTLS13_RN_SIZE 16
- static int Dtls13GetAckListLength(Dtls13RecordNumber* list, word16* length)
- {
- int numberElements;
- numberElements = 0;
- /* TODO: check that we don't exceed the maximum length */
- while (list != NULL) {
- list = list->next;
- numberElements++;
- }
- *length = (word16)(DTLS13_RN_SIZE * numberElements);
- return 0;
- }
- static int Dtls13WriteAckMessage(WOLFSSL* ssl,
- Dtls13RecordNumber* recordNumberList, word32* length)
- {
- word16 msgSz, headerLength;
- byte *output, *ackMessage;
- word32 sendSz;
- int ret;
- sendSz = 0;
- if (ssl->dtls13EncryptEpoch == NULL)
- return BAD_STATE_E;
- if (w64IsZero(ssl->dtls13EncryptEpoch->epochNumber)) {
- /* unprotected ACK */
- headerLength = DTLS_RECORD_HEADER_SZ;
- }
- else {
- headerLength = Dtls13GetRlHeaderLength(ssl, 1);
- sendSz += MAX_MSG_EXTRA;
- }
- ret = Dtls13GetAckListLength(recordNumberList, &msgSz);
- if (ret != 0)
- return ret;
- sendSz += headerLength;
- /* ACK list 2 bytes length field */
- sendSz += OPAQUE16_LEN;
- /* ACK list */
- sendSz += msgSz;
- ret = CheckAvailableSize(ssl, sendSz);
- if (ret != 0)
- return ret;
- output = GetOutputBuffer(ssl);
- ackMessage = output + headerLength;
- c16toa(msgSz, ackMessage);
- ackMessage += OPAQUE16_LEN;
- WOLFSSL_MSG("write ack records");
- while (recordNumberList != NULL) {
- WOLFSSL_MSG_EX("epoch %d seq %d", recordNumberList->epoch,
- recordNumberList->seq);
- c64toa(&recordNumberList->epoch, ackMessage);
- ackMessage += OPAQUE64_LEN;
- c64toa(&recordNumberList->seq, ackMessage);
- ackMessage += OPAQUE64_LEN;
- recordNumberList = recordNumberList->next;
- }
- *length = msgSz + OPAQUE16_LEN;
- return 0;
- }
- static int Dtls13RtxIsTrackedByRn(const Dtls13RtxRecord* r, w64wrapper epoch,
- w64wrapper seq)
- {
- int i;
- if (!w64Equal(r->epoch, epoch))
- return 0;
- for (i = 0; i < r->rnIdx; ++i) {
- if (w64Equal(r->seq[i], seq))
- return 1;
- }
- return 0;
- }
- static int Dtls13KeyUpdateAckReceived(WOLFSSL* ssl)
- {
- int ret;
- w64Increment(&ssl->dtls13Epoch);
- /* Epoch wrapped up */
- if (w64IsZero(ssl->dtls13Epoch))
- return BAD_STATE_E;
- ret = DeriveTls13Keys(ssl, update_traffic_key, ENCRYPT_SIDE_ONLY, 1);
- if (ret != 0)
- return ret;
- ret = Dtls13NewEpoch(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
- if (ret != 0)
- return ret;
- return Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
- }
- #ifdef WOLFSSL_DEBUG_TLS
- static void Dtls13PrintRtxRecord(Dtls13RtxRecord* r)
- {
- int i;
- WOLFSSL_MSG_EX("r: hs: %d epoch: %ld", r->handshakeType, r->epoch);
- for (i = 0; i < r->rnIdx; i++)
- WOLFSSL_MSG_EX("seq: %ld", r->seq[i]);
- }
- #endif /* WOLFSSL_DEBUG_TLS */
- static void Dtls13RtxRemoveRecord(WOLFSSL* ssl, w64wrapper epoch,
- w64wrapper seq)
- {
- Dtls13RtxRecord *r, **prevNext;
- prevNext = &ssl->dtls13Rtx.rtxRecords;
- r = ssl->dtls13Rtx.rtxRecords;
- while (r != NULL) {
- #ifdef WOLFSSL_DEBUG_TLS
- Dtls13PrintRtxRecord(r);
- #endif /* WOLFSSL_DEBUG_TLS */
- if (Dtls13RtxIsTrackedByRn(r, epoch, seq)) {
- #ifdef WOLFSSL_DEBUG_TLS
- WOLFSSL_MSG("removing record");
- #endif /* WOLFSSL_DEBUG_TLS */
- Dtls13RtxRecordUnlink(ssl, prevNext, r);
- Dtls13FreeRtxBufferRecord(ssl, r);
- return;
- }
- prevNext = &r->next;
- r = r->next;
- }
- return;
- }
- int Dtls13DoScheduledWork(WOLFSSL* ssl)
- {
- int ret;
- WOLFSSL_ENTER("Dtls13DoScheduledWork");
- ssl->dtls13SendingAckOrRtx = 1;
- if (ssl->dtls13Rtx.sendAcks) {
- ssl->dtls13Rtx.sendAcks = 0;
- ret = SendDtls13Ack(ssl);
- if (ret != 0)
- return ret;
- }
- if (ssl->dtls13Rtx.retransmit) {
- ssl->dtls13Rtx.retransmit = 0;
- ret = Dtls13RtxSendBuffered(ssl);
- if (ret != 0)
- return ret;
- }
- ssl->dtls13SendingAckOrRtx = 0;
- if (ssl->dtls13DoKeyUpdate) {
- ssl->dtls13DoKeyUpdate = 0;
- ret = Tls13UpdateKeys(ssl);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
- /* Send ACKs when available after a timeout but only retransmit the last
- * flight after a long timeout */
- int Dtls13RtxTimeout(WOLFSSL* ssl)
- {
- int ret = 0;
- /* We don't want to send acks until we have done version
- * negotiation in the SH or have received a unified header in the
- * DTLS record. */
- if (ssl->dtls13Rtx.seenRecords != NULL &&
- (ssl->options.serverState >= SERVER_HELLO_COMPLETE ||
- ssl->options.seenUnifiedHdr)) {
- ssl->dtls13Rtx.sendAcks = 0;
- /* reset fast timeout as we are sending ACKs */
- ssl->dtls13FastTimeout = 0;
- ret = SendDtls13Ack(ssl);
- if (ret != 0)
- return ret;
- }
- /* we have two timeouts, a shorter (dtls13FastTimeout = 1) and a longer
- one. When the shorter expires we only send ACKs, as it normally means
- that some messages we are waiting for don't arrive yet. But we
- retransmit our buffered messages only if the longer timeout
- expires. fastTimeout is 1/4 of the longer timeout */
- if (ssl->dtls13FastTimeout) {
- ssl->dtls13FastTimeout = 0;
- return 0;
- }
- /* Increase timeout on long timeout */
- if (DtlsMsgPoolTimeout(ssl) != 0)
- return -1;
- return Dtls13RtxSendBuffered(ssl);
- }
- static int Dtls13RtxHasKeyUpdateBuffered(WOLFSSL* ssl)
- {
- Dtls13RtxRecord* r = ssl->dtls13Rtx.rtxRecords;
- while (r != NULL) {
- if (r->handshakeType == key_update)
- return 1;
- r = r->next;
- }
- return 0;
- }
- int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
- word32* processedSize)
- {
- const byte* ackMessage;
- w64wrapper epoch, seq;
- word16 length;
- int ret;
- int i;
- if (inputSize < OPAQUE16_LEN)
- return BUFFER_ERROR;
- ato16(input, &length);
- if (inputSize < (word32)(OPAQUE16_LEN + length))
- return BUFFER_ERROR;
- if (length % (DTLS13_RN_SIZE) != 0)
- return PARSE_ERROR;
- WOLFSSL_MSG("read ack records");
- ackMessage = input + OPAQUE16_LEN;
- for (i = 0; i < length; i += DTLS13_RN_SIZE) {
- ato64(ackMessage + i, &epoch);
- ato64(ackMessage + i + OPAQUE64_LEN, &seq);
- WOLFSSL_MSG_EX("epoch %d seq %d", epoch, seq);
- Dtls13RtxRemoveRecord(ssl, epoch, seq);
- }
- /* last client flight was completely acknowledged by the server. Handshake
- is complete. */
- if (ssl->options.side == WOLFSSL_CLIENT_END &&
- ssl->options.connectState == WAIT_FINISHED_ACK &&
- ssl->dtls13Rtx.rtxRecords == NULL) {
- ssl->options.serverState = SERVER_FINISHED_ACKED;
- }
- if (ssl->dtls13WaitKeyUpdateAck) {
- if (!Dtls13RtxHasKeyUpdateBuffered(ssl)) {
- /* we removed the KeyUpdate message because it was ACKed */
- ssl->dtls13WaitKeyUpdateAck = 0;
- ret = Dtls13KeyUpdateAckReceived(ssl);
- if (ret != 0)
- return ret;
- }
- }
- *processedSize = length + OPAQUE16_LEN;
- /* After the handshake, not retransmitting here may incur in some extra time
- in case a post-handshake authentication message is lost, because the ACK
- mechanism does not shortcut the retransmission timer. If, on the other
- hand, we retransmit we may do extra retransmissions of unrelated messages
- in the queue. ex: we send KeyUpdate, CertificateRequest that are
- unrelated between each other, receiving the ACK for the KeyUpdate will
- trigger re-sending the CertificateRequest before the timeout.*/
- /* TODO: be more smart about when doing retransmission looking in the
- retransmission queue or based on the type of message removed from the
- seen record list */
- if (ssl->dtls13Rtx.rtxRecords != NULL)
- ssl->dtls13Rtx.retransmit = 1;
- return 0;
- }
- int SendDtls13Ack(WOLFSSL* ssl)
- {
- word32 outputSize;
- int headerSize;
- word32 length;
- byte* output;
- int ret;
- if (ssl->dtls13EncryptEpoch == NULL)
- return BAD_STATE_E;
- WOLFSSL_ENTER("SendDtls13Ack");
- ret = 0;
- /* The handshake is not complete and the client didn't setup the TRAFFIC0
- epoch yet */
- if (ssl->options.side == WOLFSSL_SERVER_END &&
- !ssl->options.handShakeDone &&
- w64GTE(ssl->dtls13Epoch, w64From32(0, DTLS13_EPOCH_TRAFFIC0))) {
- ret = Dtls13SetEpochKeys(ssl, w64From32(0, DTLS13_EPOCH_HANDSHAKE),
- ENCRYPT_SIDE_ONLY);
- }
- else if (!w64Equal(ssl->dtls13Epoch,
- ssl->dtls13EncryptEpoch->epochNumber)) {
- ret = Dtls13SetEpochKeys(ssl, ssl->dtls13Epoch, ENCRYPT_SIDE_ONLY);
- }
- if (ret != 0)
- return ret;
- ret = Dtls13WriteAckMessage(ssl, ssl->dtls13Rtx.seenRecords, &length);
- if (ret != 0)
- return ret;
- output = GetOutputBuffer(ssl);
- if (w64IsZero(ssl->dtls13EncryptEpoch->epochNumber)) {
- ret = Dtls13RlAddPlaintextHeader(ssl, output, ack, (word16)length);
- if (ret != 0)
- return ret;
- ssl->buffers.outputBuffer.length += length + DTLS_RECORD_HEADER_SZ;
- }
- else {
- outputSize = ssl->buffers.outputBuffer.bufferSize -
- ssl->buffers.outputBuffer.idx -
- ssl->buffers.outputBuffer.length;
- headerSize = Dtls13GetRlHeaderLength(ssl, 1);
- ret = BuildTls13Message(ssl, output, outputSize, output + headerSize,
- length, ack, 0, 0, 0);
- if (ret < 0)
- return ret;
- ssl->buffers.outputBuffer.length += ret;
- }
- Dtls13RtxFlushAcks(ssl);
- return SendBuffered(ssl);
- }
- static int Dtls13RtxRecordMatchesReqCtx(Dtls13RtxRecord* r, byte* ctx,
- byte ctxLen)
- {
- if (r->handshakeType != certificate_request)
- return 0;
- if (r->length <= ctxLen + 1)
- return 0;
- return XMEMCMP(ctx, r->data + 1, ctxLen) == 0;
- }
- int Dtls13RtxProcessingCertificate(WOLFSSL* ssl, byte* input, word32 inputSize)
- {
- Dtls13RtxRecord* rtxRecord = ssl->dtls13Rtx.rtxRecords;
- Dtls13RtxRecord** prevNext = &ssl->dtls13Rtx.rtxRecords;
- byte ctxLength;
- WOLFSSL_ENTER("Dtls13RtxProcessingCertificate");
- if (inputSize <= 1) {
- WOLFSSL_MSG("Malformed Certificate");
- return BAD_FUNC_ARG;
- }
- ctxLength = *input;
- if (inputSize < (word32)ctxLength + OPAQUE8_LEN) {
- WOLFSSL_MSG("Malformed Certificate");
- return BAD_FUNC_ARG;
- }
- while (rtxRecord != NULL) {
- if (Dtls13RtxRecordMatchesReqCtx(rtxRecord, input + 1, ctxLength)) {
- Dtls13RtxRecordUnlink(ssl, prevNext, rtxRecord);
- Dtls13FreeRtxBufferRecord(ssl, rtxRecord);
- return 0;
- }
- prevNext = &rtxRecord->next;
- rtxRecord = rtxRecord->next;
- }
- /* This isn't an error since we just can't find a Dtls13RtxRecord that
- * matches the Request Context. Request Context validity is checked
- * later. */
- WOLFSSL_MSG("Can't find any previous Certificate Request");
- return 0;
- }
- int wolfSSL_dtls13_has_pending_msg(WOLFSSL* ssl)
- {
- return ssl->dtls13Rtx.rtxRecords != NULL;
- }
- #ifndef WOLFSSL_TLS13_IGNORE_AEAD_LIMITS
- /* Limits specified by
- * https://www.rfc-editor.org/rfc/rfc9147.html#name-aead-limits
- * We specify the limit by which we need to do a key update as the halfway point
- * to the hard decryption fail limit. */
- int Dtls13CheckAEADFailLimit(WOLFSSL* ssl)
- {
- w64wrapper keyUpdateLimit;
- w64wrapper hardLimit;
- switch (ssl->specs.bulk_cipher_algorithm) {
- #if defined(BUILD_AESGCM) || (defined(HAVE_CHACHA) && defined(HAVE_POLY1305))
- case wolfssl_aes_gcm:
- case wolfssl_chacha:
- hardLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_LIMIT;
- keyUpdateLimit = DTLS_AEAD_AES_GCM_CHACHA_FAIL_KU_LIMIT;
- break;
- #endif
- #ifdef HAVE_AESCCM
- case wolfssl_aes_ccm:
- if (ssl->specs.aead_mac_size == AES_CCM_8_AUTH_SZ) {
- /* Limit is 2^7. The RFC recommends that
- * "TLS_AES_128_CCM_8_SHA256 is not suitable for general use".
- * We still should enforce the limit. */
- hardLimit = DTLS_AEAD_AES_CCM_8_FAIL_LIMIT;
- keyUpdateLimit = DTLS_AEAD_AES_CCM_8_FAIL_KU_LIMIT;
- }
- else {
- /* Limit is 2^23.5.
- * Without the fraction is 11863283 (0x00B504F3)
- * Half of this value is 5931641 (0x005A8279) */
- hardLimit = DTLS_AEAD_AES_CCM_FAIL_LIMIT;
- keyUpdateLimit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT;
- }
- break;
- #endif
- case wolfssl_cipher_null:
- /* No encryption being done. The MAC check must have failed. */
- return 0;
- default:
- WOLFSSL_MSG("Unrecognized ciphersuite for AEAD limit check");
- WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
- return DECRYPT_ERROR;
- }
- if (ssl->dtls13DecryptEpoch == NULL) {
- WOLFSSL_MSG("Dtls13CheckAEADFailLimit: ssl->dtls13DecryptEpoch should "
- "not be NULL");
- WOLFSSL_ERROR_VERBOSE(BAD_STATE_E);
- return BAD_STATE_E;
- }
- w64Increment(&ssl->dtls13DecryptEpoch->dropCount);
- if (w64GT(ssl->dtls13DecryptEpoch->dropCount, hardLimit)) {
- /* We have reached the hard limit for failed decryptions. */
- WOLFSSL_MSG("Connection exceeded hard AEAD limit");
- WOLFSSL_ERROR_VERBOSE(DECRYPT_ERROR);
- return DECRYPT_ERROR;
- }
- else if (w64GT(ssl->dtls13DecryptEpoch->dropCount, keyUpdateLimit)) {
- WOLFSSL_MSG("Connection exceeded key update limit. Issuing key update");
- /* If not waiting for a response then request a key update. */
- if (!ssl->keys.updateResponseReq) {
- ssl->dtls13DoKeyUpdate = 1;
- ssl->dtls13InvalidateBefore = ssl->dtls13PeerEpoch;
- w64Increment(&ssl->dtls13InvalidateBefore);
- }
- }
- return 0;
- }
- #endif
- #ifdef WOLFSSL_DTLS_CH_FRAG
- int wolfSSL_dtls13_allow_ch_frag(WOLFSSL *ssl, int enabled)
- {
- if (ssl->options.side == WOLFSSL_CLIENT_END) {
- return WOLFSSL_FAILURE;
- }
- ssl->options.dtls13ChFrag = !!enabled;
- return WOLFSSL_SUCCESS;
- }
- #endif
- #ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
- int wolfSSL_dtls13_no_hrr_on_resume(WOLFSSL *ssl, int enabled)
- {
- if (ssl->options.side == WOLFSSL_CLIENT_END) {
- return WOLFSSL_FAILURE;
- }
- ssl->options.dtls13NoHrrOnResume = !!enabled;
- return WOLFSSL_SUCCESS;
- }
- #endif
- #endif /* WOLFSSL_DTLS13 */
|